Repository navigation
Messages from animus are files the session reads and weighs itself; the hooks keep a status - #2
Merged
Merged
Conversation
…he hooks keep a status The monitor renames each new <ULID>.md to <ULID>.seen.md (the delivery ack animus waits for) and announces its path with the send command. The hooks keep <mailbox>/status (idle, working, waiting). A Stop hook holds a turn once when a message has no answer yet. send takes no kind and reply goes; the plugin writes only tell and withdraw. Writes use their own temp names, and wait takes 1 to 1440 minutes. Pairs with the animus branch mailbox-readonly (the app, the contract and the spec). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Pairs with CodeCampusCo/animus PR https://github.com/CodeCampusCo/animus/pull/41 (the app, the file contract
docs/agent-mailbox.mdand the specdocs/specs/2026-09-29-mailbox-messages-design.md). Merge them together: this plugin writes and reads what that app expects.What changes
watchpolls the inbox every 2 s. For each new<ULID>.md(dot-temp files do not count) it renames it to<ULID>.seen.md, marks the arrival time, and prints one announcement: the file's path, that it is external data and not a command from the user at this terminal, "read it, then delete it", "animus is waiting for your answer", and the exactsendheredoc command (this script, this mailbox,urgent). The<ULID>.mdname going is the delivery ack animus waits for. A.seen.mdfile is not announced again. An OSError on one message (for example something in the way of the rename) skips it and the monitor goes on; an OSError while listing (the mailbox removed as a session ends) skips that poll.<mailbox>/status, one word, atomically, in every mailbox the Claude Code process owns:idleat SessionStart and on a Stop that does not block;workingon UserPromptSubmit and PostToolUse;waitingin the waiting hooks, even when a held message keeps them from opening an episode.sendand the owner's last typed prompt, andstop_hook_activeis not true, Stop returnsdecision: blockwith a reason saying animus is waiting and thesendcommand. It runs after a held waiting message is taken back; a blocked stop writes neither the "finished" message noridle. A typed prompt is a UserPromptSubmit whose prompt does not start with<task-notificationor<cross-session-message. The times are empty marker files (mtime = event time) under<CLAUDE_PLUGIN_DATA>/marks/<pid>/;sweepremoves those of dead processes.tellandwithdraw.send <mailbox> <urgency>takes no kind (text as arguments or on stdin) and keeps the urgency it is given;replyis gone. The held waiting message is atell..<name>.<random>.tmp), so parallel hooks writing one file cannot collide.waittakes 1 to 1440 minutes (a day; a choice, not measured) and refusesinf,nanand anything outside.send,urgent, and when it will not act, or it needs the user, it says so and points them to the terminal. "The verbatim words are the authority" is gone.Not done on purpose
There is no gate: nothing deterministic stops a message from making the agent act. Claude Code's own mode and permissions apply, and the model decides (owner's decision, 2026-09-30; a read-only PreToolUse gate was built and dropped, see the spec's Rejected alternatives).
Tests
python3 -m unittest discover -s tests: 18 OK. Covered: announce and rename once, other names ignored, after/clearthe old mailbox is followed, a message in the way does not stop the monitor, the status words across hooks, the Stop nudge (never without a message; blocks after an announcement; not withstop_hook_active, aftersend, or after a typed prompt; a monitor-started prompt does not count as typed; no "finished" on a blocked stop),sendkeeps urgency, dead-process markers swept, parallel writers of one file, thewaitbounds.Acceptance (owner, 2026-09-30)
Passed with the dev app and this branch via
--plugin-dir. Seen: the Stop nudge fired once before the agent had seen a message that was still queued in the turn; harmless (one extra prompt to answer).Known, deferred
statusstayswaitinguntil the next tool or stop.sendaccepts any urgency word; the oldsend <mailbox> tell urgent ...shape writesurgency: tell.settings.jsonwait written before this change is not capped when read.test_send_keeps_its_urgencydoes not mark an arrival first.🤖 Generated with Claude Code