The problem ai-memory solves is specific, and if you run more than one coding agent you have felt it. Each agent remembers in its own way: Claude Code keeps session notes, Codex keeps its own, Cursor keeps something else again. None of them can read the others’ notes, and none of them travel with you when you switch machines. The usual workaround is a pasted summary in a chat message — lossy, manual, and exactly the kind of thing that gets skipped at 11 p.m. when you are tired.

ai-memory moves the memory one layer down. Instead of each agent owning its notes, a small server you run owns them, and every agent talks to it through lifecycle hooks and MCP tools. Sessions are captured as observations, consolidated into wiki pages at session end, and retrievable by full-text search. When you stop one agent and start another, the handoff — where you left off, what failed, what is still open — is a typed record with an owner, claimed exactly once, instead of a paragraph you retype. The memory itself is ordinary .md files under git, so you can grep it, open it in Obsidian, or edit it by hand; the database is a derived index, not the source of truth.

Two design choices matter for this guide. First, the default path uses zero LLM calls: capture, search, and handoffs work with no API key and no model configured. Second, it ships as one binary with prebuilt releases, so the install is a download, not a build. Both claims are checkable in about ten minutes, which is what the rest of this article does.

What you’ll need

  • Linux, macOS, or Windows. The walkthrough below runs on Linux (x86_64); macOS uses the same two commands, Windows uses the PowerShell equivalent.
  • One supported agent CLI — Claude Code, Codex, Cursor, Gemini CLI, OpenCode, or any of the other twenty-plus harnesses — for the wiring step. The server, search, and handoff verification below needs no agent at all.
  • No API key, no GPU, no Docker. The binary is about 59 MB; the data directory starts under a megabyte.
  • curl and a shell. That is the whole toolchain.

1. Install the binary — checksum verified

The project publishes prebuilt binaries for Linux and macOS on its GitHub releases page. The installer downloads the release for your OS and CPU, checks it against the release’s published SHA-256 checksum — it refuses to install on a mismatch — and links ~/.local/bin/ai-memory. Read the script before you pipe it into a shell; it is short, and its header documents every environment variable it honours.

curl -fsSL https://github.com/akitaonrails/ai-memory/releases/latest/download/install.sh | sh

On the machine used for this guide the installer reported exactly what you want to see:

ai-memory install: downloading ai-memory-linux-x86_64.tar.gz (latest)
ai-memory install: checksum verified
ai-memory install: installed ai-memory 3.4.6 to /tmp/aimem/lib
ai-memory install: linked /tmp/aimem/bin/ai-memory

The paths above are the sandbox locations used for verification; a normal install lands in ~/.local/lib/ai-memory with the link at ~/.local/bin/ai-memory. Confirm the version before going further:

ai-memory --version
# ai-memory 3.4.6

If you would rather not pipe a script from the internet, the same release page offers a Homebrew tap (brew install akitaonrails/tap/ai-memory), Fedora RPMs, Arch AUR packages (ai-memory-bin for the prebuilt binary), and a Docker image. All of them install the same binary; pick the one that matches how you manage software and move on.

2. Preview what setup will wire — before it touches anything

ai-memory setup does three things in one step: it initialises the data directory, starts a per-user service for the server, and wires hooks, MCP, and skills into every agent it finds. Before letting it change anything, preview the plan. --plan prints the plan and changes nothing:

ai-memory setup --plan

On the verification machine, which has session stores for four agent CLIs, the plan came back as:

ai-memory setup will:
  - keep the existing install at /tmp/aimem/data (/tmp/aimem/data/config.toml)
  - service: an ai-memory server already answers at http://127.0.0.1:49374; leaving it in charge
  - wire these agents:
      1. claude-code: MCP + hooks + skills (found its session store at /home/hatch/.claude/projects)
      2. codex: MCP + hooks + skills (found its MCP config at /home/hatch/.codex/config.toml)
      3. open-code: MCP + hooks + skills (found its session store at /home/hatch/.local/share/opencode)
      4. qwen-code: MCP + hooks + skills (found its directory at /home/hatch/.qwen)
  - check /healthz, memory_status and doctor (read-only)

