iiRecord
Agentic AI Atlas · 15 — Unified Hooks System
page:docs-agent-mux-reference-15-hooksa5c.ai
II.
Page JSON

page:docs-agent-mux-reference-15-hooks

Structured · live

15 — Unified Hooks System json

Inspect the normalized record payload exactly as the atlas UI reads it.

File · wiki/docs/agent-mux/reference/15-hooks.mdCluster · wiki
Record JSON
{
  "id": "page:docs-agent-mux-reference-15-hooks",
  "_kind": "Page",
  "_file": "wiki/docs/agent-mux/reference/15-hooks.md",
  "_cluster": "wiki",
  "attributes": {
    "nodeKind": "Page",
    "sourcePath": "docs/agent-mux/reference/15-hooks.md",
    "sourceKind": "repo-docs",
    "title": "15 — Unified Hooks System",
    "displayName": "15 — Unified Hooks System",
    "slug": "docs/agent-mux/reference/15-hooks",
    "articlePath": "wiki/docs/agent-mux/reference/15-hooks.md",
    "article": "\n# 15 — Unified Hooks System\n\n`agent-mux` provides a harness-agnostic hook system that lets one\nconfiguration drive hook dispatch across all 11 supported harnesses.\n\n## Concepts\n\n- **Hook type** — a harness-specific event name (e.g. `PreToolUse`,\n  `StopHook`, `OnToolCall`). See `HOOK_CATALOG` in\n  `@a5c-ai/agent-mux-core` for the per-harness list.\n- **Registration** — a record in `.amux/hooks.json` (project) or\n  `~/.amux/hooks.json` (global) that maps\n  `(agent, hookType) → handler(target)`. Project overrides global by `id`.\n- **Handler** — `builtin` (programmatic, in-process),\n  `command` (shell command), or `script` (executable path).\n- **Unified payload** — normalized `UnifiedHookPayload` with\n  `{ agent, hookType, sessionId, timestamp, data, raw }`. `data` contains\n  fields like `tool_name`, `tool_input`, `prompt`, etc.; `raw` preserves the\n  original harness payload for bidirectional round-tripping.\n- **Unified result** — `{ decision: allow|deny|modify, message?,\n  modifiedInput?, stdout?, exitCode? }`. `deny` maps to exit code 2 (the\n  convention used by most harnesses).\n\n## SDK usage\n\n```ts\nimport {\n  HookConfigManager, HookDispatcher, builtInHooks,\n  parseHookPayload, formatHookResult,\n} from '@a5c-ai/agent-mux-core';\n\nconst mgr = new HookConfigManager();\nawait mgr.add({\n  id: 'log-all',\n  agent: '*',\n  hookType: '*',\n  handler: 'builtin',\n  target: 'log',\n  priority: 10,\n});\n\nconst dispatcher = new HookDispatcher(mgr, builtInHooks);\nconst payload = parseHookPayload('claude', 'PreToolUse', { tool_name: 'Bash' });\nconst result = await dispatcher.dispatch(payload);\nconst { stdout, exitCode } = formatHookResult('claude', 'PreToolUse', result);\n```\n\n## CLI usage\n\n```\namux hooks <agent> discover\namux hooks <agent> list\namux hooks <agent> add <hookType> [--handler builtin|command|script]\n                                  [--target <id-or-cmd>]\n                                  [--id <id>] [--priority N] [--global]\namux hooks <agent> remove <id> [--global|--project]\namux hooks <agent> set <id> [--priority N] [--enabled true|false] [--target ...]\namux hooks <agent> handle <hookType>   # reads JSON payload on stdin\n```\n\n`handle` is the entry point registered with harnesses (e.g. claude's\n`settings.json` `\"hooks\"` section) — the harness pipes its payload to\nstdin and `amux` dispatches all matching registrations.\n\n## Built-in programmatic hooks\n\n| ID                       | Description                                             |\n|--------------------------|---------------------------------------------------------|\n| `log`                    | Append payload to `~/.amux/hook-log.jsonl`              |\n| `trace`                  | Emit a one-line trace to stdout                         |\n| `claude.session-capture` | Capture claude session metadata (CLAUDE_PROJECT_DIR…)   |\n\nAdd your own with `builtInHooks.register({ id, description, fn })`.\n\n## Dispatch semantics\n\n1. Registrations matching `(agent, hookType)` are collected (supports `*`).\n2. Disabled entries (`enabled: false`) are excluded.\n3. Remaining entries are sorted by `priority` ascending (default 100).\n4. Each runs in order; results are merged:\n   - `deny` is sticky — further entries short-circuit.\n   - `modify` wins over `allow` for the final decision.\n   - `modifiedInput` objects are shallow-merged.\n   - `stdout` fragments are concatenated.\n   - First non-zero `exitCode` wins.\n",
    "documents": []
  },
  "outgoingEdges": [],
  "incomingEdges": [
    {
      "from": "page:docs-agent-mux-reference",
      "to": "page:docs-agent-mux-reference-15-hooks",
      "kind": "contains_page"
    }
  ]
}