From a Tool Call to a Shared Handoff
This chapter follows ai-memory's first operational boundary: how work leaves a coding-agent harness and becomes a bounded, privacy-filtered handoff for a later session. The useful judgment is not simply whether an event was captured, but what survives capture, who owns it, how a session ends safely, and when optional native-session continuity is worth more complexity than an ordinary hook-based handoff.
Capture is a pipeline, not a transcript
A coding agent produces more activity than a future agent needs. It may submit a long prompt, inspect several files, call tools, retry a command, compact its context, and emit notifications before reaching one useful conclusion. If ai-memory stored every byte as an undifferentiated transcript, it would create a large privacy and retrieval problem. The capture path therefore begins by deciding what kind of lifecycle event arrived and what bounded representation that event is allowed to contribute.
The event vocabulary is intentionally operational. Session start identifies a new run. A user prompt records what the person asked. Pre-tool and post-tool events mark tool boundaries and outcomes. Compaction events provide a checkpoint when an agent compresses its working context. Notifications, stops, and session end describe changes in the interaction's state. The server normalizes client-specific names into this smaller vocabulary instead of allowing every harness to invent a new storage model.
That normalization is important because a hook payload is untrusted input. The hook router sanitizes it before creating a durable observation, and the typed observation boundary is designed so callers cannot construct an unsanitized stored object by taking a different code path. This is a control-flow decision as much as a redaction decision: untrusted text must pass through the same boundary whether it came from a generated integration, a native command, or a direct HTTP client.
The limits are part of the meaning. User prompts and post-compaction summaries are capped at 16 KiB. Notifications and tool excerpts are capped at about 2 KB, with a further 16 KiB backstop after sanitization. These caps do not claim that a short excerpt contains the whole truth of a tool call. They define the maximum amount of that event that can enter the durable observation path. A future session can search what was captured, but it cannot retrieve details that were intentionally left outside the boundary.
The privacy policy can act even earlier. A repository may place a marker file that declares paths to ignore for recognized file-tool events. When a candidate path matches, the client drops the entire event before it reaches the local spool, queue, network, transport logs, or server storage. An allowlist installation can reverse the default: a repository without the marker emits no lifecycle event at all. This is valuable for a private checkout or a project that should opt in deliberately, but it is a lexical, schema-specific boundary rather than complete data-loss prevention. Shell commands, free-form patches, prompts, assistant text, symlinks, aliases, and ambiguous tool payloads are not all path-attributable.
The capture path is also designed not to hold the agent hostage. Shell hooks send events with short timeouts. Native hook commands can spool entries locally with stable idempotency keys and let a detached drain helper deliver them later. The server queues accepted work through its writer actor and applies backpressure when saturated instead of allowing an unbounded queue to grow. This makes capture best-effort in timing but durable in intent: an unavailable server can leave a local backlog, while a server that is full can refuse new work rather than silently pretending it accepted everything.
That trade-off explains why a capture event is an operational projection, not a complete native transcript. The system wants enough structured evidence to build continuity without making every agent interaction a permanent copy. In practice, the value of a post-tool outcome or compaction summary is not that it reconstructs every hidden token. It is that it records a bounded signal about what the agent attempted, what happened, and where the next session should look.
Session end turns evidence into a baton
The most consequential transition is a true session end. ai-memory creates a rule-based sessions/<id>.md summary page and opens a handoff in one SQLite transaction. It also records the observation generation covered by that ending and marks the session ended. Putting these effects together prevents a later recovery path from seeing a half-finished state in which the session is closed but no handoff exists, or a handoff exists without a stable record of which observations it summarized.
The generation marker solves a less visible problem: clocks are not reliable enough to decide whether a resumed session has new work. A delivery can be duplicated, delayed, or replayed after a process interruption. If the same ended session receives the same observations again, the server can recognize that the generation has not advanced. If new observations arrive after the earlier end, a later ending can legitimately produce a new result. This makes the transition converge on stored state rather than on guesses from wall-clock timestamps.
The retry model is deliberately honest. Native keyed events carry a stable idempotency key, and a key is complete only after the downstream processing has finished. If a process crashes during those effects, a replay may repeat an already applied effect rather than lose the remaining work. For an interrupted session end, the replay can complete the wiki commit, durable provider job, and pending key without appending another copy of the observation or creating a second logical handoff. The guarantee is therefore about converging state and avoiding duplicate logical input, not about pretending that every filesystem action is magically atomic across all resources.
Once the handoff is open, selection has its own rules. A manual handoff is an explicit baton and takes precedence over an automatic session-end handoff. Among eligible automatic handoffs, the receiver's project and current directory matter; a handoff from a parent directory can be relevant to a child directory, while a similarly named sibling path should not be treated as the same place. Creating a new automatic handoff can expire older automatic candidates from the exact directory, and accepting one can expire older eligible automatic candidates without consuming manual work or a sibling directory's work.
Ownership adds another boundary on a shared server. Pages written to a project are shared knowledge, so another operator can retrieve a decision or gotcha that one person's session discovered. An open handoff is different: it represents an individual's unfinished context. By default, the creator sees their own handoffs and deliberately shared rows, not a teammate's private baton. A manual handoff can be marked shared when the intent is to pass it to anyone in the project. Root-authorized recovery can cross that boundary explicitly, which is safer than making every handoff public by default.
The same mechanism helps with context compaction. When a supported agent compacts its working context, the compaction hook can produce a fresh session page summarizing the work so far. The raw conversational context may no longer be available inside the agent, but the summary can be found through the memory surface. This does not restore every lost token; it restores a durable checkpoint with enough structure to continue investigating rather than starting from the original symptom.
Not every harness exposes the same lifecycle. Some clients have no reliable true session-end event and need an explicit ending action when the user wants a summary and handoff. Some can capture events but discard the output that a session-start hook would normally inject, so the receiving agent must list and accept a handoff through MCP. Another client may expose a pre-invocation hook before every model call; ai-memory treats only the documented initial invocation as the startup boundary, so a handoff created during the same conversation is not fed back into that conversation's next model call. These are not cosmetic differences. They determine whether the baton is delivered automatically, manually, or not until a later recovery action.
Two levels of cross-agent continuity
Ordinary hooks are the simpler path. They capture the work as the harness exposes it, create session summaries and handoffs, and let any compatible next agent retrieve the result. If the real requirement is “leave Claude Code at the end of the day and let Codex know what remains,” this path is often enough. It carries the semantic baton without trying to reproduce the first agent's private context.
ai-memory run adds an optional managed-workstream layer for users who need more than a summary. It selects or creates one logical workstream, opens a renewable lease so two launchers cannot silently race its state, and starts the chosen harness through that harness's native create or resume mechanism. When the child exits, ai-memory reads the harness's local session store without modifying it. It imports visible user and assistant messages, completed tool calls and results, and compaction boundaries into an append-only portable ledger. Hidden reasoning, provider-private records, and unsupported fields are left out.
The distinction between read-only import and native resume is deliberate. Every harness stores private, versioned state in its own format. Converting one agent's transcript into a fake session for another could corrupt assumptions that ai-memory does not own. Instead, the launcher preserves each harness's native session when it can resume it, while the portable ledger carries the visible semantic history between harnesses. A Codex session does not become a counterfeit Claude session; a later Claude run receives bounded portable context and can resume its own native state when linked.
The next harness receives an unseen, bounded delta rather than an unbounded transcript. The complete visible ledger remains searchable for questions that need older context, and imported events use deterministic identifiers and cursors so a retry does not duplicate the history. The launcher also uses a lease and explicit run identity to coordinate delivery. If the server is briefly unavailable, the native harness can remain usable while the launcher retries within the lease window; if the process dies uncleanly, the lease expires and a later run resumes from the last committed cursor.
This extra continuity costs more operational complexity. The user must install and maintain the managed launcher, the chosen harness must expose a readable native store or a compatible lifecycle surface, and a client may be beta or unable to acknowledge delivery perfectly. The reward is exact native-session resume where supported, plus a portable ledger that a different harness can search. The simpler hook path remains the right choice when a reliable handoff is enough.
The resulting boundary is easy to state. ai-memory captures what a harness can safely and usefully expose, compiles selected evidence into a session account, and transfers a typed baton under project and owner rules. It does not promise that every private token, hidden reasoning step, or client-specific transcript field will cross the boundary. That restraint is what lets the handoff remain portable: it carries visible work and its consequences, while each harness keeps ownership of its own private session format.
The next architectural question follows directly. Once an event or handoff has been accepted, which representation is authoritative, which one is only a search aid, and how can a human inspect or repair the result? Those are storage and state-ownership questions, not merely choices among databases.