MemNexus is in gated preview — invite only. Learn more
Back to Blog
·13 min read

Wiring Shared Memory Into a Multi-Agent Claude Code Team

A hands-on tutorial for wiring MemNexus into a Claude Code lead agent and its subagents — named state memories, codeContext tagging, conversation grouping, and the concurrent-write gotcha nobody tells you about.

MemNexus Team

Engineering

TutorialClaude CodeMulti-AgentAI AgentsMCPDeveloper Workflow

July 2026

Claude Code can run more than one agent on your codebase at once. A lead agent plans the work and spawns subagents — an implementation engineer, a QA verifier, a security reviewer — each running in its own context window, each capable of reading and writing files independently.

Wire MemNexus into all of them and something changes: every subagent reads the same project state before it starts, and writes back to it when it's done. This tutorial builds that setup end to end — one lead agent, two subagents, one shared memory store — using real mx CLI commands you can run today.

What You'll Build

A small feature team of Claude Code agents working on a per-IP rate limiter:

  • Lead agent — plans the work, tracks status, resolves blockers
  • impl-engineer subagent — implements the middleware
  • qa-verifier subagent — tests it under load and reports back

All three read from and write to the same MemNexus memory store. The lead agent doesn't manually relay findings between subagents — each subagent posts what it learned, and the next one reads it before starting.

By the end, you'll have:

  • A named memory holding live team state, readable by name from any subagent
  • A shared conversation thread showing the full history of what each subagent did
  • codeContext tags that label which team and which subagent produced each memory
  • A concrete answer to "what happens if two subagents write at the same time" — because the honest answer matters more than the happy path

