/collab-monitor
Arm or stop durable tag-scoped collab-file watches. Triggers: collab monitor, watch collab, listen-name, background watch. NOT for file-integrity auditing or worker-registry completion.
$ golems-cli skills install collab-monitorUpdated 5 days ago
Use the packaged monitor whenever a collab lane needs forward-only delivery to a declared listen name. Do not hand-roll a grep/tail loop: the recorded fleet failures are pinned in this skill's evals.
Start and Stop
COLLAB_MONITOR=~/Gits/golems/skills/golem-powers/collab-monitor/scripts/collab-monitor.sh
: "${ORCHESTRATOR_REPO:?ORCHESTRATOR_REPO must be set}"
# Durable background monitor over N explicit files
bash "$COLLAB_MONITOR" start @your-listen-name \
"$ORCHESTRATOR_REPO/collab/FLEET-STANDING.md" \
"$ORCHESTRATOR_REPO/collab/ARM-MONITORS.md"
# Keep this foreground stream attached to the orchestrator's monitored command session
bash "$COLLAB_MONITOR" follow @your-listen-name
# Verify or stop it without remembering a PID
bash "$COLLAB_MONITOR" status @your-listen-name
bash "$COLLAB_MONITOR" stop @your-listen-nameUse foreground mode when a parent monitor/supervisor owns the process:
bash "$COLLAB_MONITOR" run @your-listen-name collab.md another-collab.mdstart is the durable producer; it does not wake an orchestrator by itself. Attach follow in a monitored long-running command session before relying on alerts. Each successful start begins a fresh session log, and follow replays that session from its start before streaming new records until stop ends the monitor.
run --once performs one deterministic seed/poll and exits. It is appropriate for evals or an external scheduler; repeated calls use the same durable state. It exits non-zero when initial input, lock/state access, or event extraction fails, so a scheduler must treat non-zero as an incomplete poll.
Participation Law — a collab is a mailbox with no doorbell
Ratified by Etan 2026-08-14 after two leads and a worker each missed messages addressed to them in a shared collab. Writing to a collab makes a message durable, not delivered. Nobody is notified. A participant without a watcher on that file will not see it, no matter how urgent.
These rules bind every participant for the life of the collab.
- Arm before you work. The moment you post to a collab, are addressed in one, or are named a participant — arm a watcher on that file BEFORE doing anything else. Not after your task, not when convenient. An unwatched collab you are named in is an unread inbox.
- Waiting means detached, not looping. When you finish a unit and are waiting to be re-requested: detach a watcher and RETURN. Never hold a foreground turn open to poll, and never inspect another agent's pane to infer state — that is monitoring you were not asked to do, and it burns a turn that should have ended.
- Codex agents have no Monitor tool — use a background bash tail. This is not optional and
not a lesser substitute:
Read what it captured when you are re-invoked. A Codex that keeps working, or keeps polling in the foreground, because "it has no monitor" is choosing the wrong half of the contract.
tail -n0 -F <collab-path> & # detached, then RETURN - Dedup by line hash. A collab that gets rewritten (formatting, section moves) must not re-emit its whole history as new events. Hash lines; emit only unseen ones.
- Stop when you post your DONE — not before, not after. The watcher's life is exactly the lane's life. A watcher outliving its lane is noise; a lane outliving its watcher is a silent handoff.
- Pings are pointers, never restatements. In-pane: one line saying WHERE to look and the one
fact that makes it urgent —
Read <file> §<section> — your worker is blocked. The collab holds the detail because the collab survives restarts and the pane does not. A long message duplicating a collab post is backwards, and long payloads break the receiving pane. - Leads own reviewer monitoring; workers push, notify, stop. A worker that keeps watching its own reviewer has taken the lead's job and stayed alive to do it.
Failure mode to recognize: if a handoff "went unanswered", check whether the recipient had a watcher on that file before concluding anything about the recipient. Silence from an unwatched collab is not refusal, disagreement, or absence — it is a message that was never delivered.
Supervision: Watch, Then Read Once
A supervisor MUST NOT poll read_screen in a loop for one worker outcome. Repeated screen reads are a defect, not diligence: arm a process-exit or background-log watch, let it wake the supervisor, and read the finished screen/log once.
For headless Codex workers, use the codex-workflows skill's watch primitive. It observes process exit first and parses the completed log once. For this monitor, keep follow attached to the supervisor's monitored long-running command session; do not replace it with repeated screen inspection.
Full SKILL.md source — includes LLM directives, anti-patterns, and technical instructions stripped from the Overview tab.
Use the packaged monitor whenever a collab lane needs forward-only delivery to a declared listen name. Do not hand-roll a grep/tail loop: the recorded fleet failures are pinned in this skill's evals.
Start and Stop
COLLAB_MONITOR=~/Gits/golems/skills/golem-powers/collab-monitor/scripts/collab-monitor.sh
: "${ORCHESTRATOR_REPO:?ORCHESTRATOR_REPO must be set}"
# Durable background monitor over N explicit files
bash "$COLLAB_MONITOR" start @your-listen-name \
"$ORCHESTRATOR_REPO/collab/FLEET-STANDING.md" \
"$ORCHESTRATOR_REPO/collab/ARM-MONITORS.md"
# Keep this foreground stream attached to the orchestrator's monitored command session
bash "$COLLAB_MONITOR" follow @your-listen-name
# Verify or stop it without remembering a PID
bash "$COLLAB_MONITOR" status @your-listen-name
bash "$COLLAB_MONITOR" stop @your-listen-nameUse foreground mode when a parent monitor/supervisor owns the process:
bash "$COLLAB_MONITOR" run @your-listen-name collab.md another-collab.mdstart is the durable producer; it does not wake an orchestrator by itself. Attach follow in a monitored long-running command session before relying on alerts. Each successful start begins a fresh session log, and follow replays that session from its start before streaming new records until stop ends the monitor.
run --once performs one deterministic seed/poll and exits. It is appropriate for evals or an external scheduler; repeated calls use the same durable state. It exits non-zero when initial input, lock/state access, or event extraction fails, so a scheduler must treat non-zero as an incomplete poll.
Participation Law — a collab is a mailbox with no doorbell
Ratified by Etan 2026-08-14 after two leads and a worker each missed messages addressed to them in a shared collab. Writing to a collab makes a message durable, not delivered. Nobody is notified. A participant without a watcher on that file will not see it, no matter how urgent.
These rules bind every participant for the life of the collab.
- Arm before you work. The moment you post to a collab, are addressed in one, or are named a participant — arm a watcher on that file BEFORE doing anything else. Not after your task, not when convenient. An unwatched collab you are named in is an unread inbox.
- Waiting means detached, not looping. When you finish a unit and are waiting to be re-requested: detach a watcher and RETURN. Never hold a foreground turn open to poll, and never inspect another agent's pane to infer state — that is monitoring you were not asked to do, and it burns a turn that should have ended.
- Codex agents have no Monitor tool — use a background bash tail. This is not optional and
not a lesser substitute:
Read what it captured when you are re-invoked. A Codex that keeps working, or keeps polling in the foreground, because "it has no monitor" is choosing the wrong half of the contract.
tail -n0 -F <collab-path> & # detached, then RETURN - Dedup by line hash. A collab that gets rewritten (formatting, section moves) must not re-emit its whole history as new events. Hash lines; emit only unseen ones.
- Stop when you post your DONE — not before, not after. The watcher's life is exactly the lane's life. A watcher outliving its lane is noise; a lane outliving its watcher is a silent handoff.
- Pings are pointers, never restatements. In-pane: one line saying WHERE to look and the one
fact that makes it urgent —
Read <file> §<section> — your worker is blocked. The collab holds the detail because the collab survives restarts and the pane does not. A long message duplicating a collab post is backwards, and long payloads break the receiving pane. - Leads own reviewer monitoring; workers push, notify, stop. A worker that keeps watching its own reviewer has taken the lead's job and stayed alive to do it.
Failure mode to recognize: if a handoff "went unanswered", check whether the recipient had a watcher on that file before concluding anything about the recipient. Silence from an unwatched collab is not refusal, disagreement, or absence — it is a message that was never delivered.
Supervision: Watch, Then Read Once
A supervisor MUST NOT poll read_screen in a loop for one worker outcome. Repeated screen reads are a defect, not diligence: arm a process-exit or background-log watch, let it wake the supervisor, and read the finished screen/log once.
For headless Codex workers, use the codex-workflows skill's watch primitive. It observes process exit first and parses the completed log once. For this monitor, keep follow attached to the supervisor's monitored long-running command session; do not replace it with repeated screen inspection.
Routing Grammar
The filter is tag-scoped and anchored on both sides of a mention, so email-like text such as owner@listener does not route. For routed headings, only mentions in the recipient field between the arrow and event-summary separator qualify; a listener mentioned later in the summary is not a recipient. It accepts:
- a routed Markdown header such as
### @author → @your-listen-name — event; - a direct line beginning
@your-listen-name:or→ @your-listen-name, with the arrow form followed by end-of-line or a:,-, or—separator.
A direct line at the end of a file is held until a standalone trailing author signature (— @author or -- @author) or later heading closes its message block. Contextual dash lines and signatures that merely cc the listener do not close or classify a block. This prevents a split write from alerting before a self-author signature arrives. A block authored by the listen name—either before the routing arrow in its header or in a trailing — @your-listen-name signature—is classified as SELF-POST rather than emitted as inbound NEW-FOR mail. A recognized foreign signature overrides an earlier self-authored heading so nested inbound mail remains visible.
Prose that merely contains the tag, TASK_DONE, error, failed, PR, or done is not an event. If a post matters to a listener, address it using the routing grammar.
Fenced and indented code is excluded from routing, so examples of the grammar do not wake the monitor, including four-space fenced blocks nested beneath a Markdown list item and fences opened directly on a list-marker line. Backtick markers whose info remainder contains another backtick are treated as inline content, not as fence openers. A four-space routed reply immediately nested beneath a list item remains prose and can route normally. An unclosed fence emits WATCH-WARN reason=unclosed-fence, makes the poll incomplete, and is retried until the fence closes; start does not publish readiness while that condition exists.
Guarantees
- Silent seed: current matching history is hashed without alerting when a file is first watched.
- Content-hash dedup: a previously seen event line does not re-fire when any watched file grows or identical content is appended to another watched file for the same listen name. If the seen-set disappears or becomes unreadable after size baselines exist, the poll fails closed with
reason=state-failedinstead of replaying history. - Self-classification: self-authored routed headers and trailing-signature blocks emit a distinct
SELF-POSTrecord, never a normal inbound alert. - Shrink detection: a byte-size decrease emits a distinct
SHRINKrecord with its byte delta. - Bash 3.2 safety: state lives in ordinary files; the implementation uses neither
declare -Anorcomm. - Durable lifecycle:
startreports success only after the detached runner completes its first seed/poll, allowing 30 seconds by default for a large healthy historical seed, and records a validated PID plus per-start instance identity by listen name; an interrupted pre-readiness start terminates and reaps its unpublished runner, duplicate starts fail, ambiguous live-PID conflicts preserve their state for recovery instead of signaling or orphaning a process,stopnever signals a stale/reused PID or a same-name monitor from another state root, and a zombie runner is treated as stopped instead of timing out. - Stable path identity: relative and absolute spellings resolve to one size-state record, so a spelling change cannot silently re-seed a file.
- Transient-file retry: a watched path that temporarily vanishes or fails mid-read emits
WATCH-WARNand is retried without killing the foreground monitor;run --oncereports the incomplete poll with a non-zero exit. - Code-example exclusion: fenced and indented code cannot impersonate routed mail; an unclosed fence is an explicit incomplete poll rather than silent event loss.
- Attached alert consumption:
followstreams the current start session's log to the orchestrator and exits after that named monitor stops; detachedstartoutput alone is never presented as a wake mechanism.
Delivery is at-least-once. The monitor emits an event before atomically persisting its hash and then updating the file-size baseline. A crash at that boundary can duplicate the last alert, but does not intentionally mark an un-emitted alert as delivered.
Output
MONITOR-ARMED name=@listener files=2 state=/.../listener
WILL-NOT-CATCH :: ...
FOLLOWING name=@listener pid=<pid> log=/.../monitor.log
NEW-FOR-@listener file=/path/collab.md hash=<sha256> :: <literal event line>
SELF-POST-@listener file=/path/collab.md hash=<sha256> :: <literal own-write line>
SHRINK file=/path/collab.md old_bytes=123 new_bytes=80 delta_bytes=43
WATCH-WARN file=/path/collab.md reason=temporarily-absent|read-failed|hash-failed|state-failed|unclosed-fence action=retry
STATE_CONFLICT name=@listener pid=<pid> action=not-started|not-signaled state=preservedState defaults to ~/.local/state/collab-monitor/<listen-name>/; the special path names . and .. are rejected. Set MONITOR_STATE_DIR only for isolated tests or a deliberately managed alternate state root. Set POLL_SECONDS to a positive integer or decimal to change the foreground/background polling interval. start waits up to 30 seconds for the initial seed/poll; set START_TIMEOUT_SECONDS to a positive whole number no greater than 86400 when a very large or slow board needs a longer readiness deadline. Zero and malformed polling or startup values fail before run or start arms, while status and stop remain available for recovery.
On STATE_CONFLICT, inspect the preserved PID, instance, readiness, and run-lock records before retrying; do not delete state or signal the PID until its command and per-start identity are verified.
What This Will Not Catch
The runner prints these limits on every arm because silence is not full safety:
- same-size rewrites in place; growth rewrites trigger a scan but may look like appends;
- messages outside the anchored routing grammar;
- unclosed trailing direct messages, which are held until a signature or later heading closes the block;
- inbound direct mail nested in a self-authored block remains self-classified unless a recognized foreign signature closes it;
- process death without an external supervisor;
- worker completion represented only in an agent registry.
Use a tamper/file-integrity monitor for rewrite detection and registry polling for worker completion. This skill is the addressed-message channel, not either of those systems.
Migration
Until the external orchestrator caller is migrated, this skill is the implementation source of truth. The PR that introduced it proposes turning orchestrator/scripts/collab-monitor.sh into a thin compatibility caller rather than maintaining a second monitor implementation.
Evaluation
Run:
bash skills/golem-powers/collab-monitor/evals/run-evals.sh candidate
bash skills/golem-powers/collab-monitor/evals/live-two-file-smoke.shThe deterministic suite covers the recorded monitor failures, /large-plan's exact broken grep done teaching repro, addressed completion/blocker teaching in linked workflows, rejection of repeated read_screen supervision, code-example exclusion and malformed-fence recovery, shrink detection, limitations disclosure, durable lifecycle safety at the shipped poll interval, exact listen-name boundaries, path identity, and transient-file retry.
Best Pass Rate
81%
Opus 4.6
Assertions
85
3 models tested
Avg Cost / Run
$0.2485
across models
Fastest (p50)
2.4s
Haiku 4.5
Behavior Evals
Phase 2 baseline — skill quality on ClaudeBehavior Baseline
| Assertion | Opus 4.6 | Sonnet 4.6 | Haiku 4.5 | Consensus |
|---|---|---|---|---|
| no-task-done-match | 2/3 | |||
| no-error-failed-pr-match | 3/3 | |||
| no-code-example-alert | 2/3 | |||
| unclosed-fence-warning | 2/3 | |||
| invalid-fence-closer-stays-code | 3/3 | |||
| list-nested-fence-stays-code | 2/3 | |||
| compact-list-fence-stays-code | 2/3 | |||
| backtick-inline-span-is-not-fence | 1/3 | |||
| list-reply-routes | 3/3 | |||
| summary-mention-is-not-recipient | 2/3 | |||
| embedded-at-is-not-recipient | 2/3 | |||
| code-exclusion-documented | 2/3 | |||
| tag-scoped-filter | 2/3 | |||
| no-self-alert | 1/3 | |||
| header-author-detected | 1/3 | |||
| signature-author-supported | 3/3 | |||
| strict-signature-grammar | 2/3 | |||
| self-post-classification | 3/3 | |||
| foreign-signature-overrides-heading | 2/3 | |||
| first-alert-once | 2/3 | |||
| no-refire-after-growth | 2/3 | |||
| hash-backed-state | 3/3 | |||
| no-historical-alert | 3/3 | |||
| history-hashed | 3/3 | |||
| seed-persistence-failure-retried | 1/3 | |||
| missing-seen-set-fails-closed | 2/3 | |||
| future-events-still-visible | 1/3 | |||
| no-declare-associative | 2/3 | |||
| bash-3-run | 3/3 | |||
| file-backed-state | 2/3 | |||
| no-dot-state-escape | 1/3 | |||
| invalid-poll-rejected | 2/3 | |||
| invalid-start-timeout-rejected | 3/3 | |||
| recovery-commands-ignore-poll | 1/3 | |||
| no-comm | 3/3 | |||
| one-real-change | 1/3 | |||
| unchanged-file-silent | 2/3 | |||
| one-real-alert | 3/3 | |||
| unrelated-done-zero | 3/3 | |||
| broken-recipe-removed | 3/3 | |||
| monitor-armed-before-spawn | 2/3 | |||
| packaged-entrypoint-taught | 3/3 | |||
| attached-consumer-taught | 0/3 | |||
| addressed-status-taught | 2/3 | |||
| codex-adapter-taught | 2/3 | |||
| message-monitor-is-not-liveness | 2/3 | |||
| liveness-before-spawn | 2/3 | |||
| shrink-alert | 3/3 | |||
| old-new-bytes | 2/3 | |||
| shrink-delta | 2/3 | |||
| not-normal-message | 2/3 | |||
| will-not-catch | 1/3 | |||
| rewrite-limit | 2/3 | |||
| registry-limit | 1/3 | |||
| unclosed-message-limit | 2/3 | |||
| durable-pid | 2/3 | |||
| first-poll-readiness | 1/3 | |||
| large-seed-readiness | 3/3 | |||
| fatal-first-poll-rejected | 3/3 | |||
| interrupted-start-cleans-child | 1/3 | |||
| failed-event-hash-rejected | 2/3 | |||
| attached-log-consumer | 3/3 | |||
| running-status | 3/3 | |||
| stop-by-name | 3/3 | |||
| no-remembered-pid | 1/3 | |||
| stale-start-lock-recovered | 3/3 | |||
| duplicate-start-rejected | 3/3 | |||
| poll-sleeper-resilience | 3/3 | |||
| stale-or-reused-pid-not-signaled | 3/3 | |||
| pid-identity-is-state-scoped | 1/3 | |||
| identity-conflict-preserves-state | 3/3 | |||
| zombie-is-not-running | 3/3 | |||
| no-prefix-listener-alert | 2/3 | |||
| foreign-event-visible | 3/3 | |||
| pending-event-visible | 2/3 | |||
| one-size-state | 2/3 | |||
| monitor-survives | 2/3 | |||
| warning-keeps-requested-path | 2/3 | |||
| restored-event-visible | 2/3 | |||
| read-failure-retried | 3/3 | |||
| once-failure-is-incomplete | 2/3 | |||
| repeated-read-screen-rejected | 3/3 | |||
| process-exit-watch-taught | 1/3 | |||
| codex-workflows-cross-reference | 1/3 | |||
| valid-watch-invocation | 2/3 |
Token Usage
Cost per Run
| Model | Input Tokens | Output Tokens | Cost / Run | Cost / 1K Runs |
|---|---|---|---|---|
| Opus 4.6 | 6,700 | 7,841 | $0.6886 | $688.60 |
| Sonnet 4.6 | 2,381 | 3,113 | $0.0538 | $53.80 |
| Haiku 4.5 | 1,992 | 2,167 | $0.0032 | $3.20 |
Response Time (p50)
Response Time (p95)
| Model | p50 | p95 | Overhead |
|---|---|---|---|
| Opus 4.6 | 9.0s | 16.8s | +86% |
| Sonnet 4.6 | 5.3s | 8.2s | +53% |
| Haiku 4.5 | 2.4s | 4.5s | +85% |
Last evaluated: 2026-03-12 · Data is generated from skill assertions (real cross-model benchmarks coming soon)
Changelog entries are derived from eval runs and skill version updates. Full cascading changelog (Phase 4D) coming soon.
Best Pass Rate
81%
Assertions
85
Models Tested
3
Evals Run
15
- +Initial release to Golems skill library
- +85 assertions across 15 eval scenarios
- +Eval fixtures included