Repository navigation
feat(inbox): open threads after compaction/resume, reply_to checks, chat-or-Inbox rule, notes refreshed at start - #2246
Merged
Conversation
…m the Inbox, and check reply_to The misfiled-thread AAR (2026-10-27): an agent carried a thread id across a context compaction and replied into the wrong thread. - After a compaction (Claude Code mod: session.compact refreshes PLANNOTATOR_INBOX_REMINDER for the existing SessionStart compact hook; Pi: the reminder re-sent after a compaction) and on a Claude Code resume, the session gets up to 5 of its open threads, read from the Inbox with a peek that makes no project and counts as no read. Bounded at 1.5 s, never starts the Inbox. - INBOX_REPLY_TO_CHECK in reply_to and read_thread descriptions; send_message adds one line when the session has not read the thread for 3 h or ever. - Agent note v2 adds the check and the Recommended: line; v1 blocks upgrade in place on re-add, even with the record lost; edited blocks are kept. - Tool cost re-measured on Pi (8,964 bytes).
…-read line - Health advertises peek: true; the mod and agent-link read the thread list only from an Inbox that says so (an older one would make a project for every folder that compacts or resumes). - classic.SessionStart is matched on source resume; a string additionalContext from another handler is kept. - The thread list leaves PLANNOTATOR_INBOX_REMINDER at the next main-loop step or turn, so ids and subjects do not linger in Bash children's environment. - The not-read line only for a message that names its thread (reply_to or a thread name), and worded "You last wrote in this thread at" when the session's own message was its latest contact. - Upgrading a shared note file refreshes every record naming that file. - Subjects drop zero-width and bidi characters and fold C1 controls. - Docs: hooks.json's description did change; the above.
…d_thread list, search); health's peek in the mobile ADR
…nstalled notes refreshed at start - Wake note: reply_to set to that reply id, never an id from memory. Server instructions: reply_to from the Inbox, never from memory; read_thread with asked_by anyone lists every thread. read_thread and search leads, asked_by and include_resolved described. body: the recommendation goes on the Recommended: line, never in a choice label. - refreshInboxNotes at every Inbox start: an installed note that is byte for byte an earlier version (and its record's) is replaced in place; edited, removed, damaged, read-only, record-less or concurrently changed files are left alone; CRLF, BOM, mode and symlinks kept; shared files written once. - send_message's hints built as a list, so the recommended-in-label nudge branch and this one merge in either order. - Tool cost re-measured on Pi (9,227 bytes).
…uctions # Conflicts: # packages/server/inbox-mcp.ts
… the person seems to be here The owner, 2026-10-27: an agent raised an Inbox decision again as a blocking question in the chat when the person typed there. A decision in the Inbox stays there; in the chat the agent says what waits and links the thread, but never asks it again with a blocking question tool (AskUserQuestion or the like); a chat question only for something new raised in the chat that needs no pictures or files, or when the person asks. - INBOX_CHANNEL_RULE in the agent tool's lead and the server instructions (2,027 of 2,048), the reminder (INBOX_REMINDER_TEXT, _NO_WAKE; after a compaction too), INBOX_SESSION_THREADS_CHANNEL in the thread list, the --help "Chat or Inbox" section and the skill. - Note v3 with the rule in place of v1's presence lines; v2 (never released) frozen beside v1 so refreshInboxNotes still takes it. - Wake note and get_guide_brief's lead shortened to fit; Pi tool cost re-measured (9,283 bytes).
…ard links left alone, records before the file, one channel-rule wording - Note v3's text is all literals (no shared constant); a test pins the SHA-256 of the v1, v2 and v3 blocks, so a released note cannot change without a new version. - refreshInboxNotes leaves a file with other hard links alone (hard-linked), writes agent-notes.json before the file and puts it back if the file's write fails (refused, nothing written, when the records cannot be written). - One wording: 'when the person writes in the chat' and 'never also ask it in the chat with a blocking question tool (AskUserQuestion or similar)' in the tool lead, server instructions (2,042 of 2,048), reminder, thread list, note, skill and --help. - --help's Threads: take reply_to from the Inbox, never from memory, plus INBOX_REPLY_TO_CHECK. - Reminder tests compare against the constants and check what the lines must carry; tests for the record naming v1 over a v2 block, the mode changing between read and write, and an unwritable agent-notes.json. - Docs: the block's v3 marker, the refresh's new cases. Pi tool cost 9,298 bytes.
…earlier block, so the next start repairs it refreshInboxNotes writes the record before the note; a crash between the two (or a failed put-back) left the record naming this version over a v1/v2 block, which then read as the person's edit forever: never refreshed, kept-edited on add, 'you edited it' on uninstall. ownedBy: a record naming this version owns any earlier block exactly as Plannotator wrote it (only Plannotator puts a record ahead of its note), in refresh, add, status and uninstall. Tests reproduce the state: the next start repairs it, add updates it, and an edited note under such a record stays the person's.
…rom INBOX_NOTE_START, not a v2 literal
…-instructions # Conflicts: # packages/core/inbox-types.ts
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
After a context compaction, an agent kept a thread id from its own summary and sent seven messages into the wrong Inbox thread (the misfiled-thread AAR, 2026-10-27). The Inbox filed each one where it was told. Separately, the owner asked that every rule an agent needs reaches it with no setup, and that installed notes update by themselves. Then, from a meta-analysis: every Inbox text decided chat-or-Inbox by whether the person "is here", which an agent cannot observe. An agent raised an Inbox decision again as a blocking question in the chat once the person typed there.
What changed
inboxSessionThreadsText): one header line, at most 5 rows, then where the rest is (More: read_thread with no id …; search …). This comes from a read-only peek (_metainbox-peek; health reportspeek: true). There is no list from an older Inbox, and no error after 1.5 s.INBOX_REPLY_TO_CHECKis in the list header.reply_tofield and the wake note say "never an id from memory".reply_to/threadnames a thread with person messages the session has not read, send_message's result adds a "You last wrote in this thread at …" line (not_read_since).INBOX_CHANNEL_RULE), the reminder (INBOX_REMINDER_TEXT,_NO_WAKE, so after a compaction too), the thread list header (INBOX_SESSION_THREADS_CHANNEL),plannotator inbox --help("Chat or Inbox"), the skill and note v3.asked_by/include_resolveddescriptions;Recommended:line inbody;These all fit within the 2,048-character caps: instructions 2,042, agent tool 1,910 (about 2,029 with the Board's card line). The Pi tool cost was re-measured: 9,298 bytes.
--helpalso gains the reply_to check: take the id from the Inbox, never from memory.refreshInboxNotesruns at every Inbox start, so an update reaches installed notes when the Inbox restarts onto it. It works deterministically on the existing marker rules:agent-notes.jsonis written before the file and put back if the file's write fails. If the records can't be written, the note isn't written either.packages/server/inbox-agent-notes-refresh.test.ts.Audit: which channel carries each rule, per host
Hosts:
reply_tofield: all hosts; wake note: CC, Pi, OC2Recommended:line, never in a labelbodyfield: CC, Pi, OC1, OC2; send_message guide: Codex/othersthreadfield: allINBOX_NAME_THREAD_LINE: CC, Pi, OC2, CodexnamingLine;name_this_threadin read_thread / wait_for_reply: all:::questionformatbody/ send_message description: allasked_by,include_resolved: allWhere a host has no automatic channel:
Live checks still owed
next.tracelists non-matching links as bypassed.turn.step/turn.start.session.compactreaches the mod under the real guard.Tests
inbox-agent-notes-refresh.test.ts,agent-link-session-threads.test.ts,session-threads-text.test.ts; register / mod cases.agent-notes.json, the mode changing, a record naming v1 over a v2 block, and the pinned hashes.mod/inbox.test.tsreal processes,live-proxy-node-port), which pass alone.Approved by the owner in the Inbox, 2026-10-27