What is captured
Hook by hook, what fires, what leaves the machine, and what never does.
Capture is deterministic. The runtime fires a hook, the hook runs the CLI once, the CLI emits at most one small observation and exits 0. No agent is prompted to do bookkeeping and no tokens are spent on it. State observations (registered, stop, compact, notification, answered) are spooled locally when the service is unreachable and replayed later. Heartbeats are best effort and never replayed, since stale liveness would be a lie. Most tool-call hooks return before the CLI even starts. A session is never blocked and never broken by the service being down.
The rule for what travels
Every field on the wire belongs to one of three classes, and the schema says which.
| Class | What it is | Where it may appear |
|---|---|---|
| Structural | Enums, numbers, hashes, ids, timestamps, branch names, the worktree’s absolute path | Everywhere. This is almost all of what hooks send. |
| Authored | Prose a person or an agent composed on purpose: the --note on a claim or log, a message sent with fibers msg, and one label, the session title |
The coordination verbs you type, plus the title field on registered and stop. Checked by a local secret scan before it leaves. |
| Local | Raw text, paths, tool input and output from the runtime | Read in-process by the CLI and never serialised to the wire. |
So a hook payload carries two things that are not enums or hashes. The absolute path of the worktree, because machine plus path is the session’s identity. And the session title where the runtime has one: it is read from the local session index, scanned for secrets on your machine, and dropped if the scan finds any. Everything else, the runtime’s notification message, your transcript path, the tool input and output, is classified or fingerprinted locally and only the resulting enum or hash travels. Which modules are on is a fact about your machine and is never sent.
Hook by hook
| Runtime event | What the CLI emits | What stays local |
|---|---|---|
SessionStart |
registered: opens the session and refreshes the worktree row. Travels: machine, worktree path, session id, the source enum, and the session title if one exists. The response may carry waiting messages, which the CLI prints into the session. |
Everything else on stdin. |
SubagentStart |
registered with the parent session id, so sub-agent work is attributed rather than lost. The child’s title is its agent type as the runtime names it. |
Everything else on stdin. |
Stop, SubagentStop |
stop, refreshing the session title each turn. “Waiting for you” is inferred from a stop plus silence plus age, and rendered as an inference. A crashed terminal never sends it, which is why nothing asserts liveness. |
The turn’s content. |
SessionEnd |
stop with an end-reason enum. Its presence is what ends the session row on the service. |
As above. |
PreCompact |
compact with a trigger enum, manual or auto. A mid-session moment, not an end. |
The context being compacted. |
Notification |
notification with a reason classified in-process to permission_request, idle or unknown. |
The notification text itself. |
PreToolUse |
notification with reason question, only when the tool is the ask-the-user tool. Every other tool is nothing. A cheap shell sieve in the launcher returns before the CLI even starts for most calls. |
The tool input. |
PostToolUse |
A heartbeat, throttled to one per five minutes per session, so an hours-long turn reads as active. When the tool was the ask-the-user tool, answered instead, never throttled, which clears the needs-you state. When a shell tool reported an error inside an otherwise successful result that the fingerprinter recognises, a friction record to the local store. |
Tool output, the error text, the fingerprinted excerpt. |
PostToolUseFailure |
Nothing on the wire. The failure is fingerprinted and a friction record goes to the local store. | The whole payload. |
StopFailure |
Nothing on the wire. Fingerprinted into the local friction store like a tool failure. | The whole payload. |
UserPromptSubmit |
Nothing on the wire. Off unless this machine opts in with fibers features on asides; then a message you typed while the agent was working is appended to a local spool, with the agent’s last prose beside it, and a turn-start prompt is nothing. The launcher starts the CLI only for an opted-in machine and a prompt that is not a system envelope or a slash command. |
The whole payload, the prompt included. |
What the coordination verbs send
claim, log, release, bump, msg and the work and decisions verbs are typed by a person or an agent on purpose. They carry the ref, the kind and, where you give one, the note. The note is authored text and passes the local secret scan first. A note with no value, or with another flag where its value should be, is refused rather than recorded empty.
Friction
Repeated failures are counted on your machine. fibers friction ls reads the local store and sends nothing. The only friction facts that leave are a hash of the signature and, when you record one, the ref of the PR or work item that fixes it.
Where the schemas are
The wire schemas are JSON Schema files in the repository under docs/spec/, one per payload kind, with the content class annotated on every non-structural field. Golden tests assert that each fixture payload matches its schema, so the allowlist in the schema is the thing that decides, not the prose on this page.