Detection looks for each harness’s session store or MCP config under your home directory, so the list on your machine will reflect the agents you actually have installed. Agents it does not find can be named explicitly with --agent, and the full list runs to more than twenty names, from Cursor and Gemini CLI to Devin, Kimi, Kiro, and OpenClaw. When the plan looks right, run ai-memory setup (or ai-memory setup --yes to skip the confirmation prompt) and restart your agents so the hooks load. The rest of this guide verifies the server and the memory loop first, so you know the machinery works before any agent writes to it.

Two AI agent figures passing a relay baton over a timeline of session cards
The handoff is the product: one agent ends a session, the next claims the baton — where you left off, what failed, what is still open. Illustration generated for this article.

3. Initialise the data directory and start the server

init creates the data directory layout — wiki/, raw/, db/, models/ — writes a default config.toml, and generates a root bearer token in an owner-only file. The server requires that token on every route except /healthz, and the CLI reads it from the data directory automatically.

ai-memory init

The server listens on http://127.0.0.1:49374 by default. Start it over HTTP so the CLI, the MCP endpoint, and the browser UI all share one process:

ai-memory serve --transport http --bind 127.0.0.1:49374

Two things worth knowing here. First, the default serve also starts a filesystem watcher over the wiki directory, and on a constrained Linux box that can fail immediately with Error: OS file watch limit reached — that is what happened on the verification machine, whose inotify limits are small. The documented workaround is the --no-watcher flag, which skips the watcher and is meant for exactly this situation; the server then relies on its API and CLI for writes instead of watching the files. Second, the web UI is off by default: add --enable-web to mount it at /web. With both flags the server came up cleanly:

ai-memory serve --transport http --bind 127.0.0.1:49374 --no-watcher --enable-web
# MCP HTTP server ready (POST /mcp, POST /hook, Ctrl-C to stop)

Confirm it answers before doing anything else:

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:49374/healthz
# 200

And check the runtime state with the CLI, which talks to the running server:

ai-memory status
ai-memory 3.4.6 (server)
ai-memory 3.4.6 (client)
  server:       http://127.0.0.1:49374
  data-dir:     /tmp/aimem/data
  db:           /tmp/aimem/data/db/memory.sqlite
  bind:         127.0.0.1:49374
  auth:         bearer 
  pages:        0 (all versions: 0)
  sessions:     0
  observations: 0
  fts:          pages 0/0; observations 0/0
  providers:
    llm:       disabled
    embedding: disabled