Prerequisites

  • Claude Code installed
  • A MemNexus account (get started free)
  • Node.js 18+
  • Basic familiarity with Claude Code subagents (.claude/agents/*.md files) — if you haven't used them yet, this tutorial still works with a single Claude Code session opening multiple terminal tabs instead

Step 1: Connect MemNexus to Claude Code

Install the CLI and authenticate:

npm install -g @memnexus-ai/cli

# Interactive prompt — key stays out of shell history
mx auth login

Add MemNexus as an MCP server in your project's .mcp.json so every agent — lead and subagents alike — gets the same tool access:

{
  "mcpServers": {
    "memnexus": {
      "type": "stdio",
      "command": "npx",
      "args": ["@memnexus-ai/mcp-server"],
      "env": {
        "MEMNEXUS_API_KEY": "cmk_live_xxx.yyy"
      }
    }
  }
}

If you commit .mcp.json, don't commit a live key in it — add it to .gitignore or use a placeholder your team fills in locally; each teammate should use their own scoped key.

Because this lives in .mcp.json at the project root, it's shareable and version-controlled — every subagent that spawns inside this project inherits the same MemNexus connection automatically. There's nothing extra to configure per-subagent.

Step 2: Define the Subagents That Will Share This Memory

Claude Code subagents are markdown files under .claude/agents/. Each one gets its own name, a description that tells the lead agent when to spawn it, a tools allowlist, and a system prompt. Here's a minimal impl-engineer:

---
name: impl-engineer
description: Implements features from a spec. Use proactively when a task is ready to build.
tools: Read, Write, Edit, Grep, Bash, mcp__memnexus
---

You implement features assigned by the lead agent. Before starting any task,
call MemNexus build_context with a description of the task to load relevant
history. When you finish, save what you did as a memory in the shared
conversation so the QA subagent can pick it up.

And qa-verifier:

---
name: qa-verifier
description: Tests implemented features and reports pass/fail with detail. Use proactively after implementation work completes.
tools: Read, Bash, Grep, mcp__memnexus
---

You verify work the impl-engineer subagent has completed. Before testing,
search MemNexus for what was implemented and why. Save your findings —
pass or fail — as a memory in the shared conversation.

Neither file specifies a memory ID, a JSON payload, or CLI flags — just tool names and behavioral intent.

There's a real footgun in that tools: line, though. Listing any tools at all switches a subagent from "inherits everything" to an explicit allowlist — and MCP tools are dropped from that allowlist unless you add them back. Omit tools: entirely and a subagent inherits every tool, MemNexus included. Add a tools: line without mcp__memnexus (or the individual mcp__memnexus__build_context, mcp__memnexus__create_memory entries) and you've silently cut the subagent off from memory — it still runs, it just can't see anything the rest of the team knows, and nothing will tell you why.

This matters more here than it would elsewhere: subagents start with a fresh context window and zero conversation history by design. They don't inherit anything the lead agent said. build_context isn't a nice-to-have that saves a subagent a few minutes — for a subagent, it's the only way in.

Step 3: Create the Team's Shared State Memory

The lead agent creates one named memory to hold live team status — assigned task, current blocker, what's next. A named memory gives you a stable key (rate-limit-team-state) instead of a UUID you'd have to search for every time.

mx memories create \
  --conversation-id "NEW" \
  --content "Rate-limit team state — 2026-07-08.
Task: add per-IP rate limiting to the public API.
Assigned: impl-engineer (implementation), qa-verifier (load testing).
Status: impl-engineer starting now. No blockers.
Conversation: conv_a1b2c3" \
  --name "rate-limit-team-state" \
  --topics "rate-limiting,team-state" \
  --team "rate-limit-team" \
  --code-role "lead"

The output includes a conversationId (something like conv_a1b2c3) — that's what goes in the Conversation: line above. You won't know it before the command returns, so fill it in from the response (or run a quick mx memories update --name right after to add it). Embedding it directly in the content, not just leaving it in response metadata, means anyone who reads this memory's plain text later — human or subagent — has the ID without digging further.

Any subagent can now retrieve current state by name, without knowing an ID in advance:

mx memories get --name "rate-limit-team-state"

Step 4: Have Subagents Read Before They Write

Before impl-engineer writes a line of code, it should load context — not just the team state memory, but anything relevant from past sessions. build_context does this in one call:

mx memories build-context --context "per-IP rate limiting implementation"

This returns active work, key facts, and any gotchas that have shown up across multiple past memories on this topic — useful if a previous attempt at rate limiting already hit a snag worth knowing about. See how build_context works for the full mechanics.

qa-verifier does the same before it starts testing, searching for what was actually built rather than assuming:

mx memories search --query "rate limiting implementation" --recent 24h --brief

build_context's Active Work section returns this conversation's ID inline (conversation conv_a1b2c3) — that's where a subagent gets the ID to post into in Step 5, without you passing it manually.

Step 5: Group the Work Into One Conversation

Instead of each subagent writing to the shared state memory directly, have them post into the shared conversation from Step 3. This keeps a full, ordered history of what happened — and, as you'll see in the next section, it sidesteps a real limitation with concurrent writes to named memories.

# impl-engineer posts progress
mx memories create \
  --conversation-id "conv_a1b2c3" \
  --content "[impl-engineer] Implemented per-IP token bucket in the rate-limit middleware. Default: 100 req/min, configurable via env var. Unit tests pass." \
  --topics "rate-limiting,in-progress" \
  --team "rate-limit-team" \
  --code-role "impl-engineer"

# qa-verifier posts findings into the same conversation
mx memories create \
  --conversation-id "conv_a1b2c3" \
  --content "[qa-verifier] Load tested at 500 concurrent connections. Found an off-by-one: the first window allows 101 requests instead of 100. Blocking — needs a fix before merge." \
  --topics "rate-limiting,blocked" \
  --team "rate-limit-team" \
  --code-role "qa-verifier"

Both entries live in conv_a1b2c3. Anyone — the lead agent, a human, a subagent joining later — can reconstruct the full timeline:

mx conversations timeline conv_a1b2c3

Or get a synthesized status in one call:

mx memories digest --query "rate limiting team status" --topics "rate-limiting" --digest-format status-report

The lead agent is the only one that then updates the single state memory, folding the outbox into a fresh summary:

mx memories update --name "rate-limit-team-state" \
  --content "Rate-limit team state — 2026-07-08, updated 14:20.
impl-engineer: token bucket implemented, unit tests pass.
qa-verifier: BLOCKED — off-by-one allows 101 req in first window.
Next: impl-engineer fixes off-by-one, qa-verifier re-tests."

Step 6: Tag Memories With codeContext So Teams Stay Legible

Every memory this team creates already carries a --team tag in the commands above (--team "rate-limit-team" --code-role "impl-engineer"). That's shorthand for the fuller --code-context flag, which also accepts product, service, and role as a structured JSON object.

The tag round-trips on the memory record — fetch any memory back and the codeContext you set is right there:

mx memories get --name "rate-limit-team-state" --format json
# "codeContext": { "team": "rate-limit-team", "role": "lead" }

That matters once more than one agent team is active in the same account — a checkout-flow team, a rate-limiting team, whatever else you're running. Six months from now, a human or an agent reading a memory can tell at a glance which team and which subagent produced it, instead of guessing from prose alone. Tag consistently from the first memory each team creates — it's cheap, it's honest metadata, and it's the foundation for legible organization as your memory store grows.

The Gotcha: Concurrent Writes Can Clobber Each Other

Here's the part most tutorials skip, because it only shows up once you actually run agents in parallel.

A named memory has exactly one current version at a time. When you call mx memories update --name, MemNexus creates a new version, points the name at it, and marks the old version superseded — the full version history is preserved and retrievable with mx memories history <name>. But the update itself is a full-content replacement, not a merge, and there's no compare-and-swap: nothing checks that the version you're updating is still the current one before your write lands.

That matters the moment two writers act on the same named memory close together. Say both impl-engineer and qa-verifier fetch rate-limit-team-state at v3, each build an updated version in their own head, and both call mx memories update --name a few seconds apart. Whoever writes second overwrites the first — not by merging the two updates, but by replacing the content outright. The first writer's update isn't in the new version at all. It's still retrievable via mx memories history, but it's no longer part of what anyone reading the named memory sees.

This isn't a bug to route around quietly — it's a real constraint of full-document named-memory updates, and it's worth designing for explicitly.

This is a last-write-wins conflict on content, not a data-integrity bug — the version chain itself can't fork or duplicate (each update is a locked, atomic append), so nothing is corrupted; the losing write is just no longer what get --name returns by default.

Two Safe Patterns for Concurrent Writes

Fetch fresh, immediately before you write. If a subagent must update the shared named memory directly, it should re-fetch the current version right before writing, not rely on a version it loaded minutes ago:

# Re-read immediately before writing — don't reuse a stale copy
CURRENT=$(mx memories get --name "rate-limit-team-state" --format json)
# ...merge your update into $CURRENT's content...
mx memories update --name "rate-limit-team-state" --content "<merged content>"

This narrows the collision window but doesn't eliminate it — two subagents can still both fetch fresh within the same second.

Make the shared state memory single-writer. This is the convention used in Step 5, and it's the one worth defaulting to: subagents never call update --name on shared state directly. They only create into the shared conversation — an append-only operation with no overwrite risk, since every call produces a new memory rather than replacing one. The lead agent is the sole writer of the named state memory, synthesizing the conversation's outbox on its own schedule. One writer, no race.

What This Doesn't Fix

Being direct about the edges of this pattern:

  • No push notifications. A subagent doesn't get pinged the moment a teammate posts new information. It has to search or call build_context between steps. If your workflow needs instant handoff mid-task, you still need Claude Code's own orchestration — the lead agent deciding when to re-invoke a subagent — not MemNexus.
  • No execution ordering. MemNexus stores what happened; it doesn't sequence which subagent runs when. That's the lead agent's job, same as it would be without shared memory.
  • No automatic conflict resolution. The single-writer convention above avoids the clobber problem by design, not because MemNexus merges concurrent edits for you. If you skip the convention and let every subagent update the same named memory directly, you own the collision risk.
  • No server-side scope-filtered search. Tagging with --team or --code-context gives you legible provenance on each memory, not a query-time filter that automatically restricts results to one team. If you want that today, filter on the codeContext field in your own tooling after retrieval.

Complete Workflow Recap

  1. Add MemNexus to .mcp.json — every subagent inherits the connection, as long as any tools: allowlist includes mcp__memnexus
  2. Lead agent creates one named memory (--name) for shared team state, tagged with --team, with the conversation ID embedded in its content
  3. Subagents call build_context / search_memories before starting any task — it's their only way to see what happened before they existed
  4. Subagents create progress and findings into the shared conversation ID — never into the named state memory directly
  5. Lead agent alone updates the named state memory, synthesizing from the conversation
  6. Every memory gets a --team (or full --code-context) tag, so provenance stays legible as more teams share the account

Get Started

Install the CLI, connect it to Claude Code, and create your first shared team memory in a few minutes:

npm install -g @memnexus-ai/cli
mx auth login
mx memories create --conversation-id "NEW" --content "Starting: [your project]" --name "your-team-state"

Give your Claude Code agent team a memory that persists

Set up MemNexus in about two minutes — free during the gated preview.

Get Started Free

Full CLI reference is at docs.memnexus.ai/reference/cli, and the team-workflow patterns this tutorial builds on are documented at docs.memnexus.ai/guides/workflows/team-workflows.

Give your coding agents memory that persists

MemNexus works across Claude Code, Codex, Copilot, and Cursor — your agents get smarter every session.

Get Started Free

Get updates on AI memory and developer tools. No spam.