Hook contract
Mossbear’s agent lifecycle is four commands. This page is the contract behind them — what each is for, when it fires, and what running it is allowed to change. Flags and syntax are in CLI reference; which harness writes which config file is in Local agents. Neither lives here twice.
Every one of the four is a hook a harness runs unattended, and also a command a person can type by hand. What each does does not change between the two callers.
The four commands
Section titled “The four commands”| Command | Fires | May do | Must never do |
|---|---|---|---|
mossbear-hook [--harness <id>] | After every tool call | Append one action record to this machine’s local run log | Reach the network, or block or fail the tool call it is logging |
mossbear report | After each assistant turn | Upload the session’s queued action metadata, and pull and reconcile this repo’s subscribed Mossbear-managed artifacts | Push a local artifact edit back, close the session, or write to a path whose source of truth is git |
mossbear complete | When the agent session ends | Upload what is left, close the session for grading, pull and reconcile subscribed artifacts, and push this checkout’s locally-edited Mossbear-managed artifacts back | Push while another session in this checkout is still active, or write to a path whose source of truth is git |
mossbear refresh | Before the first turn | Pull and reconcile this repo’s subscribed Mossbear-managed artifacts | Upload actions, push a local edit back, or write to a path whose source of truth is git |
All three of report, complete and refresh pull and reconcile subscribed artifacts today —
refresh is not the only one that delivers, it is the one installed to do it before the first
turn rather than after one. Only complete ever pushes a local edit back.
None of the four ever writes delivered content into a path whose source of truth is git: the planner that resolves where a write may land refuses one by name rather than silently narrowing what it delivers.
What silence means
Section titled “What silence means”Success is silent. None of the four prints anything when a run did exactly what its row above
says and nothing else happened — there is no --quiet flag, because quiet is now the default.
--verbose opts back into the progress lines a successful run otherwise keeps to itself: what
was extracted, uploaded, and pulled.
What still prints, --verbose or not: a file written, refused, or left in conflict; a warning;
an error; and, at session start only, one line saying how many notes people have left about
this repo’s context and which command reads them. That last line is capped per reader per repo,
so its absence means “nothing new to interrupt you about” rather than “no notes”; mossbear notes is never capped and is what answers the question. Reading a hook’s stdout,
empty means “ran fine, nothing to relay” — anything else is the run’s own account of something
that was not routine, and is worth relaying to whoever is at the keyboard.
Some generated hook entries also wrap their command in || true (or that harness’s
equivalent) — a second, unrelated reason one can produce no visible failure. That swallows a
network error so it never blocks the agent’s turn; the action stays queued and goes out on the
next run that reaches the dashboard. Not every entry is wrapped this way: on Claude Code, only
the session-start entry is, so a failed report or complete there does surface as a hook
error rather than swallow one. Shell-level silence and --verbose’s absence are not the same
guarantee, and neither is universal across harnesses — only --verbose’s absence on a run that
actually completed means the run landed.
Why one command per action
Section titled “Why one command per action”A single mossbear sync, told apart only by flags, used to be all four rows above. A settings
file could not show which flag a given entry meant, so the safe reading had to be the default
everywhere and every interesting behaviour had to be asked for. Reading a hook entry now means
reading the verb.