Note the last two lines: both providers disabled, on a fresh install with no keys configured. That is the zero-LLM default, stated by the server itself. status also prints the data directory path; the bearer token lives in <data-dir>/auth-token if you ever need it for a raw API call. (If you run status before starting the server, it says so plainly — could not reach http://127.0.0.1:49374/admin/status — and exits non-zero.)

4. Write, search, and read a memory page

Memory in ai-memory is wiki pages: markdown files with a path, a kind (fact, rule, decision, or gotcha), and tags. In normal use the hooks write these pages for you at session end; the write-page command lets you write one by hand, which is also the fastest way to prove the loop works. The project is derived from the working directory, so run these commands from the project you want the memory attached to:

ai-memory write-page --path "demo-project/decisions/database-choice.md" --body "# Database choice

We picked SQLite for the demo project because the data set is under 100 MB and a single file keeps backups trivial. Revisit if write throughput exceeds 500 rows per second." --kind decision --tag demo
# ✓ wrote demo-project/decisions/database-choice.md (page_id=849616d5) under default/aimem

The page is written atomically and indexed in the store in the same step. Search is full-text over an FTS5 index:

ai-memory search "SQLite demo project"
1 result(s) for "SQLite demo project":
  demo-project/decisions/database-choice.md  rank=-0.0000
    Database choice
    # Database choice

We picked <mark>SQLite</mark> for the <mark>demo</mark> <mark>project</mark> because the data set is under 100 MB and a single file keeps backups trivial…

Read the page back in full with read-page, and list what changed most recently with recent:

ai-memory read-page --path "demo-project/decisions/database-choice.md"
ai-memory recent
path: demo-project/decisions/database-choice.md

# Database choice

We picked SQLite for the demo project because the data set is under 100 MB and a single file keeps backups trivial. Revisit if write throughput exceeds 500 rows per second.

What you just verified is the whole storage contract: a page written through the CLI lands as a markdown file in wiki/, is indexed for search immediately, and reads back byte-identical. Because the wiki is the source of truth, you can also open that file in any editor, and ai-memory reindex can rebuild the SQLite index from the files if the database is ever lost. That is the property that separates this from memory tools whose store is a black box.

5. Pass the baton: a real cross-agent handoff

Handoffs are the feature the project is named for, in spirit if not in letters. In everyday use you never create one by hand: the session-end hook writes it, and the next session’s start hook fetches it. The typed protocol is what makes it more than a summary — each handoff has an owner, is claimed exactly once, and creating a new automatic handoff expires the prior open ones, so a stale baton cannot be picked up twice.

Under the hood the handoff tools are MCP tools on the server: memory_handoff_begin, memory_handoff_list, memory_handoff_accept, and memory_handoff_cancel. An agent calls them; you can also call them directly over the MCP HTTP endpoint to see the machinery. With the server running, initialise an MCP session and begin a handoff:

TOKEN=$(cat <data-dir>/auth-token)
curl -s -X POST http://127.0.0.1:49374/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"memory_handoff_begin","arguments":{"summary":"Switched from Claude Code to Codex mid-task: SQLite decision page written, search verified, next step is wiring the hooks into the real agent CLIs.","handoff_type":"manual"}}}'
{
  "handoff_id": "01a1dda3-ad9e-73d1-b4a8-a20b22183bac"
}

List it, and it is there with state open. Accept it with that id, and the state flips to accepted with status: "claimed"; a second list comes back empty, because a claimed handoff is spent:

{
  "handoff": {
    "id": "01a1dda3-ad9e-73d1-b4a8-a20b22183bac",
    "from_agent": "other",
    "summary": "Switched from Claude Code to Codex mid-task: SQLite decision page written, search verified, next step is wiring the hooks into the real agent CLIs.",
    "state": "accepted",
    "accepted_by": "other",
    "accepted_at": "2026-11-15T05:17:47.407513Z"
  },
  "status": "claimed"
}

One scoping detail surfaced during verification and is worth knowing before you rely on handoffs. A bare MCP call that passes no working directory creates the handoff under a different project scope than the CLI’s, which derives the project from the current directory — the CLI’s handoffs list then correctly reports nothing for its own project. Session-aware clients avoid this by omitting workspace, project, and cwd and letting the hook route the call; static MCP clients should pass cwd explicitly. In the normal flow — hooks installed, agents launched from the project directory — this never comes up, because the hook carries the context. It only bites when you call the API by hand, which is exactly how this guide verified it.

The CLI side of the same check is one command, and its empty state is the correct answer before any session has ended:

ai-memory handoffs
# No open handoffs for default/aimem.
A tidy archive of folders and index cards with a magnifying glass and a small glowing server box
The memory is plain markdown in a git-backed wiki: grep it, open it in Obsidian, edit it by hand. The database is a derived index, rebuildable from the files. Illustration generated for this article.

6. Wire your agent and switch agents for real

With the server verified, the last step is the one that makes memory automatic: register the MCP server with your agent, then let setup install the hooks. For Claude Code the registration snippet is one command, printed by the tool itself:

ai-memory install-mcp --client claude-code
# Claude Code — register the MCP server
#
# Recommended (one-shot CLI):
claude mcp add --transport http ai-memory http://127.0.0.1:49374/mcp

Claude Code and Codex users can also wire ai-memory as a marketplace plugin instead (claude plugin marketplace add akitaonrails/ai-memory, then install ai-memory@ai-memory); the binary install from step 1 is still required either way. After either route, run ai-memory setup from step 2 to install the lifecycle hooks, restart the agent, and ask it “What do you remember about this project?” — it should answer through ai-memory.

The switch itself is the payoff. The documented flow is ai-memory run, which launches an agent inside a managed workstream: quit Claude Code, run ai-memory run codex, and Codex starts with the shared workstream plus a private projection of Claude’s visible history for the details the handoff packet omitted. The remote server receives only the harness and session identity, never the local transcript path or body. Direct harness launches keep working exactly as before; run is the opt-in wrapper for the handoff path.

When to use this vs the alternatives

Agent memory is a crowded corner of the ecosystem, and this blog has covered most of it. The choice turns on one question: how many agents do you actually run?

  • One agent, and it is Claude Code: claude-mem. It is Claude-only by design, its hooks and retrieval are tuned for that one harness, and if you never leave Claude Code it is the simpler install. The trade-off is the hosted observer trial and the single-agent scope. See our hands-on with claude-mem.
  • You build applications, not just use agents: mem0. mem0 is a memory layer you call from code, with an API and hosted options. It is the right shape when your product needs memory; it is the wrong shape when you want your own agents to remember across tools without writing integration code.
  • You want local inference in the loop: Hindsight. Hindsight pairs memory with a local LLM for recall. If you already run Ollama and want the model doing the remembering, that is its lane. ai-memory deliberately does the opposite by default — no model at all until you opt in.
  • You want git-native project memory without a server: OKF Agent Memory. OKF keeps memory as files in the repo and needs no running process. Choose it when a server — even a localhost one — is more moving parts than you want. Choose ai-memory when the memory has to follow you across machines, agents, and teammates, which is what the server buys you.
  • Several agents, several machines, or a team: ai-memory. Cross-agent handoffs, cross-machine sync through one server, per-project sharing with personal handoffs kept personal, and a plain-markdown store you can read without the tool. That combination is the gap it fills, and it is why the star count moved.

Honest limitations

  • The handoff is only as good as the session that wrote it. Capture records what happened; it cannot invent context the agent never saw. A session that wandered without decisions produces a thin handoff. The tool rewards working in the open — deciding out loud, naming the failure — and quietly punishes the opposite.
  • Setup writes into your agent configs. That is the point of the tool, but it is also a change to files you may have hand-tuned. Run setup --plan first, read the list, and keep a backup of your agent settings if you have custom hooks. ai-memory uninstall removes the wiring, dry-run unless you pass --apply.
  • Memory ages, and aging is a policy you have to think about. The default keeps everything; decay, compaction, and deduplication are off until you turn them on, and the opt-in “dream” pass that rewrites cold notes needs an LLM configured. Nothing is hard-deleted — originals stay in git — but a wiki left on defaults grows without bound.
  • The watcher needs inotify headroom. On constrained Linux systems the default server can fail at startup with an “OS file watch limit reached” error. --no-watcher is the documented fix, and it worked here, but it means file edits outside the API are not picked up live.
  • It moves fast. v3.4.6 is two days old as this guide publishes, the CLI surface is large, and flags change between releases. Verify install commands against the repo before running them, and pin the version you tested if you are wiring a team onto it.

The takeaway

The re-explanation tax is the most expensive line item in agent-assisted work, and it is paid every time you switch tools. ai-memory attacks it at the right layer: not another agent, and not a feature inside one agent, but a small server underneath all of them, holding plain markdown that any agent can read and any human can grep. The install is a verified binary, the default path needs no key and no model, and the handoff — begin, list, accept, spent — works exactly as documented, which is more than can be said for most tools in this category. Install it on a Friday, wire one agent, and Monday’s first prompt in a different agent is already shorter.