A task-oriented cheat sheet: "I want to do X" → how. For the full reference see
ARCHITECTURE.md; for install see install.md
(including the macOS menu bar app);
for the tool-routing table see usage.md.
ai-memory gives your AI coding agents long-term, cross-session memory. It runs
as one server; your agent talks to it over MCP (tools like memory_query,
memory_write_page) and over lifecycle hooks that automatically capture what you
do. Memory is a markdown wiki in git (the source of truth, hand-editable) plus
a derived SQLite index for search. Everything is scoped per project
(workspace, project), resolved from markers/home routes or, by default, the
normalized repository path (upstream, then origin; folder basename only
without a valid remote). It works with no LLM at all (capture + full-text search + rule-based summaries); adding a provider
enables consolidation and auto-improvement.
Call the existing MCP tools to save pages, query knowledge and pass a handoff between executions. Native hooks are optional. The programmatic memory guide includes complete HTTP requests, scope rules and machine authentication. If your tool also hosts a harness, follow the external lifecycle contract.
You mostly just talk to your agent; it calls the right tool. Common ones:
| You want | Say to your agent | Tool it uses |
|---|---|---|
| Recall prior work | "Have we discussed X?" / "what did we decide about Y?" | memory_query |
| Catch up after time away | "Where did we leave off?" / "catch me up" | handoff block / memory_explore |
| Remember a durable fact | "Remember that we always use pnpm here" | memory_write_page |
| Remember until a date | "Remember this until the migration ships" | memory_write_page + expires_at |
| A standing rule for every project | "Always: never force-push" | memory_write_page with scope: "global" |
| Read a specific saved page in full | "Read the _rules/deploy page" |
memory_read_page |
| Save context for the next session | "Wrap up — save context for next time" | memory_handoff_begin |
| See project stats | "How much memory do we have?" | memory_status / memory_briefing |
You rarely write pages by hand: lifecycle hooks capture prompts and tool calls automatically, and (with an LLM) consolidation compiles them into pages.
"Remember: before touching the payment code, read the PCI notes."
Your agent calls memory_write_page and it lands as a durable wiki page (routed
under _rules/ when it's a rule). Next session, memory_query surfaces it, and
if the project's .ai-memory.toml opts into the on-start brief, rules are
prepended to the agent's context automatically: an excerpt of every rule first,
whole bodies while the budget lasts, and memory_read_page for the rest. Pin
the rule to have it shown in full before the others. To make it apply to all your
projects, ask for it as a standing preference. It goes to your cross-project
profile (see the next recipe), or to the shared _global scope with
scope: "global". On a multi-user
server, writing a global rule needs root or a write grant on _global. From
another project's page, link to that standing page with [[_global:path]], which
always names the reserved _global project in the default workspace. Sibling
projects use [[project:path]]; another workspace uses
[[workspace/project:path]]. Bare [[name]] stays inside the current project.
"Remember this deploy gotcha; it is about
bin/deploy.sh."
Your agent can pass source_files to memory_write_page: the repository
files the page describes, each with the commit it was checked against
([{"path": "bin/deploy.sh", "commit": "3f2a9c1"}], up to 16). The server
stores the list in the page's frontmatter and never opens the files, so it
works the same against a remote or containerized server. To check a page, read
it, then run this from the checkout for each entry:
git --literal-pathspecs diff --quiet 3f2a9c1 -- bin/deploy.shA non-zero exit, or a path that no longer exists, means the file changed:
record memory_feedback with signal: "stale" and a reason such as
source-changed: bin/deploy.sh since 3f2a9c1. The page drops in rank and shows
up as a feedback_flagged finding in memory_lint. Rewriting the page with
the new commit clears the flag.
"In all my projects: use pnpm, keep integration tests in tests/suite."
Your agent writes each one into the cross-project profile
(memory_write_page with scope: "profile"). From then on every project, in
every harness, gets a short "your usual choices" section at session start, and
the agent applies those choices whenever the repository's rules file and you
say nothing. A brand-new repository gets the whole baseline, plus a pointer to
ai-memory profile apply for writing it into that repository's rules file.
- You don't have to ask: habits you state in your prompts ("always…", "prefer
X over Y", "from now on…") are learned on their own once you say them as a
general rule or in two projects.
ai-memory profile reviewshows what was learned, from which words, and what is still one project short. - See what it holds:
ai-memory profile list; drop one:ai-memory profile forget tools/pnpm.md(it stays dropped until you say it again). - Keep a client project out of it:
[profile] contribute = falsein that repository's.ai-memory.toml; keep the digest out of one:consume = false. - Scope an entry to a stack with
applies_to: ["rust"]onmemory_write_page(--applies-to rustonwrite-page), or mark itenforced_byto keep it out of the digest. - On by default for a single user (one profile across every workspace). On a
shared server it is off until the operator sets
[profile] enabled = true, and then each person gets a private profile.
Details: cross-project-profile.md.
Two ways, depending on where the document lives:
- It's already a wiki page (you saved it, or imported it as described below): tell the
agent "read the
norms/gdpr-retentionpage before implementing" and it callsmemory_read_pagewith that path and works from the full body. - It's an external file (a norm/spec on disk): save it as a page first
("remember this spec as
norms/gdpr-retention", paste or point at it), then reference it as in (1). Large references are best split into a page per document so retrieval can pull just the relevant one.
ai-memory's wiki is OKF (Obsidian-compatible markdown + frontmatter). To bring an existing body of documents in as project memory:
- A few documents: save each as a durable page via your agent
(
memory_write_page) or the CLI (ai-memory write-page), one page per document, under a stable prefix likenorms/…. Then any project can read a specific one before implementing (recipe above). - A whole OKF/Obsidian vault or an export from another tool: use the
companion importer (see
companion-crates.md). It ingests OMC and external-conversation exports into the store.ai-memory export-okfis the inverse (export your wiki as an OKF bundle), useful to see the exact on-disk shape your documents should take. - The wiki lives at
<data_dir>/wiki/<workspace>/<project>/…and is plain markdown in git, so you can also drop files in and let the file watcher + reindex pick them up. Keep them under a clear prefix and commit.
Once the material is saved as pages in the right scope, any project can search
it (memory_query) and read a specific document in full (memory_read_page)
before implementing against it.
ai-memory bootstrap seeds a project from its git log, README and docs. Run it
from several shells (or a loop with &) to seed many repositories; the server
decides how many call the LLM at a time with bootstrap_max_concurrent
(default 1). Runs for the same project always wait for each other, and chunks
within one run stay sequential, so the largest repository sets the floor.
- Local GPU (vLLM, llama.cpp server): the server batches concurrent
requests, so a single run leaves it mostly idle. Raise the limit until the
engine starts queueing (vLLM's
num_requests_waitingmetric) or its KV cache fills; 4–8 per GPU is a reasonable start. - Hosted API (DeepSeek, OpenAI, …): each call is latency-bound, so the speedup is close to linear until your account's rate or concurrency limit. Set the limit below that quota.
- Hosted API with a fallback: add a
[[llm_fallbacks]]entry. When the primary answers429, its circuit opens for the provider'sRetry-Afterand the remaining runs go to the next candidate instead of failing.
llm_provider = "openai-compat"
llm_model = "deepseek-chat"
llm_base_url = "https://api.deepseek.com/v1" # key from the LLM_API_KEY env var
bootstrap_max_concurrent = 8
# Takes the overflow while the primary is rate-limited.
[[llm_fallbacks]]
provider = "openai-compat"
model = "<another-model>"
base_url = "<another OpenAI-compatible endpoint>/v1"
api_key_env = "FALLBACK_API_KEY"The data moves with the companion importer
(ai-memory-importer, boundary in
companion-crates.md). Most of the work is re-wiring
each harness. Do it in this order:
-
Export from agentmemory while it still runs. Its export command writes one
ExportDataJSON file; its Obsidian export writes a vault directory. The JSON is the complete route (memory versions, TTLs, sessions, summaries, lessons, insights). The importer reads only that file and never contacts agentmemory. -
Stop agentmemory and unwire it. Remove its MCP server entry, the plugins and skills it installed for each harness, and the memory guideline block its
connectcommand writes into rules files (AGENTS.md,GEMINI.md,.cursor/rules/,.kiro/steering/and the like). Left in place, that block keeps agents calling tools that no longer exist, and one of them,memory_consolidate, is also an ai-memory tool with different arguments.ai-memory doctorlists every leftover it can see, with the file and lines and the fix, and changes nothing:⚠ agentmemory configuration is still present (2 place(s)). ... - MCP server entry in /home/me/.cursor/mcp.json (mcpServers.agentmemory) fix: remove the `mcpServers.agentmemory` entry from /home/me/.cursor/mcp.json; ... - guideline block in /home/me/work/api/AGENTS.md (lines 5-10) fix: delete the agentmemory guideline block (lines 5-10) from ...Rules kept outside files (Warp's, for example) need a look by hand.
-
Wire ai-memory into each harness:
ai-memory install-hooks --agent <name> --apply,ai-memory install-mcp --client <name> --applyandai-memory install-skills --agent <name>. -
Map projects, dry-run, then import. agentmemory names a project by its directory basename, so the importer needs a mapping file to the ai-memory
workspace/project(by basename, or by exact sessioncwdwhen two repositories share a name). The dry run lists every unmapped project and every record type it leaves out, with counts;--applyrefuses to run while anything is unmapped:cargo run --manifest-path companions/ai-memory-importer/Cargo.toml -- \ agentmemory-export --file agentmemory-export.json --mapping mapping.json cargo run --manifest-path companions/ai-memory-importer/Cargo.toml -- \ agentmemory-export --file agentmemory-export.json --mapping mapping.json \ --apply --manifest-out agentmemory-manifest.json
Pages land under
imported/agentmemory/in the mapped project. A memory's versions become one page with its supersession history,forgetAfterbecomesexpires_at, and observations are dropped unless you pass--replay-observations. Rerunning is safe: pages already imported are skipped. For a vault, useagentmemory-vault --dir <vault> --workspace W --project Pinstead. -
Check. Ask your agent something an old memory answered, or call
memory_queryfor a known title in each project, and runai-memory doctoragain until it reports no leftovers.
What has no ai-memory counterpart (graph nodes and edges, actions, signals,
routines, sentinels, sketches, checkpoints) is counted in the manifest's
dropped section and not imported. ai-memory derives its own entity graph from
the imported pages.
To keep a team's shared memory reviewable next to the code it documents, use
the ai-memory-wikisync companion
(boundary in companion-crates.md). It exports
explicitly allowlisted page families from the server's read-only /api/v1
surface into a directory in your repo. It is dry-run by default:
ai-memory-wikisync plan --server http://127.0.0.1:49374 \
--workspace demo --project app --dest ./wiki \
--include _rules --include decisions # lists create/update/unchanged; never writes
ai-memory-wikisync export ...same args... --apply # writes; prints the git commands to runEverything is opt-in and fail-safe: the family allowlist must be explicit
(* is refused), files edited locally since the last export are reported
with a diff summary and refused without --force, no frontmatter is forged,
and the tool never runs git itself. sync sends reviewed repository edits
back through MCP (each write conditional on the version it planned against;
needs ai-memory 3.0+), and deletes travel only with --propagate-deletes.
install-hook writes a git post-merge hook that runs sync after every
merge or pull: a dry-run report by default, or a write with --on-merge apply. It
never stores a token (the hook reads AI_MEMORY_AUTH_TOKEN when it runs) and
never passes --prefer, so conflicts still wait for a person:
ai-memory-wikisync install-hook --workspace demo --project app \
--dest docs/wiki --include _rules --include decisions
ai-memory-wikisync uninstall-hook --dest docs/wiki # removes only its blockIn CI, sync --check writes nothing and exits 0 in sync, 3 when the
repository and the server differ, and 4 on conflicts or refusals. A CI
checkout has no sync state, so it compares the repository with the server
directly. A GitHub Actions job that flags drift on wiki pull requests:
name: team-wiki
on:
pull_request:
paths: ["docs/wiki/**"]
jobs:
wiki-drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cargo install --locked --git https://github.com/akitaonrails/ai-memory ai-memory-wikisync
- name: Compare docs/wiki with the team's ai-memory server
env:
AI_MEMORY_SERVER_URL: ${{ secrets.AI_MEMORY_SERVER_URL }}
AI_MEMORY_AUTH_TOKEN: ${{ secrets.AI_MEMORY_AUTH_TOKEN }}
run: |
ai-memory-wikisync sync --check \
--workspace demo --project app --dest docs/wiki \
--include _rules --include decisionsThe server must be reachable from the runner (serve --enable-api behind a
token). To tolerate drift and fail only on refusals, end the command with
|| [ $? -eq 3 ].
By default there is nothing to think about: memory decays on a single gentle
curve, and an upgrade to 2.4 changes no scores and evicts nothing. When you do
want to tune aging, it is all opt-in and reversible. The original of anything
compacted or merged stays in git and the supersession chain, recoverable with
ai-memory restore-page.
- Keep something forever: pin it. A pinned page is exempt from the forget-sweep regardless of tier or age. Semantic and procedural pages never decay either; only working/episodic memory ages.
- Make a note expire on a deadline: ask your agent to remember it "until
" (an
expires_at); the forget-sweep deletes it when the time passes, no matter how often it was read. A TTL outranks pinning. - Tune how long each tier lasts: set per-tier half-lives in the project's
.ai-memory.toml[decay.half_life_days](e.g. keep episodic history longer, working-tier scratch shorter). Omit it for the default single curve. - Compact instead of evict, and de-duplicate:
[decay] compact_cold_episodickeeps a cold page's durable facts (paths, error codes, decisions) and drops the prose;[decay] dedup_cold_clusterscollapses near-duplicate cold pages into one survivor. Both are zero-LLM, off by default, and supersede rather than delete. - Keep used memory longer: nothing to configure. A page you open, search, or reach through a related-pages walk is reinforced automatically and resists decay.
- Review similar knowledge: run
memory_lint(through your agent or the CLI); with embeddings configured it emitssimilarity_candidatefindings for same-topic page pairs, advisory only. Similarity reads shared vocabulary as much as disagreement, so read each candidate as a pair to check, not as a contradiction or a supersession instruction. Explicitcontradictsedges remaincontradictionfindings. If that noise is too high, raisecontradiction_band_min(config.tomlorAI_MEMORY_CONTRADICTION_BAND_MIN, default0.4). On such a store the band measures domain proximity more than conflict, so a higher floor trims same-domain-but-unrelated pairs. - Let an LLM consolidate on idle ("dream"): with a provider and an embedder
configured,
[dream] enabledturns on a background pass that rewrites clusters of cold notes into single coherent pages while you're idle and cancels the moment you return. It is off by default, never deletes a source, and is gated on an internal recall eval before it could ever become default behavior.
A local model with a context window around 200k tokens, or any long-horizon session, compacts again and again. Each compaction keeps a lossy summary, and the first thing it loses is the start of the session: the task you gave, its constraints, the early decisions. ai-memory has the prompts you actually typed, so the agent can re-ground on them.
- On Claude Code, Codex, Factory Droid and OpenCode V1/V2, after each compaction the hooks inject a small post-compaction anchor (about 2,000 characters by default) with the session's first and latest prompts, and the installed instructions tell the agent to trust it over the summary.
- On Gemini CLI, Cursor, Copilot CLI, Kimi Code, Grok, Kiro, Cline, Muse and
the rest, nothing is injected: the routing block and the handoff skill tell
the agent to read its own session's prompts with
memory_read_session_observationsafter a compaction. Install the managed routing (ai-memory install-instructions, or ask "install ai-memory routing") so every session gets that rule. - Anywhere the hooks answer a prompt, you can start one with
reload contextto get the stretch the last compaction dropped, for examplereload context, then finish the migration.
Codex's compact_prompt setting replaces Codex's whole compaction prompt and
applies only to local providers, so it cannot add one line the way the OpenCode
hook does. Change it only if you mean to rewrite how Codex summarizes. See
usage.md for the per-harness
details.
- Continuity across agents in the same project (quit Claude Code, open Codex in the same repo): automatic. A handoff is captured at session end and the next session's on-start hook prepends it. Ask "where did we leave off?".
- Ask an agent in another project to do something without loading that
project's context here: use cross-project messaging. Say "send project-b a request to
add the export endpoint" (
memory_message_send), and over there "check my inbox" (memory_message_pop). Seeagent-messaging.md.
When an orchestrator has to stop for a person, send a normal cross-project
message and poll for a normal reply. The subject lines are the shared
convention; memory_message_send and memory_message_list are the tools.
- Send to the project the operator reads.
subjectisdecision: <short question>. The body names the question, each option'sidand label, andreply_project: <your workspace>/<your project>. Save the returnedmessage_id. You need write on that mailbox project, and it must already exist. - The operator, or a companion, answers with
memory_message_sendback toreply_project.subjectisdecision-reply: <message_id>. The body carriesoption: <id>. Sending the reply needs write on your project. - Poll
memory_message_liston your inbox until a pending row's subject is that exactdecision-reply:line. The oldest match is the answer. Pop it when you take it, thenmemory_message_cancelthe question.
Before you act on a requires_root: true decision, compare from_owner_user
on the reply with the root identity you were configured with. It is
attribution, not a role, and it is empty on anonymous and single-operator
servers, so treat an empty value as not root. The server itself does not check
who answers. /web shows the mailbox and leaves every message pending.
The list is oldest-first, 50 rows by default and 200 at most, so keep the
inbox you poll from drained. A companion can wake on the message_send
observer webhook, then list; the webhook carries scope and actor, and the
orchestrator still polls.
Full layout and limits:
agent-messaging.md.
Give each account or provider its own config home and pass it with --env, so
the harness, its hooks and MCP, and transcript import all use that one home:
ai-memory run --env CLAUDE_CONFIG_DIR="$HOME/.claude-work" claude
ai-memory run --env CODEX_HOME="$HOME/.codex-work" codex # the dir must exist-
--envand--env-filebelong toai-memory run, so they go before the harness name. -
A launcher or orchestrator that starts harnesses with its own environment (provider keys, an account's config dir) can write it to a file and pass
--env-file <path>, oneKEY=VALUEper line. Values are taken literally, so use absolute paths in the file. -
To name an account once instead of repeating
--env, add a profile toconfig.tomland select it with--profile(before the harness name):[run.profiles.work.env] CLAUDE_CONFIG_DIR = "/home/me/.claude-work"
Then
ai-memory run --profile work claude. Use absolute paths: profile values are not expanded.--env-fileand--envstill override a profile entry, and an unknown name fails before anything is wired or launched. A--profileafter the harness name belongs to the harness (OMP and Codex have their own). -
Auto-wire runs once per config home, so the second account gets its hooks + MCP on its own first launch. To wire one by hand, export the variable for the installers:
CLAUDE_CONFIG_DIR="$HOME/.claude-work" ai-memory install-hooks --agent claude-code --apply, then the same forinstall-mcp --client claude-code --apply.
--yolo maps to each harness's dangerous-mode flag (Claude Code →
--dangerously-skip-permissions, plus --settings forcing
bypassPermissions), which runs every tool call with no confirmation. ai-memory run --yolo adds guardrails around that, gated
entirely on a real interactive terminal (stdin and stderr both TTYs), so
scripts, hooks, and CI are never prompted:
ai-memory run --yolo claude- The warning. Before the agent spawns, you are asked to confirm:
Enter/y/yesproceeds (the default);n/noaborts before anything launches. - The ai-jail offer. If ai-jail
is usable (on Linux/macOS, installed on
PATHor~/.local/bin/ai-jail, with its sandbox backend present:bwrapon Linux,sandbox-execon macOS) and you are not already inside it, a second question offers to re-run the session inside it. When it is not usable (or on Windows) there is no second question; the run just proceeds. With an ai-jail older than 3.0.1, accepting re-execs the original command underai-jail --network --agent-state --env <NAME>... --, forwarding only the credential/config environment variables that are already set (server/hook URL,CLAUDE_CONFIG_DIR, provider API keys, etc.).--networkkeeps the loopback ai-memory server reachable while still sandboxing the filesystem. Declining keeps the run unsandboxed (your choice, already warned). - Choosing what the jail gets. After you accept the offer, a checklist
lists what this host can mount, pre-marked so
Enterdoes the friendly thing: every credential that exists (~/.config/gh,~/.aws,~/.kube,~/.config/gcloud,~/.docker/config.json), SSH keys + agent when youroriginis an SSH remote, and worktree metadata in a linked worktree. The Docker socket (grants host root), GPU, display, Pictures, and Tailscale are listed unchecked. Type row numbers to flip them (2 4), orall/none. A mounted credential is usable by the unsupervised agent, so uncheck what it should not touch. What you see is what you get: unchecked rows are passed as--no-X, so they stay off even if your global~/.ai-jailenables them. - Your answers come back next time. The checklist remembers what you
chose for each checkout, so the next launch shows the same marks and Enter
is enough. Each pre-checked row says why it is recommended (
found on this machine,origin pushes over SSH), and the header says when your answers were saved and what changed since (new: …,no longer offered: …). Typeresetto go back to the recommended marks. The answers are stored in ai-memory's data directory, never in your repository. - Letting the agent read a sibling project. Press
fin the checklist to pick extra folders. The picker starts in the folder above your checkout: type to filter, Space to select (read-only), Ctrl+W to make the selected one read-write, Tab or → to open a folder, ← to go up, Enter when done. From the command line,ai-memory run --jail --jail-map ../ai-jail claudemounts a folder read-only and--jail-rw-map DIRread-write; both repeat. Your home,/, credential folders (~/.ssh,~/.aws,~/.config/gh, …) and ai-memory's own data directory are refused, and the error says why. Edits the agent makes in a read-write sibling are captured under the current project, because capture follows the session. This needs ai-jail 2.15. - The same choices next time. When the jailed session ends, ai-memory
prints the
ai-memory run …line that repeats your choices,--jail=…list, folders and harness included. Paste it, or keep it as an alias, to skip the questions. Switching harness from the post-run menu keeps the same jail and options. - Skipping the questions.
ai-memory run --jail claudere-runs inside ai-jail straight away, turning on those pre-marked defaults and leaving everything else to your own ai-jail config. This works with or without--yolo, and in scripts too; it fails rather than running unjailed if ai-jail is not usable.--jail=github,ssh,no-miseis exact: the listed toggles (no-Xforces one off), with every other checklist row forced off;allturns every row on andnoneturns every row off.--no-jailnever jails and skips the offer (the--yolowarning stays). There are no bare--github-style flags on purpose: they would collide with the harness's own flags (Claude Code has a--worktree). The credential mounts need ai-jail 2.5.0; toggles your installed ai-jail lacks are hidden, and naming one is an error. - Connecting back to ai-memory. The jailed process automatically receives
the resolved server URL and URL base path, including a remote server from
config.toml. A root bearer read fromconfig.tomlorbearer_token_fileis not exposed to the managed harness; the launch stops instead. For an authenticated server, give the launch a least-privilege API token withAI_MEMORY_AUTH_TOKEN=... ai-memory run --jail ..., or run without the jail. An explicitly supplied environment token already belongs to the child-process boundary and is forwarded. - A project
.ai-jailwins. If the directory you launch from has its own.ai-jail, ai-jail loads it as-is: no checklist, and a bare--jailadds no toggles;--jail=…still applies its list on top. A project file cannot enable credentials (ai-jail treats it as untrusted), so to have them mounted automatically there, enable them in your global~/.ai-jailor pass--jail=github,…. ai-memory always passes--no-save-config, so a jailed run never writes its own flags into your repository's.ai-jail. - With ai-jail 3.0.1 or newer. ai-jail reviews the access itself, once
per project, so ai-memory's screen keeps only the extra folders (
f). ai-memory names the harness for ai-jail and passes what the session needs as plain grants, with no extra prompts: the harness's login state, theAI_MEMORY_*variables, and only that harness's own API key (a Claude jail never gets your OpenAI key). A memory server on this machine is reached through one forwarded port, so the network stays filtered unless you open it in ai-jail's review; a server on another machine keeps full network, which ai-jail labels OPEN. Copilot and Command Code, which ai-jail has no preset for, keep the checklist above. - Already inside ai-jail. Both prompts are skipped and the run proceeds
directly, so
ai-jail ai-memory run … --yolosees no extra friction. Detection is Linux (ai-sandboxhostname) / macOS (PS1starting with(jail)); it fails open (shows the warning) when undetectable, never open to skipping it silently. - Claude's own permission settings. For Claude,
--yoloalso forcesbypassPermissionsover anydefaultModein your settings, so anautooracceptEditsdefault cannot narrow the run. Through 3.4.2 that took a separate--true-yolo; it is now a hidden alias of--yolo(it prints a one-line note), andclaude_true_yoloinconfig.tomlis ignored (remove it). It cannot remove your ownaskrules: Claude Code honors explicitpermissions.askrules (and its built-in command-safety checks) in every mode, so a rule likeBash(docker run *)in~/.claude/settings.jsonstill pauses the run. For a pause-free sandbox, drop thoseaskentries;denyrules block without pausing, so they can stay. Best paired with ai-jail. - Passing extra env, e.g. a GitHub token.
ai-memory run claude --yolo --env GH_TOKEN="$(gh auth token)"forwards it into the jailed agent (needs ai-jail 2.4.2 or later when you accept the jail offer). This hands a sandboxed agent your token, so only do it for work you'd trust it with; it is deliberately never forwarded automatically.
See design-yolo-safety-ai-jail.md for the
full contract.
install-hooks --agent claude-code --apply wires the hooks user-wide
(~/.claude/settings.json), so every Claude Code session is captured and you
exclude paths with [capture] ignore_paths in .ai-memory.toml. To opt in
per repository instead, run from inside the checkout:
ai-memory install-hooks --agent claude-code --scope project --applyThis writes the repository's gitignored .claude/settings.local.json where
Claude Code reads it (the git root; the current directory on Windows or when
the repository root is your home directory) and leaves the user-level file
alone. Backups of an updated file go under the data dir, not the checkout.
Pick one scope per machine: Claude Code merges project and user hooks. The
installer warns when the file is not git-ignored, and ai-memory uninstall --only hooks --apply from inside the checkout removes the entries again.
Claude Code only; other harnesses keep their user-level hook files.
One machine, several organisations, each with its own ai-memory server. Register each server once under a name, with the directory it is allowed to serve, then let each repository's marker pick it:
ai-memory server add team-a --url https://memory-a.example.com --root ~/work/team-a --auth-token-stdin
ai-memory server add team-b --url https://memory-b.example.com --root ~/work/team-b --auth-token-stdin# ~/work/team-b/.ai-memory.toml
workspace = "team-b"
server = "team-b"Repositories without a server key keep using the server install-hooks
configured. The marker only ever names a profile; a profile that does not
resolve drops the event rather than sending it anywhere else. Commands you run
inside the repository (run, workstreams, doctor, search, ...) use the
same profile. Details, the
fail-closed rules, and which integrations support it:
marker-file.md.
Use the menu bar app when you want one .app that starts the server and
opens the existing tools (web UI, ai-memory status, config, logs). It does
not replace those tools with a second dashboard.
./companions/ai-memory-macos/build.sh
open "companions/ai-memory-macos/dist/AI Memory.app"Drag AI Memory.app to /Applications, then Install & Start Server
from the menu extra. Wire an agent with the bundled binary:
BIN="/Applications/AI Memory.app/Contents/Resources/runtime/ai-memory"
"$BIN" install-mcp --client claude-code --apply
"$BIN" install-hooks --agent claude-code --applyMemory stays in ~/Library/Application Support/ai-memory. Replacing the
.app does not rewrite it. Full paths (tarball, source, Docker, launchd):
macos.md.
Your agent runs most of these for you; run and continue are how you start it:
ai-memory run <harness> # launch a harness, hooks + MCP auto-wired
ai-memory continue # resume the newest managed checkout
ai-memory resume --search auth # pick a matching workstream in this checkout only
ai-memory resume --all # pick from every linked checkout on this machine
ai-memory workstreams # list this checkout's managed workstreams
ai-memory status # counts, paths, health
ai-memory recover # replay outage spool/transcripts safely
ai-memory list-projects # every workspace/project the server knows about
ai-memory project init # pin this checkout's scope in a .ai-memory.toml
ai-memory doctor # is every harness that ran here captured?
ai-memory backfill # import prior local history into an empty store
ai-memory search "wal mode" # FTS5 lookup in this project
ai-memory recent # newest wiki pages in this project
ai-memory write-page … # save a durable page
ai-memory handoffs # list open handoffs for the project
ai-memory message list # cross-project inbox
ai-memory server list # server profiles a marker can route to
ai-memory export-okf … # export the wiki as an OKF bundle
ai-memory serve # run the serverOn an interactive terminal, status and doctor group and wrap their output
for readability. Redirected output, JSON, NO_COLOR, and TERM=dumb remain
plain; see Diagnostic report presentation for the exact
contract.
-
Server/homelab down:
ai-memory rundoes not need the server to start a harness. When the server is unreachable it prints one loud warning and launches anyway. Hooks keep capturing to the local spool (drained automatically when the server returns), an existing MCP registration degrades to no-recall for the session, and the child's exit code is returned. What you lose for that run is the workstream lease/context, immediate transcript import, and handoff delivery; sessions resume only through an explicit native selector because no lease means no mutual exclusion. An explicit resume is journaled with its exact pre-launch native cursor and recovery imports only the appended delta; a cursor that cannot be proven requires manual repair. A fresh run is journaled only when one new native session can be correlated; ambiguity prints a manual backfill action. Once the server returns, runai-memory recover: for transcript-capable harnesses it quarantines correlated spool entries, drains unrelated events, and replays the bounded exact transcript through sanitized/hook/batch; Antigravity has no supported transcript exporter, so its degraded run is journaled as spool-only and clears only after correlated hook evidence has a durable-delivery confirmation; recovery never calls its exporter. Empty or previously correlated-loss spool state stays journaled for manual repair. Owner-authorized recovery finishes an expired original managed run only when it was not superseded. A full journal refuses new entries instead of evicting old work, and dropped spool events make the command fail while retaining every journal entry for a later clean pass. Re-running is safe. See Degraded offline launches. To fail instead of degrading, pass--require-server(or setrun.require_server = true/AI_MEMORY_RUN_REQUIRE_SERVER=true). For a planned outage, considerAI_MEMORY_HOOK_SPOOL_MAX_ATTEMPTS=0so spooled events are never dropped for retry-attempt count. -
Nothing is being remembered: hooks may not be installed.
ai-memory run <harness>installs its hooks + MCP on the first launch per harness, ai-memory version and config home, and again afterai-memory uninstall. If that harness already launched throughrunand its hooks went missing another way (removed by hand, a failed first wire), install them by hand:ai-memory install-hooks --agent <your-agent> --applyandai-memory install-mcp --client <client> --apply. Then checkai-memory status/ai-memory doctor. -
The current checkout resolves to an unexpected project: run
ai-memory doctor. Its project-coordinate block shows the effective local marker, credential-stripped repository identity source/style, canonical and legacy candidate names, the server's exact/compatibility/missing/ambiguous result, and whether an authorized write can promote the existing name in place. The check is read-only: an unknown coordinate is reported, never created. If the server coordinate is ambiguous, a returned UUID/current name is only the preferred identity-backed candidate for context, not a unique resolution or rename permission. Local harness rows remain visible and their captured counts are shown as unavailable rather than zero. -
Only some agents are being remembered: run
ai-memory doctor. It lists every harness that has local sessions in this project and whether the server captured them. A harness you rotated in without installing its hook (a silent gap: it keeps its own local history while capturing nothing) shows up as a warning with the exactinstall-hookscommand to fix it. For Claude Code it also reports the detected default auto-memory directory and whether the repository's capture exclusions cover it. A customautoMemoryDirectoryis not discoverable from Claude's session transcripts and is not reported. Anexcludedverdict applies only to native/generated hooks; shell and PowerShell compatibility hooks do not enforce capture-policy exclusions. -
Nothing new is being remembered at all: run
ai-memory doctor. It works with the server down and says so; it reports the local hook spool (events waiting for the server, and a warning once it is full and newly captured events are dropped until space is available); and when ai-memory's Codex hooks are installed, it asks Codex whether it will run them. Codex skips a hook you have not trusted, and skips it again after its command changes, without telling you: open Codex, run/hooks, and trust them. -
Agents keep calling
memory_recall,memory_saveor other tools ai-memory does not have: agentmemory's MCP entry or its rules-file guideline block is still there.ai-memory doctornames each one with the fix (see Coming from agentmemory). -
I just installed hooks in a project I've worked in for a while: the first time you open the project after installing, ai-memory imports your existing local session history once (bounded, sanitized on the server, only into an empty store) so it isn't starting from nothing. It runs automatically in the background; you can trigger or preview it yourself with
ai-memory backfill(--dry-runto see what it would import), or turn it off withAI_MEMORY_BACKFILL_ON_START=false. A single transcript record over 1 MiB (usually a screenshot in a tool result) is skipped and counted on stderr; the rest of that session is still imported. -
A search misses something you saved: confirm the scope. Memory is per-project; a page saved in project A is not returned in project B unless it was written to the global scope or you query with an explicit scope.
-
You want an LLM feature (consolidation, digests): set a provider (
AI_MEMORY_LLM_PROVIDER=…); without one, capture + search still work.