Skip to content

The SessionStart hook (memprove hook)

memprove hook session-start is the handler hook install writes into .claude/settings.local.json. At the start of every Claude Code session in the Workspace it reads the session’s JSON on standard input, chooses the Task (this client session’s context, else this directory’s context, else the only Task in progress in this Workspace), and prints one opening statement and the Pack in a fence, within a budget of 9000 code units for the Pack and 10000 for the whole output; it sends read requests only and always exits 0. The opening says which Task and why, the current UTC time, the agent the environment declares, and the open-item sentence of the takeover rule; on a fork source it adds that the listed Sessions were not started by this session. A completed or cancelled Task gets no Pack: When this client session’s context names one, the hook prints only a statement that names the Task and its state; When this directory’s context names one, the hook goes on to the only Task in progress in this Workspace. With no Task to choose it prints one statement that says so and names the configuration directory it used.

The hook’s time limit. The hook gives itself 8 seconds to read the Pack, within the handler’s own timeout of 10 seconds that hook install writes, so that Claude Code never cuts it off first. When the daemon has not answered by then, it stops waiting, prints only

memprove: the Context Pack was not read within 8 seconds; no Context Pack was injected into this session; running memprove resume --pack in this session fetches it.

and exits 0, about 8 seconds after it started; it writes no last-Pack record and prints no token. The client then starts with no Pack and can read one with memprove resume --pack (or the MCP pack tool) once the daemon answers. To reproduce it, point the hook at a socket that accepts and never answers, in a Workspace whose context names a Task (MEMPROVE_DATA_DIR=/tmp/mute memprove hook session-start).

With MEMPROVE_CLIENT_SESSION set (the hook sets it for the Bash commands of the Claude Code session), every command uses that client session’s own context file and last-Pack record instead of the directory’s. Two sessions in the same directory then begin their own Sessions and never overwrite each other’s context. A value that is not 1 to 128 characters of A-Z, a-z, 0-9, _ and - is ignored, with a warning. memprove mcp serve also takes CLAUDE_CODE_SESSION_ID, which Claude Code sets for it. The agent (MEMPROVE_AGENT_NAME, MEMPROVE_AGENT_ROLE) is read by each process from its own environment, not from the client session.

Sub-agents, one client session each. An agent that hands pieces of one Task to sub-agents working in the same directory gives each of them its own client session name, set for every command the sub-agent runs. Such a client session is new: it has no context, so a plain begin is a usage error. The orchestrator takes the two IDs from this directory’s context and puts them in the sub-agent’s instructions:

Terminal window
memprove context show # the directory's context: Project, Task (no MEMPROVE_CLIENT_SESSION)
export MEMPROVE_CLIENT_SESSION=<name> # in the sub-agent's commands
export MEMPROVE_AGENT_NAME=<name> MEMPROVE_AGENT_ROLE=sub_agent MEMPROVE_PARENT_SESSION=<the orchestrator's Session>
memprove begin --project <PROJECT_ID> --task <TASK_ID>
memprove run --test-format cargo -- cargo test
memprove checkpoint create --fact "<what holds, conclusion first>" --evidence r1 --next "<next>"
memprove end --reason "<piece> done"

Each sub-agent runs its own commands, records its facts and open items on its own runs, and ends its own Session; it leaves decide, task complete, --withdraw and --reaffirm-all to the orchestrator. It may --supersedes the open items of its own stage and the statements of its own earlier Sessions (the same agent name); it does not supersede or withdraw a statement of another sub-agent or of the orchestrator. The orchestrator corrects afterwards: --supersedes for a statement that is wrong, --withdraw for one that no longer holds, --reaffirm for a fact that holds again. resume --text ends each statement with from Session k (from Session k「<name>」 when that Session declared an agent), which says which sub-agent wrote it.

What the daemon refuses a sub_agent. A Session that declared --agent-role sub_agent (or MEMPROVE_AGENT_ROLE=sub_agent, or the MCP begin’s agent_role) is refused three writes with 403 role_forbidden, exit 1, and nothing is written; standard error ends with the daemon’s reason, one fixed sentence that says who does it instead:

write refused when standard error ends with
decide always a Session declared as sub_agent cannot record a Decision; the orchestrating session or a person does it
task complete (and task transition --to completed) the request names a sub_agent Session, whatever runs it cites: task complete sends the context’s Session (with none in the context it is refused, exit 2, before any request), and task transition sends it only with --to completed of the context’s Task while the context has a Session; with no Session in the context (after end) or another Task named, it sends none, and the daemon does not judge that completion by role a Session declared as sub_agent cannot move the Task to completed; the orchestrating session or a person does it, and they can cite any Session's runs
checkpoint create with --supersedes, --reaffirm, --reaffirm-all, --withdraw, or --withdraw-session a target was written by a Session of another agent name, or by one that declared no agent, and is not an open item it supersedes (a withdrawal of another agent’s open item is refused too) a Session declared as sub_agent can supersede open items and the statements written by Sessions of the same agent name, and can withdraw only statements written by Sessions of the same agent name; superseding another agent's facts, next actions, and Decisions, and withdrawing any statement another agent wrote, is for the orchestrating session or a person

So a sub-agent may supersede another agent’s open item; may not supersede another agent’s fact, next action, or Decision; may not withdraw anything another agent wrote, an open item included; and may supersede or withdraw anything a Session of its own agent name wrote. --reaffirm <N> is a --supersedes of fact N with the same text, so it follows the same rule. --next alone replaces the next action in force without an edge and is never refused. A sub_agent’s --next therefore replaces the next action in force even when another agent wrote it: that replacement is a rule, not an edge the writer records, so the role check does not see it; the fixed text of the 403 speaks of an explicit --supersedes of a next action. One refused target refuses the whole Checkpoint. Ending another Session with session end <SESSION_ID> --abandoned is allowed to every role. An orchestrator, a person (--agent-role human) and a Session that declared no agent are refused nothing. The role is what the Session said about itself: the check guards against a mistake, not against an agent that declares another role. A completion sent without a Session (an older client, task transition --to completed after end or of another Task, or a direct call of the API without session_id) is not checked by role: the CLI sends only the Session its context holds.

Ending a sub-agent’s Session. An orchestrator that ends a Session a sub-agent left open, memprove session end <SESSION_ID> --abandoned --reason "<why>" from its own context, is recorded as that Session’s ender: its own Session and the agent it declares. The ended Session’s line then ends with ; ended by Session <j> (; ended by unlisted Session <id> when that Session belongs to another Task, ; ended by agent「<name>」(<role>) when the ender has no Session in its context). Nothing is typed for the ender, and no option names another one.

From docs/guide.md at 2625064cbf0a · Markdown

memprove About Roadmap llms.txt GitHub 中文 apache-2.0 · no cookies, no tracking