How to Implement Cross-Agent Handoffs Between Claude Code and Codex in ai-memory
ai-memory enables seamless cross-agent handoffs by providing Model Context Protocol (MCP) tools that let one agent create a structured handoff (memory_handoff_begin) and another agent consume it (memory_handoff_accept), preserving full context across Claude Code and Codex sessions.
The akitaonrails/ai-memory repository implements a server-side handoff mechanism that eliminates context loss when switching between AI agents. By using dedicated MCP tools, you can transfer session state—including file changes, open questions, and next steps—from Claude Code to Codex without manual copy-pasting or context window management.
Understanding the Handoff Architecture
The Two-Phase Protocol
The handoff system operates through a strict two-phase commit pattern. First, the ending agent creates a handoff record in the handoffs table. Second, the starting agent consumes that record. This design ensures that no context is lost even if hours or days pass between sessions.
In crates/ai-memory-mcp/src/server.rs, the implementation exposes two primary tools: memory_handoff_begin (lines 37–46) for creation and memory_handoff_accept (lines 48–57) for consumption. The server handles all persistence logic, meaning agents only need to invoke these tools without managing state directly.
Data Structure and State Management
The core data structure is defined in crates/ai-memory-core/src/handoff.rs. The NewHandoff struct (lines 58–88) captures:
summary: A high-level description of completed workopen_questions: Pending uncertainties for the next agentnext_steps: Recommended actionsfiles_touched: List of modified filescwd: Current working directory for contextshared: Optional flag for project-wide visibility
The HandoffState enum (lines 20–28) tracks lifecycle states, ensuring each handoff can only be consumed once. Once accepted, the state transitions from Open to Accepted, preventing duplicate work.
Creating a Handoff from Claude Code
The memory_handoff_begin MCP Tool
When Claude Code finishes a session, it calls the memory_handoff_begin tool. This tool records a NewHandoff row via the writer actor and returns a unique handoff ID. The implementation in crates/ai-memory-mcp/src/server.rs (lines 37–46) validates the request context and persists the payload atomically.
The tool automatically captures the operator identity from the request's actor context, setting the owner_user field unless the shared flag is explicitly enabled.
Structuring Handoff Content
Effective handoffs require structured content. The NewHandoff struct enforces this by separating concerns into distinct fields. Rather than dumping raw conversation history, you provide curated context that the next agent can immediately act upon.
# Claude Code creates a handoff before exiting
ai-memory handoff begin \
--workspace default \
--project my-app \
--summary "Implemented JWT authentication flow; all integration tests passing" \
--open-questions "Should we implement refresh token rotation?" \
--next-steps "Add OAuth2 provider support" \
--files-touched src/auth.rs src/middleware.rs tests/auth_test.rs
This command returns a handoff ID (e.g., a1b2c3...) and stores the context in the ai-memory database, ready for the next agent.
Consuming the Handoff in Codex
Automatic SessionStart Hook
When Codex initializes a new session via ai-memory session start, the built-in SessionStart hook automatically invokes memory_handoff_accept. This tool queries for the most recent open handoff using the latest_open_handoff function in crates/ai-memory-store/src/reader.rs (lines 3996–4004).
If a valid handoff exists, the tool marks it as Accepted and prepends its payload to Codex's initial context window. You see this as a formatted block in the agent's console:
📥 ai-memory: pending handoff from previous session
Summary: Implemented JWT authentication flow; all integration tests passing
Open questions:
• Should we implement refresh token rotation?
Next steps:
• Add OAuth2 provider support
Files touched:
• src/auth.rs
• src/middleware.rs
• tests/auth_test.rs
Manual Acceptance for Scripts
For automation or scripting scenarios, you can manually trigger acceptance using the CLI:
# Fetch handoff manually in Codex or scripts
ai-memory handoff accept \
--workspace default \
--project my-app
# Returns JSON payload with full context
Controlling Handoff Visibility with Ownership
User-Scoped vs Shared Handoffs
By default, handoffs are private to the creator. The owner_user field in the NewHandoff struct binds the record to the authenticated operator (extracted from OIDC or bearer tokens). This prevents accidental context leakage in multi-user environments.
To enable team handoffs, set the shared flag to true during creation. This sets owner_user = None in the database, making the handoff visible to any operator with project access. This is ideal for shift handovers or collaborative debugging sessions.
Identity Filtering in Action
The acceptance logic in crates/ai-memory-mcp/src/server.rs builds an owner_filter from the caller's identity. If the handoff has an owner, only that specific operator can claim it. If shared, the first caller wins. This security model is tested in crates/ai-memory-mcp/tests/handoff_admission.rs, which validates proxy-operator isolation and ownership enforcement.
Complete Cross-Agent Workflow Example
The following workflow demonstrates a complete handoff from Claude Code to Codex, including ownership considerations:
Step 1: Claude Code finalizes work
# Claude Code session ending
ai-memory handoff begin \
--workspace production \
--project api-service \
--summary "Refactored database connection pooling; resolved timeout issues" \
--open-questions "Consider adjusting pool size for high-traffic periods?" \
--next-steps "Implement circuit breaker pattern" \
--files-touched src/db/pool.rs src/db/connection.rs \
--shared true # Make available to team
Step 2: Codex starts fresh
# Later, Codex picks up the context
ai-memory session start \
--workspace production \
--project api-service \
--agent codex
# Codex automatically receives the formatted handoff context
Step 3: Verification
If you need to verify the handoff was consumed (preventing duplicate processing):
# Check for remaining open handoffs
ai-memory handoff accept \
--workspace production \
--project api-service
# Returns: {"handoff": null} if already consumed
Summary
- Server-side persistence: ai-memory stores handoffs in a database, not agent memory, enabling durable cross-agent context transfer.
- Two-tool API: Use
memory_handoff_begin(lines 37–46 inserver.rs) to create handoffs andmemory_handoff_accept(lines 48–57) to consume them. - Single-use guarantee: The
HandoffStatemachine ensures each handoff is consumed exactly once, preventing duplicate work. - Ownership controls: Handoffs default to private (
owner_userset) but support project-wide sharing via thesharedflag. - Structured context: The
NewHandoffstruct enforces clean separation of summaries, questions, next steps, and file references for efficient context windows.
Frequently Asked Questions
How does ai-memory prevent the same handoff from being consumed by multiple agents?
The handoff system uses a state machine defined in crates/ai-memory-core/src/handoff.rs (lines 20–28) with two states: Open and Accepted. When memory_handoff_accept successfully processes a handoff, it atomically updates the database row to Accepted status. Subsequent queries for open handoffs filter out accepted records, ensuring only the first caller receives the context.
Can I transfer a handoff between different users or machines?
Yes, but only if the handoff is created with the shared: true flag. By default, handoffs include an owner_user field derived from the creator's authentication context (OIDC or bearer token). Private handoffs can only be accepted by the same identity. Setting shared to true sets owner_user = None, making the handoff claimable by any authenticated user with project access.
What happens if Codex starts without an existing handoff?
If no open handoff exists for the project (or if all handoffs are already accepted), the memory_handoff_accept tool returns handoff: null. Codex then starts with a fresh context window. This behavior is handled gracefully in the SessionStart hook, allowing agents to function normally even without pending handoffs.
Which source files should I examine to understand the handoff implementation?
Key implementation files include:
crates/ai-memory-core/src/handoff.rs: DefinesNewHandoffstruct (lines 58–88) andHandoffStateenum (lines 20–28)crates/ai-memory-mcp/src/server.rs: Implementsmemory_handoff_begin(lines 37–46) andmemory_handoff_accept(lines 48–57)crates/ai-memory-store/src/reader.rs: Containslatest_open_handoffquery logic (lines 3996–4004)crates/ai-memory-mcp/tests/handoff_identity.rs: Demonstrates cross-transport handoffs between HTTP and local transport agents
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →