Skip to main content
Glama
agent-handoff-memory

agent-handoff-memory

by JusticeUA

agent-handoff-memory

ci

An MCP server that gives several agents one shared, versioned memory - and an explicit handoff packet, so the next session starts where the last one stopped instead of re-deriving it.

Agents lose their context at the session boundary. The usual patch is to dump a transcript into the prompt and hope the next run picks the right sentence out of it. A handoff packet is the opposite: a short, structured object that says what was done, what is next, what is still unclear, and which exact record versions to start from - and the receiving agent gets those versions resolved in the same call, with a warning about any that have moved on since.

git clone https://github.com/JusticeUA/agent-handoff-memory.git
cd agent-handoff-memory && npm install
npm run demo

That runs two agents in two processes against one SQLite file. No API keys, no services, no native build step - node:sqlite is part of the runtime.

What the demo shows

A scout agent crawls a (fixture) job board, writes what it found, corrects one of its own assessments, and hands over. A separate executor process then picks the work up knowing nothing else:

--- 1. pick up whatever is waiting --------------------------------
  . packet h_1f4089bf from scout-agent: Two listings worth an application, one source caveat
  . next: Draft an application for listing/482 (supplier catalogue scrape, $900)
  . next: Draft an application for listing/553 (price monitor, $600)
  . open: Is the 60s backoff enough, or does the board keep a longer penalty window?
  . 4 pinned record versions arrived with the packet
  . stale: listing/553/assessment was pinned at v1, now at v2

--- 3. re-read anything the warning touched -----------------------
  . listing/553 v2 now says "maybe" (budget edited down to $400 and 17 more applicants arrived)
  . dropping listing/553 - acting on the pinned v1 would be wrong

--- 5. report what actually happened ------------------------------
  . success on listing/482/assessment: confidence 80% -> 84%
  . failure on source/boards-example/rate-limit: confidence 60% -> 39%

The scout edited listing/553 after writing the packet. The executor is told its pinned version is stale rather than being handed the new one behind its back, re-reads, and drops the listing. Then it reports what actually happened, and the confidence of the facts behind the decision moves accordingly.

Full output of both sessions: docs/demo-transcript.md.

To watch it as two terminals instead of one script:

# terminal 1
MEMORY_DB=shared.db node dist/demo/scout.js
# terminal 2
MEMORY_DB=shared.db node dist/demo/executor.js

Related MCP server: junto-memory

Tools

Tool

What it does

remember

Store a fact under scope + key. An existing key gets a new version; nothing is overwritten.

recall

Read the current version of a key, or search by scope prefix, tag, free text, minimum confidence.

history

Every version of a key: value, author, confidence, and the hash chain tying the versions together.

handoff

Write a packet: summary, next steps, open questions, and pinned record versions. With no refs given, everything the session touched is pinned.

resume

Claim the oldest open packet for this agent and get it back with the pinned records resolved and stale ones flagged.

record_outcome

Report success or failure against the records that drove a decision; their confidence moves and the before/after is kept.

memory_stats

Counts, average confidence, handoff states, and an optional integrity check of the whole hash chain.

Use it from an MCP client

{
  "mcpServers": {
    "handoff-memory": {
      "command": "node",
      "args": ["/absolute/path/to/agent-handoff-memory/dist/src/server.js"],
      "env": {
        "MEMORY_DB": "/absolute/path/to/shared-memory.db",
        "AGENT_ID": "researcher"
      }
    }
  }
}

Point several clients at the same MEMORY_DB with different AGENT_IDs and they share one memory. The store runs in WAL mode precisely so that works.

For Claude Code:

claude mcp add handoff-memory -e MEMORY_DB=$PWD/shared.db -e AGENT_ID=researcher \
  -- node $PWD/dist/src/server.js

Design decisions

Values are immutable, opinions are not. Writing an existing scope+key appends version N+1 and stamps the old one superseded. Confidence and outcome counts do move on the current version - they are opinions about a fact, not the fact - and every move is written to an outcomes table with before/after values. So history stays a history of what was believed, not a log of vote changes.

Every version is hashed and chained. Each row carries sha256 of its body plus the hash of the previous version. memory_stats { verify: true } recomputes the lot; a value edited straight in the database file shows up as corrupted. One of the tests does exactly that edit and asserts it is caught.

Stale refs are reported, never silently swapped. A packet pins versions. If the ground moved, the receiving agent is told - it can re-read deliberately. The alternative (quietly serving the newest version) makes an agent act on data its plan was never built on.

