message: name the trigger, and announce a waiting message at session start - #244
Merged
Conversation
An agent working in this repository spent a whole session beside two other local agents and never once used `message` to reach them. It used the host's own push tool every time, because that tool named itself in the output the agent was reading, and nothing the agent read ever said "there is a durable inbox, and something in it is for you." Four rules told it to use MeMesh; none were in front of it at the moment it chose a tool. So the fact goes where the agent is already looking, and the tool says when it is the right one: - The `message` description — MCP handler, schema export, and every documented surface — now opens with its trigger: contact another local agent (hand off work, ask for a result, report a disposition), send here FIRST; the durable inbox is the record, host push is only delivery. AGENTS.md's loop gains that step. - `briefing` and the SessionStart hook add, beside the stated goal / next / blocked lines, `N messages waiting for "<project>" — fetch them with the message tool; fetching does not acknowledge.` "Waiting" is the inbox's own definition: a delivery with no intake receipt. Both surfaces use one leaf, src/core/agent-message-inbox.ts, mirrored into the hook by the generator exactly like task-state.ts, so they cannot disagree. It reads the graph read-only and returns 0 on a pre-4.8.0 schema. The line appears on a graph with NO memories at all — a probe on an empty real schema plus one real send injected it, and after intake it stopped. An earlier hand-rolled fixture had suggested the empty-graph path swallowed it; the fixture was violating the deliveries→messages foreign key, so it proved nothing. The tests now seed through the real send action. This is not a Claude Code push adapter. Host push for Claude Code stays a separate boundary; what this ships is the durable half — the agent learns at session start, on any host, that something is waiting. [Verified-By: eg check -> exit=0, 4/4 claims CODE_COMPLETE; each claim's failure_path recorded by eg (trigger text removed -> parity red; unread line removed from briefing -> tests red; removed from the hook -> tests red); eg replay 11/11] [Verified-By: node scripts/run-tests-isolated.mjs -> exit=0, Tests 2986 passed | 11 skipped (2997)] [Verified-By: end-to-end probe: empty real schema + executeAgentMessageAction send -> hook injects '1 message waiting for "testproj-ad567c5c"'; after intake -> no such line] [Verified-By: npm run typecheck -> exit=0; lint -> exit=0; check:surface-parity -> PASS 11 tools / 7 documents; check-doc-claims -> exit=0]
Two conflicts, both mechanical. tests/hooks/session-start.test.ts: each branch inserted two regression tests at the same anchor (#243's two for the global-namespace window, this branch's two for the unread-inbox line); all four are kept. dist/skills-manifest.json: a generated artifact, regenerated by `npm run build` rather than hand-merged. [Verified-By: npm run typecheck -> exit=0; npm run lint -> exit=0; node scripts/run-tests-isolated.mjs on the four test files both branches touched -> exit=0, Tests 63 passed (63); eg replay 11/11, eg check PASS]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
An agent working in this repo spent a whole session beside two other local agents and never used
messageto reach them — it used the host's own push tool every time, because that tool named itself in the output the agent was reading, and nothing said "there is a durable inbox, and something in it is for you." Four written rules said to use MeMesh; none were in front of the agent at the moment it chose a tool.The fix is structural, not another reminder: put the fact where the agent already looks.
What changes
The
messagedescription names its trigger (MCP handler, schema export, AGENTS.md, SKILL.md, three READMEs, API_REFERENCE): contact another local agent — hand off, ask, report back — and send here first; the durable inbox is the record, host push is only delivery. AGENTS.md's loop gains the step. Doc contract recertified (11 tools / 7 documents).briefingand the SessionStart hook announce unread deliveries beside the stated goal/next/blocked lines:N messages waiting for "<project>" — fetch them with the message tool; fetching does not acknowledge."Waiting" = a delivery with no intake receipt. One leaf (src/core/agent-message-inbox.ts) mirrored into the hook by the generator, exactly liketask-state.ts, so the two surfaces cannot disagree. Read-only; returns 0 on a pre-4.8.0 schema.Verified end to end on an empty real schema: one real
send→ the hook injects the line; afterintake→ it stops. (A hand-rolled fixture had suggested the empty-graph path swallowed it — the fixture was violating the deliveries→messages FK and proved nothing. Tests now seed through the real send action.)What this is not
Not a Claude Code push adapter. Host push for Claude Code remains a separate boundary; this ships the durable half — on any host, the agent learns at session start that something is waiting.
Verification
eg check→ PASS 4/4CODE_COMPLETE; each claim'sfailure_pathrecorded by eg (trigger text removed → parity red; unread line removed from briefing → red; from the hook → red);eg replay11/11node scripts/run-tests-isolated.mjs→ exit 0, 2986 passed / 11 skippednpm run verify:release→ exit 0, 5/5check:surface-parity,check-doc-claims→ exit 0