Expand description
The hook: every harness’s events, one canonical, Claude-shaped event each (session_id, cwd, prompt,
tool_name, tool_input, error, last_assistant_message, transcript_path, stop_hook_active), answered
Claude-shaped ({“decision”:“block”,“reason”} at stop, hookSpecificOutput with context at a prompt
or tool call); adapters translate both ways (harness/). What differs per harness comes from its
Harness: capabilities, the turn’s work and the drone’s last message, never its name.
main routes and records presence; dispatch has one function per event. Hooks always fail open:
any error lets the drone continue untouched.
Functions§
- dispatch
- One hook event, canonical already (harness
normalise), for the dronehruns: what borg answers (Claude-shaped), or None. One function per event. - judge_
session - The session-end judge (0.7.6), run by
borg learn --sessionbefore it learns (main.rslearn_cmd): every delivery ofsession(any channel) whose latest delivery no verdict settled yet (none came, or only unclear, consequence_remains or missing ones, its tries spent or not) is judged, beside as much of the session’s work as the prompt’s budget leaves (end_budget,session_sources,within). The lessons go in batches by delivery order, each prompt within the budget (batches), each batch its own model call,runner::JOBSat a time, each withinend_timeout, under the session lock, renewed before each call (live.rsGuard::renew). Each batch records as soon as its call returns, while the others still run, so a pass stopped partway keeps what it was already told (and paid for). An answered batch records as a check’s judge does (record_verdicts,atoutcome.rsAT_END, its cost line namingbatch=<i>/<n>,budget=andcut=) and writes the state lines#borg-judged, then its ownEND_JUDGED: what it judged settles there, andborg learnthen settles the rest asasked_not_correctedwith its reason (unjudged). Each call is counted as amodel_callwith whyjudge. A failed batch is no try, for its own lessons alone (#borg-unjudged … why=failed), and its cost linejudge-failedkeeps its lessons as sent and unanswered for the judge’s effective length (judge_length.rs); afterrunner::MAX_FAILURESfailed calls before the first answer the judge is unavailable, and the batches not yet asked fail alike, without a call. A pass whose lock was taken over asks nothing more; what it did not ask stays open for the lock’s new holder, andborg learnsettles no session whose lock another holds (learn.rs). A lock held by another (a stop, or an earlier pass of a resumed session) is waited for, as long as it is renewed: it reads stalelive::stale_msafter its holder stops. Nothing runs, and nothing is written, without learning (BORG_LEARN=off), without a runner for the consequence model (BORG_PREDICT_MODEL=off, none installed), or with nothing open. Returns how many lessons it judged. - main
borg hook <harness> <event>, the event on stdin: routes the repo to its collective (an off repo leaves no trace), records presence, then answers through steering, the experts anddispatch, with the messages from other sessions (msg.rs). An unknown harness, like any failure here, lets the drone continue untouched.- stripped
- Whether the judge sees question
lessonofcheckwithout the drone’s<id>: applies|skip: a fair coin from blake3 over both, so a retry strips alike and a replay knows it (outcome.rsstripped; a test predicts a judge prompt by it). Method: a random half, to measure what the declaration adds to a verdict.