0005 — Comments from the board to agents¶
- Status: Implemented (step 11.4, unreleased, for 0.2.0); the behaviour is in SPEC §1, §2 and §4. Needs the hooks of 0001.
- Size: ~1.5–2 agent-days; +0.5–1 if the
asyncRewakewake-up works and is adopted.
Goal¶
A comment written on a card reaches the agent of the bound session; the card shows whether it was delivered and read.
Model¶
comment: id, task_id, author (owner or session), body_md, created_at, delivered_at,
delivered_to (session), read_at. Later extended with optional step_id / attachment_id for
review steps and screenshots (0007). Events comment.added, comment.delivered,
comment.read.
Delivery¶
- Working session (documented hook behaviour): the hook receiver answers
PostToolUse/PostToolBatch/UserPromptSubmitwithhookSpecificOutput.additionalContextcontaining the unread comments for that session's task ("Owner comment on acme-shop-12: …; ack with comment_ack") → delivered. AStophook answersdecision: "block"with the comments asreasonwhen unread ones exist, so the agent handles them before ending the turn; guarded bystop_hook_active, the client's continuation cap and relaybay's own counter (at most twice per turn). - Idle session: by default the comment waits for the next
UserPromptSubmit; the coordinator seescomment.addedinevents_sinceand can forward it. Options considered for waking an idle session: anasyncRewakehook that long-polls relaybay and exits with code 2 when a comment arrives (first thought of as started atSessionStart; built started atStop, see the decisions below); Claude Code channels; the session's cross-session inbox (reachable only from processes started by that session, so again via a hook). - Sessions started by relaybay (0012) receive comments directly.
- Marked read when the agent calls
comment_ackor replies.
API¶
comments_list(task, unread_only?), comment_ack(id), comment_add(task, body) (agents can reply).
Hook endpoint gains PostToolUse, PostToolBatch and the Stop answer; relaybay setup adds
the extra hook events (the marker rules stay the same).
UI¶
Comment box in the task dialog; list with "sent / delivered / read" marks, live over SSE; a small unread counter on the card. Unanswered agent replies appear in the Inbox (0004).
Risks¶
| Risk | Mitigation |
|---|---|
A Stop block loops |
stop_hook_active, own counter, client cap |
| Comments injected into the wrong session | Delivery only to the exactly linked hook session of the bound session |
| Comment text as prompt injection | It is the owner's own text; agents treat it like a user message; length limit |
| Idle sessions never see a comment | Shown as "sent, not delivered"; coordinator forwards; wake-up options verified first |
Decisions taken while building¶
- Exact link only. A new
session.cc_exactmarks hook ids the agent linked itself (hook_session); links guessed from the folder (and every link made before migration0008) get no comment text until the agent passeshook_sessiononce. - Delivery events:
UserPromptSubmit,PreToolUseandPostToolUse(added to the installed events).PostToolBatchis not installed:PostToolUsealready covers every tool call. Comments fit in about 8000 characters per answer (Claude Code movesadditionalContextover 10,000 characters into a file); the rest follow with the next events. - Linking is the caller's own. An id another live session linked exactly is never moved (the
write answers with a warning line), and
task_bind_sessionlinks no hook id at all, so a coordinator binding a session cannot pull that session's comments into its own context. - Rebind hands delivered-but-unread comments to the newly bound session.
- Stop semantics. relaybay blocks at most twice per turn per session and twice per comment in
all (then the SessionStart line and comments_list remind), and never stacks onto a
continuation it did not start: with
stop_hook_activeset and no relaybay block in this turn it allows. Its counter resets onUserPromptSubmitand whenever it allows aStop, because a turn woken by the wake-up hook starts without a prompt. - Read marks. An owner comment is read on
comment_ackor a reply (in_reply_to, else every unread one of the task). An agent reply is read when the owner presses "Mark replies read" or writes a comment on the task. - asyncRewake: built as an opt-in, not verified live. The hooks reference documents
asyncRewakeas a command-hook field ("runs in the background and wakes Claude on exit code 2"; stderr, or stdout when stderr is empty, is shown to Claude as a system reminder), says anasyncRewakehook that exits 2 wakes Claude even when the session is idle, and that Claude Code still enforcestimeouton it (default 600 s for command hooks). That is enough to wire it safely:relaybay setup --wake(default off, command mode only) adds a separate, markedStophook that long-polls/hooks/claude-code/waitfor up to 25 minutes with a 1800 s hook timeout and exits 2 only with comment text, 0 in every other case. Starting it atStopinstead ofSessionStartre-arms it after every turn; a newer wait supersedes the older one. Tested against a real relaybay server with the hook command run as a process; not verified against a live Claude Code (the reference names no minimum version forasyncRewake). Because a build that ignored the field would hold every turn's Stop for up to 30 minutes, setup refuses--wakewithout--force-wakewhileMIN_ASYNC_REWAKE_VERSIONis unknown, anddoctorshows the installed hook asUNVERIFIED. The reference documents no hook input field that tells a hook it runs in the background, so the client cannot detect the fallback itself. Without it, a comment waits for the next prompt, and the coordinator seescomment.addedinevents_since. - Not built in this step: the unread counter on the card, channels and the cross-session inbox.