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).
One context per client session
Section titled “One context per client session”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:
memprove context show # the directory's context: Project, Task (no MEMPROVE_CLIENT_SESSION)export MEMPROVE_CLIENT_SESSION=<name> # in the sub-agent's commandsexport 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 testmemprove 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