67 KiB
Installation cookbook
The README quick-start covers the happy path (docker + Claude Code). This page covers everything else:
- Server on a different machine (homelab, LAN box, remote server)
- Configuring the CLI URL and auth
- Arch Linux native packages (AUR) (systemd system service or user service)
- Configuring other agent CLIs (Codex, Devin CLI, OpenCode, OMP, Pi, Cursor, Claude Desktop, Gemini CLI, Antigravity CLI, Grok Build CLI, Zero, Kimi Code, OpenClaw, VS Code Copilot)
- Installing hooks without docker (curl-based installer)
- Running ai-memory without docker (cargo install, building from source)
- Managed cross-harness workstreams
(
ai-memory run, transparent native resume, and argument forwarding) - LLM provider tiers + self-hosted Ollama
- Subcommand reference
- Managed routing snippets and Agent Skills
- Operating without auth (local-only)
- Keeping ai-memory up to date
Shorthand. Most snippets use
$TOKENandhomelab:49374. If you're following along verbatim:export TOKEN=$(docker run --rm akitaonrails/ai-memory:latest generate-auth-token)and replace
homelabwithlocalhostif the server runs on the same machine as the agent CLI.
The Docker image is published for linux/amd64 and linux/arm64; Apple
Silicon Macs and ARM64 Linux hosts should not need --platform linux/amd64.
Server on a different machine
When the ai-memory server runs on a LAN box (homelab, headless server) and you use Claude Code / Codex / etc. on a laptop:
Server side (the homelab host)
docker run -d --name ai-memory \
--restart unless-stopped \
-p 0.0.0.0:49374:49374 \
-v ai-memory-data:/data \
-e AI_MEMORY_AUTH_TOKEN="$TOKEN" \
-e AI_MEMORY_ALLOWED_HOSTS="<server-ip>,localhost,127.0.0.1" \
-e AI_MEMORY_LLM_PROVIDER=anthropic \
-e ANTHROPIC_API_KEY=sk-ant-... \
akitaonrails/ai-memory:latest
See Security in the README for why
AI_MEMORY_AUTH_TOKEN and AI_MEMORY_ALLOWED_HOSTS are both
required for any non-loopback bind.
Client side (the laptop)
export AI_MEMORY_SERVER_URL="http://<server-ip>:49374"
export AI_MEMORY_AUTH_TOKEN="$TOKEN"
ai-memory install-mcp --client claude-code --apply
ai-memory install-hooks --agent claude-code --apply
If CLAUDE_CONFIG_DIR is set, the claude-code installers match Claude Code's
own config resolution: install-mcp writes the MCP registration to
$CLAUDE_CONFIG_DIR/.claude.json (instead of ~/.claude.json),
install-hooks / setup-agent target $CLAUDE_CONFIG_DIR/settings.json
(instead of ~/.claude/settings.json), and install-skills --scope global
uses $CLAUDE_CONFIG_DIR/skills (instead of ~/.claude/skills). uninstall
sweeps the active relocated paths alongside the home defaults. It cannot
discover an older arbitrary CLAUDE_CONFIG_DIR that is no longer set. The
Docker wrapper forwards the variable for config roots under its existing
$HOME bind mount; use the native binary when the relocated root is outside
$HOME.
The CLI commands (bootstrap, status, search, lint, auto-improve,
curator, pending-writes, etc.) inherit the two env vars automatically. So do
install-mcp, install-hooks, and
setup-agent: with AI_MEMORY_SERVER_URL set, install-mcp derives the
/mcp endpoint and install-hooks uses the bare server origin.
After upgrading ai-memory, refresh the managed routing package in existing
projects so Claude Code/OpenCode/Codex/Gemini pick up new tool guidance and
proactive retrieval rules. From an agent, ask "refresh the ai-memory routing in
this project"; from the terminal, run ai-memory install-instructions (or pass
--target AGENTS.md for non-Claude prompt files). The update is idempotent:
legacy long snippets between <!-- ai-memory:start --> /
<!-- ai-memory:end --> are replaced in place with the slim snippet, and
managed Agent Skills are installed or updated alongside it.
Configuring the CLI URL and auth
The ai-memory binary is a thin HTTP client. It never opens the wiki
or SQLite directly; state-touching commands go through the running
server, which is the sole writer.
Configuration is two optional environment variables:
| Variable | Default | When to set it |
|---|---|---|
AI_MEMORY_SERVER_URL |
http://127.0.0.1:49374 |
When the server runs somewhere other than the same machine, such as http://192.168.0.90:49374. |
AI_MEMORY_AUTH_TOKEN |
unset | When the server has bearer auth enabled. |
For a single-laptop loopback server, set neither variable. For a remote or homelab server, put both in your shell rc or direnv file:
export AI_MEMORY_SERVER_URL="http://192.168.0.90:49374"
export AI_MEMORY_AUTH_TOKEN="<token>"
Explicit --server-url and --auth-token flags on install-mcp,
install-hooks, and setup-agent override the environment. That is
useful when you are generating config for a client that talks to a
different server than your default CLI target.
If you run install-mcp --apply first and later run install-hooks --apply
without env vars or flags, hooks reuse the existing ai-memory MCP entry for
that agent when possible. This keeps remote MCP config and lifecycle capture
pointed at the same server instead of falling back to loopback.
init, serve, and generate-auth-token do not need these env vars because
they either create local files or start the server itself.
Default project resolution (--project-strategy)
By default each session files memory under basename(cwd). Because an agent
shell keeps its working directory between tool calls, a single
mkdir sub && cd sub reparents the rest of the session into a phantom project
named sub. To make every session for an install resolve its project from the
git repo root instead — collapsing subdirectories and worktrees — bake the
strategy into the hooks:
ai-memory install-hooks --apply --agent claude-code --project-strategy repo-root
--project-strategy accepts basename (the default; bakes nothing, so existing
installs are unchanged) or repo-root. It works for every agent and delivery
path. A per-repo .ai-memory.toml marker's own project_strategy / project
still take precedence — see
the marker-file reference.
Arch Linux native packages (AUR)
Use the native packages when you want /usr/bin/ai-memory plus systemd units
instead of the Docker wrapper. The package installs the binary and hook sources
once; each user still stages their agent hook scripts into their own home dir
with install-hooks --apply.
Package choice
yay -S ai-memory-bin # prebuilt Linux x86_64/aarch64 binary, fastest install
yay -S ai-memory # builds from source, works on x86_64 and aarch64
Both packages install the same runtime layout:
| Path | Purpose |
|---|---|
/usr/bin/ai-memory |
Native CLI/server binary. |
/usr/share/ai-memory/hooks/ |
Packaged hook source bundle used by install-hooks. |
/usr/lib/systemd/system/ai-memory.service |
System-wide service unit. |
/usr/lib/systemd/user/ai-memory.service |
Per-user service unit. |
/usr/lib/sysusers.d/ai-memory.conf |
Creates the ai-memory system user. |
/usr/lib/tmpfiles.d/ai-memory.conf |
Creates /var/lib/ai-memory for the system service. |
/etc/ai-memory/config.toml |
System-service config file, tracked as a pacman backup file. |
/etc/ai-memory/env |
System-service environment/secrets file, tracked as a pacman backup file. |
The binary itself does not guess between system and user mode. The unit file chooses explicitly:
| Mode | Data dir | Config | Env/secrets | Requires sudo? |
|---|---|---|---|---|
| User service | ~/.local/share/ai-memory |
~/.config/ai-memory/config.toml |
~/.config/ai-memory/env |
No |
| System service | /var/lib/ai-memory |
/etc/ai-memory/config.toml |
/etc/ai-memory/env |
Yes |
Do not run both services on the same bind address. They can coexist on disk, but
only one can listen on 127.0.0.1:49374 unless you change bind in one config.
User-level service
Use this on a single-user workstation. It needs no sudo after package install and keeps all state in your home directory.
mkdir -p ~/.config/ai-memory ~/.local/share/ai-memory
ai-memory \
--data-dir ~/.local/share/ai-memory \
--config ~/.config/ai-memory/config.toml \
init
Edit provider/auth settings if you want LLM consolidation or bearer auth:
$EDITOR ~/.config/ai-memory/config.toml
$EDITOR ~/.config/ai-memory/env
For a loopback-only local service, bearer auth is optional. If you want one:
TOKEN=$(ai-memory generate-auth-token)
printf 'AI_MEMORY_AUTH_TOKEN=%s\n' "$TOKEN" >> ~/.config/ai-memory/env
Start and inspect the service:
systemctl --user daemon-reload
systemctl --user enable --now ai-memory.service
systemctl --user status ai-memory.service
journalctl --user -u ai-memory.service -f
If the service should keep running after you log out:
loginctl enable-linger "$USER"
Verify the HTTP server:
curl http://127.0.0.1:49374/mcp
# Expect a JSON-RPC error, which means the server is reachable.
System-level service
Use this for a shared workstation, LAN box, or homelab-style host where the server should run independently of any logged-in user.
Make sure the package-created user and state directory exist, then initialize the data layout as that service user:
sudo systemd-sysusers /usr/lib/sysusers.d/ai-memory.conf
sudo systemd-tmpfiles --create /usr/lib/tmpfiles.d/ai-memory.conf
sudo -u ai-memory ai-memory \
--data-dir /var/lib/ai-memory \
--config /etc/ai-memory/config.toml \
init
Edit system config and secrets:
sudoedit /etc/ai-memory/config.toml
sudoedit /etc/ai-memory/env
The package installs /etc/ai-memory/env as root-readable only because it may
hold API keys. Keep that file out of backups or logs that other users can read.
For LAN exposure, set a non-loopback bind and allowed hosts in
/etc/ai-memory/config.toml, and set a bearer token in /etc/ai-memory/env:
bind = "0.0.0.0:49374"
allowed_hosts = ["homelab", "192.168.0.90", "localhost", "127.0.0.1"]
TOKEN=$(ai-memory generate-auth-token)
printf 'AI_MEMORY_AUTH_TOKEN=%s\n' "$TOKEN" | sudo tee -a /etc/ai-memory/env
Start and inspect the service:
sudo systemctl daemon-reload
sudo systemctl enable --now ai-memory.service
sudo systemctl status ai-memory.service
journalctl -u ai-memory.service -f
Verify from the host:
curl -sI http://127.0.0.1:49374/handoff
# 401 Unauthorized when AI_MEMORY_AUTH_TOKEN is set.
LLM provider login with native services
API-key providers go in the relevant env file:
# User service
printf 'AI_MEMORY_LLM_PROVIDER=anthropic\nANTHROPIC_API_KEY=sk-ant-...\n' >> ~/.config/ai-memory/env
systemctl --user restart ai-memory.service
# System service
sudoedit /etc/ai-memory/env
sudo systemctl restart ai-memory.service
OAuth-style providers write tokens into the selected data dir. Run the login
with the same --data-dir and --config pair as the service:
# User service
ai-memory \
--data-dir ~/.local/share/ai-memory \
--config ~/.config/ai-memory/config.toml \
auth login openai-oauth
# System service
sudo -u ai-memory ai-memory \
--data-dir /var/lib/ai-memory \
--config /etc/ai-memory/config.toml \
auth login openai-oauth
Use auth login copilot the same way for GitHub Copilot. For per-developer
native hook auth against an OIDC issuer, run auth login oidc-device in the
developer's selected data dir instead:
ai-memory auth login oidc-device \
--issuer "https://issuer.example.com/realms/team" \
--client-id "ai-memory-cli"
The stored OIDC access token is also used by thin-client HTTP commands
(status, search, read-page, write-page, backup, embed, and
similar) when no static AI_MEMORY_AUTH_TOKEN / [auth].bearer_token is
configured. Static bearer auth still has precedence. This is for external
OIDC-aware gateways/bridges; native ai-memory server auth still uses static root
bearer / DB-user tokens, and /admin/* remains root-only unless a gateway
translates accepted OIDC auth into upstream auth that ai-memory accepts.
OIDC/Keycloak sid claims describe the login provider's session, not the
coding-agent session ai-memory uses for [auto_scope] isolation. Gateways may
propagate the authenticated user/client/agent headers, but
X-Memory-Actor-Session-Id should only contain a real lifecycle-hook session id
from a session-aware bridge.
Restart the service after changing provider settings:
systemctl --user restart ai-memory.service # user mode
sudo systemctl restart ai-memory.service # system mode
Wire agent CLIs after native install
For a local loopback server with no bearer token:
ai-memory install-mcp --client claude-code --apply
ai-memory install-hooks --agent claude-code --apply
For a bearer-protected local or LAN server, export the endpoint first. The MCP
URL includes /mcp; the hook URL is the bare origin.
export AI_MEMORY_SERVER_URL="http://127.0.0.1:49374"
export AI_MEMORY_AUTH_TOKEN="$TOKEN"
ai-memory install-mcp --client claude-code --apply
ai-memory install-hooks --agent claude-code --apply
install-hooks finds packaged hook sources under /usr/share/ai-memory/hooks,
then stages runnable copies under ~/.local/share/ai-memory/hooks/<agent>/ so
the agent can execute files owned by your user. Re-run install-hooks --apply
after package upgrades to refresh those staged copies.
Capture-policy capability and refresh
[capture] ignore_paths is enforced only by native ai-memory hook commands
and generated OpenCode/OMP/Pi/OpenClaw integrations. Local installers select
native commands where supported; legacy .sh/.ps1 hooks and remote-only or
Docker script bundles do not enforce it. Re-run install-hooks --agent <agent> --apply or refresh/reinstall generated plugins after upgrading; installer
capability output reflects the selected integration. See the canonical
capture exclusions reference.
Some agent harnesses attach the assistant's final turn to their Stop event —
Claude Code sends it as a raw last_assistant_message. By default that text is
never persisted: the native hook binary strips the raw field before it can reach
the local spool or the wire, and the server strips it defensively on arrival.
Opt-in capture (#196). You can opt in to storing a sanitized, 2 KB-capped excerpt of the assistant's final turn as the Stop body. It is a double opt-in — enable the server first, then the client:
-
Server: set
capture_assistant = truein the live<data_dir>/config.toml(or the service's configured TOML file), or setAI_MEMORY_CAPTURE_ASSISTANT=true, then restartai-memory serve. -
Client: re-install the Claude Code hooks with the flag:
ai-memory install-hooks --agent claude-code --capture-assistant --apply
The client sanitizes (built-in patterns) and truncates the excerpt before it
touches the spool or wire; the server re-scrubs with its [sanitize] patterns
before storing. If either side is off — or the marker is malformed — the Stop
stays empty. Re-running install-hooks without --capture-assistant removes
the flag (idempotent). --capture-assistant is Claude Code + native-platform
only; on any other agent or the script fallback the installer refuses it rather
than enabling something that cannot take effect. Assistant text is
privacy-sensitive — read the SECURITY.md notes on what it can contain and where
it flows (consolidation/reviewer prompts, and out to a cloud LLM provider if one
is configured) before enabling it.
Upgrading the binary is sufficient for native Claude Code installs, and pending
spooled events drain with the raw field stripped as well. Installs that run the
.sh/.ps1 script fallback (the Docker script bundle or an explicit
AI_MEMORY_HOOK_PLATFORM=posix) cannot sanitize the assistant text, so a Stop
payload still carrying the raw field is dropped whole by the script rather than
POSTed verbatim. The Docker wrapper deliberately keeps script commands because a
binary path inside its helper container is not valid on the host; running
install-hooks through that wrapper refreshes the scripts but does not convert
them. To capture assistant text safely, install a native ai-memory client on the
agent host, then use that native executable to run
install-hooks --agent claude-code --apply. Even if the script fallback is
retained, the server still strips any raw field on receipt before persistence.
Native ai-memory hook --event ... commands spool events locally. Session start
does a short bounded cleanup drain before fetching a handoff; cancellation-prone
boundary events (stop, pre-compact, and session-end) start a detached
hook-drain helper so delivery does not depend on one shutdown hook surviving.
On Unix, the helper uses a trusted setsid launcher when available and falls
back to a separate process group otherwise; Windows uses detached/breakaway
process flags. The spool is capped, so a permanently undrained backlog is
eventually pruned rather than unbounded, but old undelivered events can be lost.
The built-in timings stay short on agent-facing paths, but high-latency or
large-backlog instances can raise them with whole-minute runtime env vars in the
agent's environment; no install-hooks rerun is needed:
| Env var | Built-in default | Max override | What it caps |
|---|---|---|---|
AI_MEMORY_HOOK_DRAIN_TIMEOUT_MINUTES |
3 seconds | 60 minutes | each event POST during a drain |
AI_MEMORY_HOOK_HANDOFF_TIMEOUT_MINUTES |
3 seconds | 60 minutes | the synchronous session-start handoff GET |
AI_MEMORY_HOOK_START_BUDGET_MINUTES |
3 seconds | 60 minutes | total time session-start may spend waiting for the drain lock and cleanup draining |
AI_MEMORY_HOOK_BACKGROUND_DRAIN_BUDGET_MINUTES |
5 minutes | 60 minutes | total time the detached hook-drain helper may spend after a background-drain boundary |
AI_MEMORY_HOOK_INCREMENTAL_THRESHOLD |
32 events | positive integer | spool backlog size that triggers a 250 ms post-tool-use catch-up drain |
Timing values must be positive whole minutes. Missing, empty, non-numeric, or zero values fall back to the built-in defaults; values above 60 are clamped. The incremental threshold is a positive event count; invalid values fall back to 32.
Server-side hook ingest also has an optional per-source limiter for shared or
remote installs that need protection from one runaway agent session. Set
AI_MEMORY_HOOK_RATE_PER_SEC on the server to the token refill rate per
actor/session source; 0 or unset disables the limiter. Set
AI_MEMORY_HOOK_RATE_BURST to override the burst size (defaults to the refill
rate, minimum one token when enabled). The limiter is bounded in both key count
and key bytes, and /hook/batch drains can skip over-budget sources while still
accepting later unrelated sources.
Native service operations
# User service
systemctl --user restart ai-memory.service
systemctl --user stop ai-memory.service
journalctl --user -u ai-memory.service -n 100
# System service
sudo systemctl restart ai-memory.service
sudo systemctl stop ai-memory.service
journalctl -u ai-memory.service -n 100
Backups still use the same CLI, just point it at the service data dir:
# User service
ai-memory --data-dir ~/.local/share/ai-memory backup --to ~/ai-memory-backup.tar.gz
# System service
sudo -u ai-memory ai-memory --data-dir /var/lib/ai-memory backup --to /var/lib/ai-memory/backup.tar.gz
Package removal does not delete data. Stop the service and remove state only when you intentionally want to erase memory:
systemctl --user disable --now ai-memory.service
sudo systemctl disable --now ai-memory.service
# Optional destructive cleanup:
rm -rf ~/.local/share/ai-memory ~/.config/ai-memory
sudo rm -rf /var/lib/ai-memory /etc/ai-memory
Maintainer integration test
The normal CI runs scripts/check-native-packaging.sh, a host-safe regression
check that uses a temporary alternate root for systemd-analyze,
systemd-sysusers, and systemd-tmpfiles. It verifies unit syntax, expected
paths, sysusers output, tmpfiles rules, env-file mode, and AUR shell syntax
without writing to host /usr, /etc, /var, or touching real services.
The repo also includes a manual Arch integration harness that is intentionally kept out of routine CI because it creates a disposable distrobox, installs packages, starts real systemd services, and can take several minutes:
scripts/test-native-arch-systemd-distrobox.sh
It verifies the AUR metadata shape, builds the current working tree, installs
the native layout into the disposable Arch container, starts the system service
with systemctl, starts the user-profile command under transient systemd
supervision, and checks that packaged hook sources under
/usr/share/ai-memory/hooks can be staged by install-hooks.
The destructive part of that script refuses to run unless it detects a container/distrobox environment.
Useful knobs:
AI_MEMORY_NATIVE_TEST_BOX=ai-memory-native-test scripts/test-native-arch-systemd-distrobox.sh
AI_MEMORY_NATIVE_TEST_KEEP_BOX=1 scripts/test-native-arch-systemd-distrobox.sh
AI_MEMORY_NATIVE_TEST_IMAGE=quay.io/toolbx/arch-toolbox:latest scripts/test-native-arch-systemd-distrobox.sh
Configuring other agent CLIs
install-mcp --server-urlaccepts either the bare server origin or the full MCP endpoint and appends a missing/mcpexactly once.install-hooks --server-urltakes the bare server origin (e.g.http://homelab:49374) — hook scripts append/hook,/handoff, etc. themselves.
Each agent CLI needs two things:
- MCP registration - so the agent can call
memory_query,memory_recent,memory_handoff_accept. - Lifecycle hooks - so the server auto-captures session events. Without this, the agent can still query memory but capture becomes manual.
Claude Desktop and VS Code Copilot are MCP-only today. The hook-capable clients
in the README Support Matrix, including Pi and
Zero, have lifecycle capture paths through install-hooks.
Hook install pattern. Local supported profiles default to host-native commands. Claude Code may use its supported Windows exec form (
command= realai-memory.exe,args= argv tokens forhook --event ...); other agents use native single command strings according to their hook schema. PowerShell/Git Bash script bundles are compatibility fallbacks and do not enforce capture-policy v1. Remote-only/Docker script installs still use the two-step path: (1)docker cpbundled scripts to your home dir, (2)docker run --rm install-hooksrenders the config snippet. OpenClaw, OpenCode, OMP, and Pi are different: they use generated TypeScript plugin/extension files, so no shell-script extraction is needed for those clients.
OpenAI Codex
# MCP snippet (merge into ~/.codex/config.toml):
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client codex \
--server-url "http://homelab:49374/mcp" \
--auth-token "$TOKEN"
# Hooks — extract scripts + render config:
docker cp ai-memory:/usr/local/share/ai-memory/hooks ~/.ai-memory/
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent codex \
--hooks-dir ~/.ai-memory/hooks \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
Codex still does not expose a reliable true session-end hook. Its Stop hook is
captured as a turn/stop observation only; ai-memory does not treat it as
SessionEnd. When you need the final session summary, handoff, and
auto-improvement eligibility for the current project, run:
ai-memory finalize-session
# add --all to close every matching open Codex session in this workspace/project
Devin CLI
Devin uses ~/.devin/config.json for MCP servers and ~/.devin/hooks.v1.json
for lifecycle hooks by default. If you prefer one combined Devin config file,
pass --config-file ~/.devin/config.json to install-hooks; ai-memory then
merges the hook entries under that file's hooks key.
ai-memory install-mcp --client devin --apply \
--server-url "http://homelab:49374/mcp" \
--auth-token "$TOKEN"
ai-memory install-hooks --agent devin --apply \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
ai-memory install-skills --agent devin
Devin's hook vocabulary is close to Claude Code's, with two important differences:
- Devin emits
PostCompactionafter compaction and includes asummaryfield; ai-memory records it aspost-compaction. - Devin does not expose subagent start/stop hooks, so ai-memory cannot capture nested subagent boundaries for Devin.
The SessionStart hook injects pending handoffs through Devin's
hookSpecificOutput.additionalContext. Real Devin SessionStart and
PostToolUse payloads may omit session_id and cwd; ai-memory now infers cwd
from DEVIN_PROJECT_DIR or the hook process working directory when the payload
omits it, and mints/reuses a per-host session id from hook state when necessary,
so those events are still captured. A payload-provided value always wins.
Kimi Code
Kimi Code keeps MCP servers in ~/.kimi-code/mcp.json and lifecycle hooks in
~/.kimi-code/config.toml; both move together when $KIMI_CODE_HOME is set.
The CLI also accepts --agent kimi as an alias. install-mcp writes the
server URL with a ?flavor=moonshot query because the Moonshot API rejects
root-level anyOf/oneOf/allOf in tool parameter schemas ("moonshot
flavored json schema") — the ai-memory server answers flavored requests with
flat schemas, and all other clients keep the upstream shape.
ai-memory install-mcp --client kimi-code --apply \
--server-url "http://homelab:49374/mcp" \
--auth-token "$TOKEN"
ai-memory install-hooks --agent kimi-code --apply \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
install-hooks merges [[hooks]] entries into config.toml, preserving the
provider/model settings the same file holds. Entries cover 10 events —
SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse,
PostToolUseFailure (Kimi Code reports tool failures separately from
successful calls; it reuses the post-tool-use handler), Stop,
SubagentStart, SubagentStop, and PreCompact — and default to
native ai-memory hook --event … --agent kimi-code commands on local installs
(local spool plus batched delivery, capture-policy v1 enforced); the staged
script bundle under ~/.local/share/ai-memory/hooks/kimi-code/ is the
compatibility fallback (fire-and-forget POSTs to /hook). A pending handoff
is injected at UserPromptSubmit through the hook's stdout, which Kimi Code
appends to the model context as a user message before the turn; Kimi Code
fires SessionStart but discards that hook's stdout, so hooks installed by
an older release consumed handoffs without delivering them. Existing native
hook commands invoke the current ai-memory binary and pick up the corrected
delivery behavior on upgrade. Re-run
ai-memory install-hooks --agent kimi-code --apply only for a
script-fallback installation so its staged scripts are refreshed.
Kimi Code hook entries accept only event, matcher, command, and
timeout; extra fields make the whole config.toml fail to load, so prefer
install-hooks --apply over hand edits.
OpenCode
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client opencode \
--server-url "http://homelab:49374/mcp" \
--auth-token "$TOKEN"
# Plugin — write to ~/.config/opencode/plugins/ai-memory.ts.
# If you have the local wrapper installed, prefer `--apply`:
ai-memory install-hooks --agent opencode --apply \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
# Docker-only preview path; redirect only if you want to write the file yourself:
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent opencode \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
Restart OpenCode after installing or changing the plugin; plugins are loaded at startup.
Oh My Pi / OMP
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client omp \
--server-url "http://homelab:49374/mcp" \
--auth-token "$TOKEN"
# Extension — write to ~/.omp/agent/extensions/ai-memory.ts.
# If you have the local wrapper installed, prefer `--apply`:
ai-memory install-hooks --agent omp --apply \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
Restart OMP after installing or changing the extension; extensions are
loaded at startup. The ai-memory CLI accepts --client omp (or
--client oh-my-pi) for MCP and --agent omp (or --agent oh-my-pi)
for hooks; both target OMP's native .omp integration surface.
Pi
Pi does not read a native mcp.json. ai-memory supports Pi through one
generated TypeScript extension at ~/.pi/agent/extensions/ai-memory.ts; the
same file captures lifecycle events and bridges ai-memory's HTTP MCP tools into
Pi with pi.registerTool.
ai-memory install-hooks --agent pi --apply \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
# `install-mcp --client pi` prints this guidance instead of writing mcp.json:
ai-memory install-mcp --client pi --server-url "http://homelab:49374/mcp"
Restart Pi after installing or changing the extension. OMP / Oh My Pi remains
separate and continues to use .omp paths.
Bind mounts vs docker cp
The setup-agent subcommand does the extract + render in one shot
using a bind mount:
docker run --rm -v "$HOME/.ai-memory:/host" \
akitaonrails/ai-memory:latest \
setup-agent --agent claude-code --to /host/hooks \
--host-prefix "$HOME/.ai-memory/hooks" \
--server-url "http://homelab:49374" --auth-token "$TOKEN"
This works cleanly when the container user's UID matches the host
user's UID (e.g. the homelab where both are 1000). It fails on
rootless Docker and on hosts with userns-remap enabled - the
container can't write to a host directory that belongs to a UID
outside the user-namespace mapping.
The docker cp pattern recommended above sidesteps all of that
because docker cp is mediated by the docker daemon and outputs
files owned by the user running the command. Prefer it as the
default; reach for setup-agent only when your docker setup is
known not to remap UIDs.
Cursor, Gemini CLI, Claude Desktop, OpenClaw, Antigravity CLI, Grok Build CLI, Zero, VS Code Copilot
See docs/mcp-install.md for the per-client MCP
config file path and snippet, or one-shot it via:
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client cursor --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent cursor --auth-token "$TOKEN" \
--server-url "http://homelab:49374"
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client claude-desktop --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client gemini-cli --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent gemini-cli --auth-token "$TOKEN" \
--server-url "http://homelab:49374"
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client antigravity-cli --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent antigravity-cli --auth-token "$TOKEN" \
--server-url "http://homelab:49374"
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client grok --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent grok --auth-token "$TOKEN" \
--server-url "http://homelab:49374"
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client openclaw --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent openclaw --auth-token "$TOKEN" \
--server-url "http://homelab:49374"
docker run --rm akitaonrails/ai-memory:latest \
install-mcp --client vscode-copilot --auth-token "$TOKEN" \
--server-url "http://homelab:49374/mcp"
Cursor, Gemini CLI, Antigravity CLI, Grok Build CLI, and OpenClaw support both
install-mcp and install-hooks. Grok's install-mcp --client grok writes
$GROK_HOME/config.toml (default ~/.grok/config.toml); its hooks live under
$GROK_HOME/hooks (default ~/.grok/hooks). install-hooks --agent grok
captures lifecycle events.
Grok ignores SessionStart stdout, so handoffs must be accepted through MCP with
memory_handoff_accept when resuming. Claude Desktop and VS Code Copilot are MCP-only here,
so you'll need to nudge the model to call memory_query /
memory_handoff_accept itself.
For clients with install-hooks support, the capture path handles
handoff injection at session start or the client's closest equivalent, except
for Grok's (and Zero's) no-stdout SessionStart behavior (Antigravity CLI uses PreInvocation).
Installing hooks without docker
If you only need to use ai-memory from a machine (i.e. that machine doesn't run the server), the curl installer pulls shell hook scripts straight from GitHub for shell-hook agents:
curl -sSL https://raw.githubusercontent.com/akitaonrails/ai-memory/main/scripts/install-hooks.sh \
| bash -s -- --agent claude-code
# Then render the JSON config (still wants `ai-memory` somewhere —
# either via docker as a one-shot, or installed locally):
docker run --rm akitaonrails/ai-memory:latest \
install-hooks --agent claude-code \
--hooks-dir "$HOME/.ai-memory/hooks" \
--server-url "http://homelab:49374" \
--auth-token "$TOKEN"
The curl script installer supports
--agent claude-code|codex|cursor|gemini-cli|antigravity-cli|grok|opencode|openclaw|omp|oh-my-pi|pi
and --to <dir>; --help prints the full flag list. OpenCode,
OpenClaw, OMP / Oh My Pi, and Pi do not need script extraction because
install-hooks generates TypeScript plugin/extension files for them
instead. For Pi, the generated extension also provides the MCP bridge.
This path is friction-free when:
- You have curl + bash but not docker
- You don't need to run a local ai-memory server (you're a client of a homelab/remote ai-memory)
Hook command paths across a container boundary
install-hooks --apply stages the hook scripts into the data dir and
writes their absolute paths into the agent's config. When the CLI runs
inside a container but the agent runs on the host, those staged paths
would be container paths the host can't see. Set
AI_MEMORY_HOOKS_HOST_ROOT to the host directory that the staged
hooks/ tree is mounted from and the rendered config uses
<host-root>/<agent>/… command paths instead. The bundled docker
wrappers (bin/ai-memory, bin/ai-memory.ps1) forward this variable
automatically; you only set it by hand for custom container setups.
Running ai-memory without docker
Most users should stick to the docker wrapper from the Quick start. On macOS,
tagged releases also publish native ai-memory-macos-aarch64.tar.gz and
ai-memory-macos-x86_64.tar.gz archives when you only need the client CLI.
Build from source only when hacking on ai-memory itself or running on a platform
docker doesn't support.
git clone https://github.com/akitaonrails/ai-memory ~/.ai-memory
cd ~/.ai-memory
cargo build --release --workspace
./target/release/ai-memory init # one-time
./target/release/ai-memory serve --transport http \
--bind 127.0.0.1:49374 # MCP + hook HTTP server
Data dir defaults to ~/.local/share/ai-memory on Linux,
~/Library/Application Support/ai-memory on macOS, and the platform
local-data directory on Windows, typically
%LOCALAPPDATA%\ai-memory. Override with AI_MEMORY_DATA_DIR=/path.
To require bearer-token auth, set AI_MEMORY_AUTH_TOKEN in the
server's environment.
Optional serve flags
The serve subcommand also accepts:
| Flag | Env var | What it does |
|---|---|---|
--enable-web |
AI_MEMORY_ENABLE_WEB=true |
Mount the read-only web browser + /api/v1 JSON API. |
--base-path /wiki |
AI_MEMORY_BASE_PATH |
Host the entire HTTP surface (/mcp, /hook, /admin/*, /api/v1, /web) under a configurable subpath — useful behind a reverse proxy sharing a hostname. . and .. segments are rejected; unsafe chars cause a fallback to root with a warning. See docs/https-via-proxy.md. |
--web-slug /web |
AI_MEMORY_WEB_SLUG |
Where the web UI mounts within the base-path. Default /web; set to / to mount the UI at the base-path root. |
--web-ui-dir <path> |
AI_MEMORY_WEB_UI_DIR |
Serve a custom SPA from <path> instead of the built-in browser. ai-memory injects <base href> and <meta name="ai-memory-base-path"> so the SPA can build relative URLs and API calls under the configured prefix. |
--cors-allow-origin <origin> |
AI_MEMORY_CORS_ALLOW_ORIGINS (CSV) |
Allow listed origins to call /api/v1. Layer is scoped only to that route — /mcp, /hook, /admin, and /web remain origin-locked. |
| (config only) | AI_MEMORY_HOOK_RATE_PER_SEC, AI_MEMORY_HOOK_RATE_BURST |
Optional per-actor/session hook ingest token bucket. Unset/0 rate disables it; burst defaults to the rate (minimum one token when enabled). |
On macOS, see docs/macos.md; use the archive matching your
architecture: aarch64 for Apple Silicon, x86_64 for Intel. On Windows, see
docs/windows.md.
The short version: run the install commands from the same environment that
launches the agent. WSL2-launched agents need WSL paths and POSIX .sh hooks.
Native Windows agents can use the tagged ai-memory-windows-x86_64.zip, the
Docker Desktop wrapper, or a source build. Native Claude Code uses Claude exec
form with a real ai-memory.exe by default; the Windows Docker wrapper renders
other native Windows script-hook agents through encoded PowerShell .ps1
fallback commands.
When run from source, install-hooks finds the bundled scripts in
the repo's hooks/ automatically. Extracted release archives also
auto-discover the sibling hooks/ bundle beside the ai-memory binary:
./target/release/ai-memory install-hooks --agent claude-code --auth-token "$TOKEN"
(No need for setup-agent in this case - the scripts already live
at the right host path.)
LLM provider tiers
ai-memory works in three intensity tiers:
| Tier | What you get | Env vars | Cost |
|---|---|---|---|
| Zero-LLM (default) | FTS5 search, rule-based session summaries, auto-handoffs from prompt + tool-call history | (none) | $0 |
| + LLM consolidation | LLM rewrites session pages as coherent narratives; PreCompact checkpoints; LLM-driven contradiction lint | AI_MEMORY_LLM_PROVIDER=anthropic + ANTHROPIC_API_KEY |
~$0.01–0.05 / session |
| + Anthropic via subscription | Same LLM features using a Claude Pro/Max subscription instead of an API key | AI_MEMORY_LLM_PROVIDER=anthropic-oauth + ANTHROPIC_OAUTH_TOKEN |
Uses your Claude subscription |
| + ChatGPT/Codex OAuth | Same LLM features using a ChatGPT Pro/Plus login instead of an OpenAI Platform key | AI_MEMORY_LLM_PROVIDER=openai-oauth + ai-memory auth login openai-oauth |
Uses your ChatGPT subscription |
| + GitHub Copilot | Same LLM features using a GitHub Copilot subscription | AI_MEMORY_LLM_PROVIDER=copilot + ai-memory auth login copilot or COPILOT_GITHUB_TOKEN |
Uses your Copilot subscription |
| + Hybrid retrieval | RRF over FTS5 + vector cosine similarity. Better recall on paraphrased queries | AI_MEMORY_EMBEDDING_PROVIDER=openai + OPENAI_API_KEY |
~$0.0001 / page on backfill |
Recommended models (chosen as defaults)
If you set only the provider, ai-memory picks a sensible default:
| Setting | Default | Why |
|---|---|---|
AI_MEMORY_LLM_PROVIDER=anthropic |
claude-haiku-4-5 |
Recommended default. Best balance of speed, restraint, and classification quality. Not a reasoning model. Consistently classifies durable project rules as kind: rule. |
AI_MEMORY_LLM_PROVIDER=anthropic-oauth |
claude-sonnet-4-6 |
Anthropic via Claude subscription. Run claude setup-token once; set ANTHROPIC_OAUTH_TOKEN (or CLAUDE_CODE_OAUTH_TOKEN). No ANTHROPIC_API_KEY needed. Same /v1/messages endpoint, Bearer token auth. |
AI_MEMORY_LLM_PROVIDER=openai |
gpt-5.4-mini |
Cheaper + faster alternative. Same parse reliability; mild over-classification on thin sessions. |
AI_MEMORY_LLM_PROVIDER=openai-oauth |
gpt-5.5 |
ChatGPT/Codex backend. Run ai-memory auth login openai-oauth once; ai-memory stores the refresh token in <data_dir>/auth.json and refreshes access tokens automatically. |
AI_MEMORY_LLM_PROVIDER=copilot |
gpt-5.5 |
GitHub Copilot Chat backend. ai-memory stores a GitHub user token in <data_dir>/auth.json, exchanges it for a short-lived Copilot API token, and refreshes before expiry. |
AI_MEMORY_LLM_PROVIDER=gemini |
gemini-2.5-flash |
Google's hosted option with a generous free tier. ai-memory disables Gemini 2.5 Flash's default dynamic thinking so hidden thought tokens do not truncate strict JSON. Set GEMINI_API_KEY (or GOOGLE_API_KEY). |
AI_MEMORY_LLM_PROVIDER=opencode |
claude-sonnet-4-6 |
OpenCode Zen/Go cloud API — OpenAI-compatible endpoint at opencode.ai/zen/go/v1. Set OPENCODE_API_KEY (key from opencode.ai/auth). Alias: opencode-zen. |
AI_MEMORY_EMBEDDING_PROVIDER=openai |
text-embedding-3-small (1536-dim) |
5× cheaper than -3-large with marginal recall loss. |
AI_MEMORY_EMBEDDING_PROVIDER=openai + AI_MEMORY_EMBEDDING_BASE_URL=https://openrouter.ai/api/v1 |
openai/text-embedding-3-small via OpenRouter |
Reuses LLM_API_KEY or OPENAI_API_KEY with the OpenAI-compatible embedding client. |
AI_MEMORY_EMBEDDING_PROVIDER=voyage |
voyage-3 (1024-dim) |
Voyage's current general-purpose recommendation. |
AI_MEMORY_EMBEDDING_PROVIDER=google / gemini |
gemini-embedding-001 (768-dim) |
Google-hosted embeddings via embedContent. Set GEMINI_API_KEY (or GOOGLE_API_KEY). |
What we don't recommend: reasoning-mode models (Claude with extended thinking, GPT-o3, Gemini "thinking" variants) — they burn token budget on internal reasoning and hang or emit empty responses with the strict-JSON consolidation prompt. Turn reasoning off if you must use one.
Anthropic via Claude subscription (OAuth)
Warning
Unofficial and against Anthropic's usage policies — use at your own risk. Anthropic provides no public OAuth API for the Claude Pro/Max subscription; this reuses the
claude setup-tokencredential against/v1/messages, which is not a supported or sanctioned integration. Anthropic's terms reserve subscription (Claude Code) access for interactive use, and using it as an automated API backend may breach those terms and could get your account rate-limited, flagged, or banned. The header recipe is also undocumented and can change without notice. If you want a supported path, use theanthropicprovider with a real Platform API key. We ship this purely as an opt-in convenience and make no guarantees about it.
anthropic-oauth is for Claude Pro/Max subscribers who want to use their
existing subscription instead of an Anthropic Platform API key. It hits the
same /v1/messages endpoint as the anthropic provider — only the auth
headers differ (Bearer token + anthropic-beta: oauth-2025-04-20).
# Obtain a token once using the Claude Code CLI:
claude setup-token
# Then export it (the CLI may also write CLAUDE_CODE_OAUTH_TOKEN automatically):
export ANTHROPIC_OAUTH_TOKEN=<paste token here>
export AI_MEMORY_LLM_PROVIDER=anthropic-oauth
ai-memory serve
For Docker, pass the token as an env var:
docker run -d --name ai-memory \
-p 127.0.0.1:49374:49374 \
-v ai-memory-data:/data \
-e AI_MEMORY_LLM_PROVIDER=anthropic-oauth \
-e ANTHROPIC_OAUTH_TOKEN=<token> \
akitaonrails/ai-memory:latest
Both ANTHROPIC_OAUTH_TOKEN and CLAUDE_CODE_OAUTH_TOKEN are accepted;
ai-memory checks ANTHROPIC_OAUTH_TOKEN first.
Tip
Pick a small, fast model. ai-memory's LLM work — session consolidation, lint, and explore — is summarisation/extraction, not hard reasoning, so a Haiku-class model is plenty: faster, cheaper, and far easier on subscription rate limits than Sonnet/Opus. Set e.g.
AI_MEMORY_LLM_MODEL=claude-haiku-4-5. Save the high-effort thinking models for your actual coding agent.
OpenAI OAuth / Codex
openai-oauth is for ChatGPT Pro/Plus/Codex accounts. It does not use
OPENAI_API_KEY and it does not call api.openai.com; requests go to the
ChatGPT/Codex Responses backend with a refreshable OAuth token.
For the Docker quick start wrapper, this writes into the same named volume the
server mounts at /data:
ai-memory auth login openai-oauth
docker run -d --name ai-memory \
-p 127.0.0.1:49374:49374 \
-v ai-memory-data:/data \
-e AI_MEMORY_LLM_PROVIDER=openai-oauth \
akitaonrails/ai-memory:latest
For a remote Docker host, run the login on that host against the same container or data volume:
docker exec -it ai-memory ai-memory auth login openai-oauth
Use ai-memory auth status to check whether a token is present and
ai-memory auth logout openai-oauth to remove it.
Tip
Pick a small, fast model. Consolidation / lint / explore are summarisation tasks, not hard reasoning — a mini-class model is plenty and is much easier on subscription rate limits. Set e.g.
AI_MEMORY_LLM_MODEL=gpt-5-mini(thegpt-5.5default works but is overkill for this workload). Reserve the high-effort reasoning models for your coding agent.
GitHub Copilot
copilot uses a GitHub user token, then exchanges it for a short-lived Copilot
API token through https://api.github.com/copilot_internal/v2/token. The raw
GitHub token is never sent to api.githubcopilot.com.
For the Docker quick start wrapper:
ai-memory auth login copilot
docker run -d --name ai-memory \
-p 127.0.0.1:49374:49374 \
-v ai-memory-data:/data \
-e AI_MEMORY_LLM_PROVIDER=copilot \
akitaonrails/ai-memory:latest
For a remote Docker host, run the login against the same data volume:
docker exec -it ai-memory ai-memory auth login copilot
Non-interactive deploys can set COPILOT_GITHUB_TOKEN instead. ai-memory also
accepts GH_TOKEN and GITHUB_TOKEN when running natively; prefer the explicit
COPILOT_GITHUB_TOKEN in Docker so you do not pass a broad token by accident.
Advanced users with a pre-minted Copilot API token can set
GITHUB_COPILOT_API_TOKEN and optionally COPILOT_API_URL.
auth login copilot defaults to GitHub Copilot's public device-flow client id.
Pass --client-id or set AI_MEMORY_COPILOT_CLIENT_ID if you operate your own
OAuth app.
OpenAI-compatible providers (Ollama / vLLM / LM Studio / hosted APIs)
docker run -d --name ai-memory \
-p 49374:49374 \
-v ai-memory-data:/data \
-e AI_MEMORY_AUTH_TOKEN="$TOKEN" \
-e AI_MEMORY_LLM_PROVIDER=openai-compat \
-e AI_MEMORY_LLM_BASE_URL=http://host.docker.internal:11434/v1 \
-e AI_MEMORY_LLM_MODEL=qwen2.5-coder:14b \
akitaonrails/ai-memory:latest
There is no safe default model for openai-compat; the env var is
required. For OpenRouter (Kimi, DeepSeek, etc.):
-e AI_MEMORY_LLM_PROVIDER=openai-compat
-e AI_MEMORY_LLM_BASE_URL=https://openrouter.ai/api/v1
-e AI_MEMORY_LLM_MODEL=moonshotai/kimi-k2.6
-e LLM_API_KEY=sk-or-v1-...
Atlas Cloud uses the same provider; no Atlas-specific ai-memory provider is needed. Pass its API key through the generic compatibility credential:
-e AI_MEMORY_LLM_PROVIDER=openai-compat
-e AI_MEMORY_LLM_BASE_URL=https://api.atlascloud.ai/v1
-e AI_MEMORY_LLM_MODEL=qwen/qwen3.5-flash
-e LLM_API_KEY="$ATLASCLOUD_API_KEY"
Replace the model with another current Atlas model id when needed. ai-memory does not select a default for hosted compatibility endpoints.
Modern Ollama, vLLM, LM Studio, llama.cpp, and gateway endpoints may honour
OpenAI-style response_format=json_schema. If the tolerant default parser fails
with errors such as did not contain a JSON object or serde: unknown variant,
try strict compat mode:
-e AI_MEMORY_LLM_COMPAT_STRICT=true
Strict mode is opt-in. ai-memory sends the schema-constrained request first and falls back to the tolerant parser only when that raw strict call fails.
Subcommand reference
Two ways to invoke a subcommand against the docker deploy:
# A) Against the running container (stateful: status, search, backup,
# checkpoints, restore-page, audit-contamination, forget-sweep, lint, embed).
docker exec ai-memory ai-memory status --json
docker exec ai-memory ai-memory search "karpathy"
docker exec ai-memory ai-memory backup --to /data/snapshot.tar.gz
# B) One-shot, no running container needed for pure-stdout helpers
# (generate-auth-token, completions, install-mcp, install-hooks, setup-agent,
# llm-test).
# Auth login is stateful: use docker exec against the running container or
# the wrapper so it writes into the same data volume as the server.
docker run --rm akitaonrails/ai-memory:latest generate-auth-token
docker run --rm akitaonrails/ai-memory:latest completions zsh
docker run --rm akitaonrails/ai-memory:latest install-mcp --client cursor
docker run --rm akitaonrails/ai-memory:latest --help # full subcommand tree
| Subcommand | Pattern | What it does |
|---|---|---|
serve |
docker compose up -d (already done) |
Run the HTTP MCP server |
run [harness] [args...] |
host wrapper or native binary | Opt into one managed cross-harness workstream; omit the harness to resume the newest usable local session, or name Claude Code, Codex, OpenCode, Pi, Crush, or OMP explicitly; exact --yolo is wrapper-owned and other native arguments pass through |
workstream-search [query] |
managed child or thin HTTP client | Search the complete visible managed-workstream ledger; the managed child receives its workstream id automatically |
status |
docker exec |
Counts, paths, derived-index diagnostics, and passive LLM/embedding provider health |
search "<query>" |
docker exec |
Wiki search with FTS5 + graph/vector RRF |
write-page |
docker exec |
Manual page write (atomic + indexed) |
backup --to / restore --from |
docker exec |
Snapshot or restore the data dir |
checkpoints / restore-page |
docker exec |
List wiki git checkpoints or restore one markdown page and reindex it |
audit-contamination |
docker exec |
Read-only structural audit for likely cross-project contamination |
forget-sweep / lint / embed |
docker exec |
Manual maintenance; sweep + lint also run on the server schedule by default |
commit -m "…" |
docker exec |
Stage + commit the wiki tree |
reset --confirm |
docker exec |
Wipe data (refuses while siblings alive) |
generate-auth-token |
docker run --rm |
Print a random hex bearer token |
auth login openai-oauth |
same data volume as the server | Store a ChatGPT/Codex OAuth refresh token for the optional openai-oauth LLM provider |
auth login copilot |
same data volume as the server | Store a GitHub token for the optional copilot LLM provider |
auth login oidc-device |
same developer data dir as native hooks and thin-client CLI commands | Store a per-developer OIDC device token for native hook authentication and HTTP CLI fallback auth |
install-mcp --client |
docker run --rm |
MCP-config snippet per client |
install-hooks --agent |
docker run --rm |
Hook-config snippet for an existing hooks dir |
setup-agent --agent --to --host-prefix |
docker run --rm -v |
Extract bundled scripts + print config (one-shot) |
install-instructions [--target] [--print] [--no-skills] |
same host environment used for the agent prompt files | Install or update the slim CLAUDE.md / AGENTS.md routing block and, by default, the managed ai-memory Agent Skills |
install-skills [--scope] [--agent] |
same host environment used for the agent skill dirs | Install or update only the managed ai-memory Agent Skills |
uninstall --apply |
same host environment used for install | Remove only ai-memory-owned hooks, MCP entries, instruction blocks, managed skill files, and generated plugin files after content/marker validation. Use --mcp-url for custom MCP endpoints and --mcp-name only to narrow removal. |
llm-test --provider … |
docker run --rm -e … |
Smoke-test an LLM provider |
completions <shell> |
docker run --rm or native binary |
Print a bash/zsh/fish/PowerShell/elvish completion script; see shell-completions.md |
Managed routing snippets and Agent Skills
ai-memory's routing install is agent-facing prompt packaging. It does not add a
runtime skill router, and SKILL.md files are not durable memory pages. The
wiki remains the durable source of truth.
ai-memory install-instructions now writes two managed prompt artifacts by
default:
- A slim instruction block in
CLAUDE.md,AGENTS.md, or the file passed with--target. The block is bounded by<!-- ai-memory:start -->and<!-- ai-memory:end -->delimiters that appear alone on their own lines. - Managed ai-memory Agent Skills containing the detailed tool-routing guidance.
Re-running the command is safe. If a project still has the old long ai-memory
block between line-anchored markers, the refresh replaces that block in place
with the slim snippet, leaves unrelated instructions before and after it alone,
and writes a timestamped .bak-* backup before changing an existing file.
Managed skill files contain an ai-memory ownership marker; same-name user skills
without that marker are preserved unless you explicitly force replacement.
install-instructions --print previews only the instruction snippet; run
install-skills --print when you want to preview the managed skill payloads.
install-instructions flags for skills:
| Flag | Meaning |
|---|---|
--no-skills |
Refresh only the markered instruction block. |
--skills-scope <scope> |
Choose project-local or user-global skill roots. Values: project, global. Defaults to project. |
--skills-agent <agent> |
Choose .claude/skills, .agents/skills, .devin/skills, .grok/skills, or both Claude/Agents roots. Values: claude-code, agents, devin, grok, both. By default, CLAUDE.md targets imply claude-code, AGENTS.md targets imply agents, and both instruction files imply both. |
--skills-target-dir <dir> |
Write managed skill directories below an explicit root instead of inferring from scope and agent. |
--skills-force |
Replace unmanaged same-name skills during install-instructions; without it, they are left untouched and the command exits with an actionable error. |
Use install-skills when the instruction block is already right and only the
Agent Skill files need a refresh:
ai-memory install-skills
ai-memory install-skills --scope global --agent agents
ai-memory install-skills --scope global --agent devin
ai-memory install-skills --scope global --agent grok
ai-memory install-skills --agent both --print
ai-memory install-skills --target-dir .custom/skills --force
install-skills flags:
| Flag | Meaning |
|---|---|
--scope <scope> |
Install into this project or the current user's global skill roots. Values: project, global. Defaults to project. |
--agent <agent> |
Install into Claude Code's skill root, the cross-agent skill root, Devin's skill root, Grok's skill root, or both Claude/Agents roots. Values: claude-code, agents, devin, grok, both. Defaults to claude-code. |
--target-dir <dir> |
Write managed skill directories below an explicit root; --scope and --agent are ignored. |
--print |
Print target paths and SKILL.md contents without writing files. |
--force |
Replace unmanaged same-name skills; without it, user-authored same-name skills are preserved. |
Default skill target roots:
| Scope | --agent claude-code |
--agent agents |
--agent devin |
--agent grok |
|---|---|---|---|---|
project |
.claude/skills |
.agents/skills |
.devin/skills |
.grok/skills |
global |
~/.claude/skills |
~/.agents/skills |
Windows: %APPDATA%\devin\skills; non-Windows: ~/.devin/skills |
$GROK_HOME/skills (default ~/.grok/skills) |
Each managed skill is written as <root>/<skill-name>/SKILL.md.
ai-memory uninstall --only skills --apply removes managed skill files only
from the default project/global roots shown above, after validating the
ai-memory ownership marker. If you installed with --target-dir or
--skills-target-dir, clean up that custom root manually.
Data dir inside the container is /data (mounted via the compose
volume). Outside docker, override with AI_MEMORY_DATA_DIR=/path.
Scheduled maintenance is configured in [maintenance] in config.toml.
By default, rule-based lint and forget sweep run daily outside hook
latency across every existing workspace/project. Embedding backfill is
supported but defaults to off because it can call a paid provider; if you
enable embedding_backfill_interval_secs after configuring an embedder,
each scheduled tick backfills every existing workspace/project and may
increase provider usage accordingly.
Forget sweep and rule-based lint persist their last successful completion. On restart, a job that is not due waits only its remaining interval; a never-run or overdue job runs once after a bounded startup delay. Failed runs are not recorded as successful and retry after that bounded delay. Embedding backfill remains opt-in and keeps its interval-only behavior (no startup catch-up).
Bootstrap mid-project
When you adopt ai-memory in a project that's already been around for
a while, the wiki starts empty. ai-memory bootstrap ingests the
project's existing history into seed pages so the first session has
warm context.
cd /path/to/project
ai-memory bootstrap
If you installed the Docker wrapper from the quick start and started the
server on 127.0.0.1:49374, the wrapper automatically reaches that host
loopback server from its short-lived helper container. Set
AI_MEMORY_SERVER_URL=http://<server>:49374 only when the server is
remote or uses a custom host/port.
What gets ingested by default:
| Source | Priority (dropped first when over budget) |
|---|---|
CLAUDE.md / AGENTS.md (project rules) |
never dropped |
README.md at the repo root |
very-late |
docs/**/*.md |
late |
| Substantive git commits (body >120 chars OR conventional-commit prefix) | mid |
Module-level //! doc-comments in **/*.rs |
first to drop |
Flags:
--repo-path <PATH> (default: git rev-parse --show-toplevel)
--workspace <NAME> (default: "default")
--project <NAME> (default: derived from cwd — main repo root's
basename via `git rev-parse --show-toplevel`,
or basename(cwd) when no repo is found.
"scratch" only as a defensive fallback for
hook events with no usable cwd.)
--max-input-tokens N (default: 150000; total source budget after prune)
--chunk-input-tokens N (default: 24000; per LLM call; 0 = single call)
--since "30 days ago" (git log filter; supports "N days/months/years ago" + YYYY-MM-DD)
--exclude-git (skip commit history)
--exclude-readme (skip README)
--exclude-docs (skip docs/**/*.md)
--exclude-code (skip Rust module headers)
--dry-run (collect + estimate but don't call LLM or write)
--force (re-bootstrap, overwrites the prior manifest)
Cost. With Kimi 2.6 via OpenRouter ($0.73/$3.49 per M):
- 50k input tokens cap → ~$0.04 worst case input
- 1-2k generated tokens → ~$0.007 output
- Total: well under $0.20 per run.
Idempotency. The first run produces a per-project bootstrap.md
manifest (at <wiki>/<workspace>/<project>/bootstrap.md) listing every
page generated + a one-paragraph rationale. Re-running without --force
errors out. Delete the manifest (and the generated pages) if you want a
clean re-bootstrap.
Dry-run first. Always worth doing before the real call to see which sources would actually be sent + how many tokens that represents. Output is JSON to stdout.
ai-memory bootstrap --dry-run
{
"sources_collected": 117,
"sources_sent": 22,
"sources_dropped": 95,
"estimated_input_tokens": 48760,
"pages_written": [],
"rationale": "(dry-run; LLM not invoked)",
"dry_run": true,
"llm_chunks": 1
}
Large repos (e.g. years of git history) are pruned client-side before
POST, then processed in sequential LLM chunks so provider context limits
are not exceeded. The CLI logs llm_chunks in dry-run and the final
outcome.
Caveat: LLM-fabricated detail. A bootstrap run can produce
plausible-but-wrong pages (the LLM doesn't know your project, it's
inferring from git history). The wiki is git-versioned precisely so
this is recoverable: review what landed, docker exec ai-memory git -C /data/wiki diff HEAD~1, and revert if it's off.
Logs and read-only sandboxes
The CLI and server write daily-rolling logs to <data_dir>/logs/
(~/.local/share/ai-memory/logs/ by default). When that location is not
writable — sandboxes like ai-jail
mount $HOME read-only or as throwaway tmpfs — ai-memory degrades instead
of failing: it falls back to the OS temp dir, then to stderr-only logging,
printing the exact path that failed at each step. Commands keep working
either way. To keep durable file logs (and durable hook spooling) inside a
sandbox, map the data dir read-write, e.g. ai-jail --rw-map ~/.local/share/ai-memory ….
Operating without auth
For local-only / single-machine deploys you can skip the bearer token:
docker run -d --name ai-memory \
-p 127.0.0.1:49374:49374 \
-v ai-memory-data:/data \
akitaonrails/ai-memory:latest
Notice the bind: 127.0.0.1:49374, not 0.0.0.0:49374. This is the
critical pairing - no bearer token AND loopback only is the only
safe combination. The startup log will warn loudly if you bind to a
LAN address without setting AI_MEMORY_AUTH_TOKEN.
Then wire up the agent CLI. Both commands default to no auth and
http://127.0.0.1:49374 - no extra flags needed for the local case:
ai-memory install-mcp --client claude-code --apply
ai-memory install-hooks --agent claude-code --apply
The installed Docker wrapper runs CLI commands inside a short-lived
helper container. For local loopback servers, it automatically bridges
that helper back to the host's 127.0.0.1:49374, so ai-memory status,
ai-memory search, and ai-memory bootstrap work with the same default
URL as the generated agent config.
SELinux-enforcing hosts
On SELinux-enforcing Linux systems such as Fedora, RHEL, and openSUSE, normal
home-directory labels can prevent the helper container from writing agent
config even when its UID and GID match the host user. The wrapper checks both
the host enforcement mode and Docker's advertised security options. For the
short-lived helper commands that write host files (install-*, setup-agent,
uninstall, and backup), it adds --security-opt label=disable; thin-client
commands remain confined. This relaxes SELinux label confinement only for that
trusted helper invocation. It does not modify the long-lived ai-memory server,
which uses a Docker-managed named volume.
Do not add :z or :Z to the wrapper's whole $HOME bind. Docker's
bind-mount documentation
warns that relabeling system directories such as /home can make the host
inoperable. Docker documents label=disable in the
docker run security options.
ai-memory run is the exception: the current wrapper intercepts it and starts a
cached checksum-verified native client on the host, where harness executables
and session stores exist. It preserves an explicit remote
AI_MEMORY_SERVER_URL. If run logs data_dir=/data and then cannot find
codex, claude, or another harness executable, refresh the stale wrapper with
ai-memory upgrade on that client machine.
Docker compose alternative
If you prefer compose, clone the repo and run:
docker compose -f docker/docker-compose.yml up -d
The bundled compose file already has restart: unless-stopped, a
healthcheck, and the named volume wired up. Agent setup is the same as
the regular Docker path.
Keeping ai-memory up to date
The wrapper checks Docker Hub at most once every 24 hours and prints a one-line warning when a newer image is available. Upgrade with:
ai-memory upgrade
The command self-upgrades the wrapper script, pulls the latest Docker
image, re-stages hook scripts under
~/.local/share/ai-memory/hooks/<agent>/ for configured agents, and
prints how to restart the server container so the new binary is used.
Re-running install-hooks --apply remains idempotent: ai-memory
replaces only the hook entries it owns and leaves unrelated hooks alone.
Set AI_MEMORY_NO_VERSION_CHECK=1 to silence the daily check, or
AI_MEMORY_WRAPPER_URL=<url> to pin wrapper self-upgrades to a fork or
tagged release.
When the upgraded server starts, it applies SQLite schema migrations and pending wiki-structure migrations automatically. No manual database reset or wiki rewrite is required for normal upgrades.
If the server runs on another host, ai-memory upgrade refreshes only
the local wrapper, local image, and local hook scripts. Redeploy the
remote server separately with bin/deploy or docker compose pull && docker compose up -d in that deploy directory.
Inside ai-jail or another bwrap sandbox, the wrapper is usable from the
sandbox, but run install-* commands outside the sandbox because they
write to ~/.local/share/ai-memory/hooks/.
See also
docs/deploy.md- homelab deploy walkthrough (bin/deploy, cloudflared TLS, env-file management)docs/usage.md- handoffs, proactive querying, web UI, slim routing snippet + managed Agent Skills, migration from other memory tools, and raw-wiki inspectiondocs/mcp-install.md- per-client MCP config reference for every client in the README Support Matrixdocs/ARCHITECTURE.md- what's actually running inside ai-memory