Confidence follows outcomes, and stays inside 0..1. Success closes part of the gap to 1, failure scales down, so repeated evidence approaches the edges without pinning there. The multipliers live in one table in src/models.ts.

No network, no daemon, no native modules. Storage is node:sqlite, transport is stdio. The whole thing is a node process and a file.

SenseLab AMFS

The project also runs on SenseLab's AMFS TypeScript SDK. src/amfs/sqlite-adapter.ts implements SenseLab's AmfsAdapter contract on SQLite - their AgentMemory does the reasoning, this does the remembering - and demo/amfs-bridge.ts re-tells the handoff walkthrough through their API:

npm run demo:amfs

The SDK ships an in-memory adapter (gone when the process exits) and an HTTP adapter (needs a hosted endpoint and a key); this fills the gap between them, and along the way populates contentHash / integrityChain and answers commitLog(), which the in-memory adapter leaves empty. A parity test runs the same session through both adapters and compares the results.

What I measured while building it - including why commitOutcome(SUCCESS) lowers confidence in 0.3.2 - is written up in docs/senselab-amfs.md.

Tests

npm test

29 tests over the store, the handoff lifecycle, the MCP surface (a real client and server joined by an in-memory transport, so the tool schemas are exercised too), and the AMFS adapter. The AMFS group skips itself when the optional SDK is not installed.

Layout

src/models.ts              types and the outcome table
src/store.ts               versioned SQLite store: memory, handoffs, outcomes
src/server.ts              the MCP server and its seven tools
src/amfs/types.ts          structural mirror of the AMFS SDK shapes
src/amfs/sqlite-adapter.ts durable adapter for SenseLab's AMFS SDK
demo/scout.ts              session 1: crawl, write, correct, hand over
demo/executor.ts           session 2: resume, act, report outcomes, hand back
demo/amfs-bridge.ts        the same story through @senselab-ai/amfs

Requirements

Node 24 or newer, where node:sqlite is stable and needs no flag; developed and tested on 25.9. On Node 22.5-23.x the same code runs with --experimental-sqlite. npm install builds the project (via prepare), so dist/ is ready afterwards.

The optional @senselab-ai/amfs dependency is published by SenseLab under BSL-1.1; this repo's own code is MIT.

License

MIT - see LICENSE.

Available Tools

7 tools
handoffHand work to the next agentA

Write a handoff packet: what was done, what is left, what is still unclear, and which exact record versions the next agent must read. With no refs given, everything this session touched is pinned.

Inputs: title (required), summary (required), refs, to_agent, +2 more.

historyVersion historyB
Read-only

Every version of one key, oldest first: who wrote it, when, with what confidence, and the hash chain that ties the versions together.

Inputs: key (required), scope (required).

memory_statsMemory statisticsA
Read-only

Counts per agent and scope, average confidence, handoff states, and an integrity check of the hash chain.

Inputs: verify.

recallRecall factsA
Read-only

Read the current version of a key (scope+key), or search current records by scope prefix, tag, free text and minimum confidence.

Inputs: key, tag, limit, query, +2 more.

record_outcomeReport what actually happenedB

Close the loop: report success or failure against the records that drove the decision. Their confidence moves accordingly, and the before/after values are kept as an audit trail. Pass handoff_id to close the packet in the same call.

Inputs: outcome (required), outcome_ref (required), note, refs, +1 more.

rememberRemember a factA

Store a fact under scope+key. Writing an existing key appends a new version instead of overwriting, so nothing is ever silently lost.

Inputs: key (required), scope (required), tags, value, +1 more.

resumePick up a handoffA

Claim the oldest open packet addressed to this agent (or a specific one by id) and get back the packet together with the pinned records. Refs whose version has moved on are reported as stale rather than silently swapped for the newer version.

Inputs: handoff_id.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 7 tools

    Disambiguation5/5

    Each tool targets a distinct action: storing, reading, versioning, handoff creation, handoff retrieval, outcome recording, and statistics. No two tools overlap in purpose, making misselection unlikely.

    Naming Consistency5/5

    All tool names use lowercase snake_case with a verb-first or clear noun pattern (remember, recall, history, handoff, resume, record_outcome, memory_stats). The style is uniform and predictable.

    Tool Count5/5

    Seven tools is well-scoped for a memory and handoff system. Each tool fills a necessary role without redundancy or excessive granularity.

    Completeness5/5

    The set covers the full lifecycle: writing memories, reading (current and historical), creating handoff packets, claiming and resuming them, recording outcomes, and monitoring integrity. There are no obvious gaps for the stated purpose.

    Related MCP Connectors

    Related MCP Servers