Skip to main content

Module hook

Module hook 

Source
Expand description

ai-crew-sync context hook --binding <id> --event <event>.

The one thing lifecycle hooks run in authenticated mode. A hook is a short-lived process with no credential of its own; this helper reads the private binding record its conversation’s proxy wrote (0700 directory, 0600 file), performs the operation with that window’s session credential, and prints only what the host expects. The credential never reaches argv, stdout, a log or a tool result (ADR 0001).

Three rules the implementation exists to keep:

  1. Same window, never a sibling. The binding is looked up by the host’s conversation id. A missing or unusable binding is a quiet no-op, never a fallback to a shared session or another team — a hook that drained the wrong window’s inbox would be a silent data loss.
  2. A hook never fences its own proxy. It sends the epoch the proxy recorded and never registers, so it cannot bump the epoch and lock out the window it belongs to.
  3. Presence only, no reads that move a cursor. The events here publish presence and read context; the Stop drain still runs in the shell script, which is where its loop guard lives. Its reads go through --event call, one tool call as the bound window, so an exported BUS_TOKEN/BUS_SESSION can never redirect them to a sibling window’s inbox.

Enums§

Event
Lifecycle events this helper knows. Anything else is a caller mistake worth naming rather than a silent success.
HookHost
Which host’s hook contract to answer in (#229). The events are the same; what a host reads back from a hook differs.
Resolution
How the binding was resolved, so status can explain a silent hook.

Constants§

HOOK_CALL_TOOLS
The tools --event call serves: exactly what the hook scripts call through bus-call.sh. Anything else is refused before the binding is even read, so resume_session through a hook cannot rotate the proxy’s credential and print the new secret.
WATCH_WAKE_LABEL
The label a watcher announces as this window’s wake mechanism (#221). The plugin runs the watcher only in Claude Code, as an asyncRewake hook.

Functions§

resolve_binding
run
Run one hook event. Returns what to print on stdout: the host’s JSON for session_start, the tool’s structured content for call, nothing for the presence events. call names the tool and its arguments for Event::Call and is ignored by every other event.
run_as
run, answering in host’s hook contract.
watch
--event watch: block until something new is addressed to this window, then return the text to wake it with. None when the deadline passes, the binding is closed or missing, or a newer watcher took over. Starting takes the window over from any earlier watcher, keeping what that one had already woken the window for; a window watched for the first time starts from what is waiting now, which its session start already said. Every read-check-write of the state file holds the configuration lock, so a replaced watcher can never overwrite its successor’s claim.