On this page
Archivum documentation
Local-first memory for coding agents: plain files you own, a background “dream” pass using your own LLM key, review before anything changes.
Quickstart
Archivum is local-first memory for coding agents. Everything lives as plain files on your machine; there is no account and no hosted service. Requires Node 22 or newer.
- Run init. It detects Claude Code (
~/.claude) and Codex (~/.codexorcodexon your PATH) and wires up whatever it finds.
npx archivum init
What init changes
- Claude Code: merges a
SessionStartand aStophook into~/.claude/settings.json(created if missing). Before the first change it backs the file up tosettings.json.archivum-bak. Existing hooks are never removed and running init twice does not add the hooks twice. It also registers the MCP server withclaude mcp add archivum -- npx -y archivum-cli mcp, or prints that exact command if theclaudebinary is not found. - Codex CLI: runs
codex mcp add archivum -- npx -y archivum-cli mcp, or prints the command and the[mcp_servers.archivum]TOML ifcodexis not found. - Nothing else. Preview with
npx archivum-cli init --dry-run; limit it with--claude-codeor--codex.
Your first session
Start your agent as usual, inside a project directory. At session start the hook injects a small digest of that project's memory (empty at first, so nothing is injected). The agent can call the MCP tools such as remember and recall. When the session stops, the hook saves the transcript, with secrets scrubbed, to your Archivum home as a pending transcript. You can also add notes yourself:
archivum remember "Run tests with npm run test:unit, not npm test"
archivum recall "how do I run the tests"
archivum status
Dream
Once a few sessions have piled up, consolidate them into the wiki. Dreaming uses your LLM key (see Dreaming).
export ANTHROPIC_API_KEY="sk-ant-..."
archivum dream
It prints how many transcripts and notes it selected plus a rough token estimate, then asks Proceed? [y/N]. Nothing is written to your live wiki yet: the result is a proposal.
Review and apply
archivum proposals
archivum diff
archivum apply # or: archivum reject
apply writes each changed file to the live wiki, but skips any file you changed since the dream started (and lists it). Every write is a version you can restore.
Concepts
The design is inspired by Anthropic's article The components of agent memory. Archivum is an independent project and is not affiliated with Anthropic; this page makes no claims about benefits beyond what is described here.
The four layers
| Layer | What it is | Where |
|---|---|---|
| Transcripts | Append-only record of a session (user, assistant, tool events), secrets scrubbed. Raw material for dreaming. | transcripts/<id>.json |
| Notes | Short memories added by an agent (remember) or you (archivum remember). | notes.jsonl |
| Wiki | Small linked markdown files, organised by dreaming and editable by you, with an _index.md table of contents. | wiki/ |
| Context | The top layer: the index, kept small and injected at session start (about 4,096 characters by default; the Claude Code hook caps it at 10,000). | wiki/_index.md |
Space = project
Memory is partitioned into spaces. A space is chosen by --space X, otherwise $ARCHIVUM_SPACE, otherwise the cwd's folder name (characters outside A-Za-z0-9_.- become -, at most 64 characters, fallback default). In practice one project is one space and projects do not see each other's memory.
What lives where
- Everything is under
$ARCHIVUM_HOME(default~/.archivum) on your disk. - Your agent only sees memory through the digest the hook injects and the MCP tools.
- Only
archivum dreamsends anything to an LLM, using the provider you configured.
On-disk layout
Per space, under <home>/spaces/<space>/:
wiki/ your live markdown pages; /quillon-tests.md is wiki/quillon-tests.md
_index.md the index (the context digest)
transcripts/ one file per recorded session
notes.jsonl one note per line
history/ a copy of every page each time it changed, plus a log
proposals/<id>/ each dream's staged wiki, waiting for your review
Folders inside wiki/ are allowed. All writes are atomic (temp file then rename).
Edit by hand or commit to git
The live wiki is ordinary markdown. Open it in your editor, fix a page, delete one, or run git init inside wiki/ and commit it. Hand edits are safe: if you change a page after a dream started, apply sees the page has changed and skips it rather than overwriting you. Changes made outside the CLI are not recorded in the history log; only writes made by apply, restore and write are.
History and restore
Each history entry has an operation (create, update, delete, rename, restore) and an actor (user, dream:<id> or restore).
archivum history
archivum history /quillon-tests.md
archivum restore /quillon-tests.md --version 3
CLI reference
One binary, archivum. Output is human-readable text. Install nothing: npx archivum-cli <command> works, or install the package globally.
init
| Flag | Meaning |
|---|---|
--claude-code | Configure Claude Code only. |
--codex | Configure Codex only. |
--all | Configure every supported client, detected or not. |
--dry-run | Print the actions without changing anything. |
--home D | Use D as the Archivum home. |
With no client flag, init configures every client it detects.
mcp, hook, log
archivum mcp [--space X]: stdio MCP server (see MCP server).archivum hook session-start|stop: Claude Code hook entry points, reading hook JSON on stdin (see hooks).archivum log [--file F | -] [--source S] [--id ID]: append a transcript from a JSON file or stdin, either{"events":[...]}or a bare array of events, for agents without hooks. Each event is{"role":"user|assistant|system|tool","content":"...","name"?,"ts"?}.archivum import omp [--dir D] [--session FILE] [--all] [--since DATE] [--space S]: store omp sessions as transcripts. omp keeps sessions as JSONL under~/.omp/agent/sessions(override with--dirorOMP_SESSIONS_DIR). By default it imports the sessions whose working directory is the current one;--alltakes every session (each into the space named after its working directory) and--sessiontakes one file. It is idempotent: the omp session id is the transcript id, so importing again after a session grew updates the same transcript and puts it back to pending. Thinking blocks are dropped, tool output is clipped to 4,000 characters, and known secret patterns are redacted.
remember, recall, context, status
archivum remember "text"
archivum recall "query" --limit 5
archivum context --max-chars 4096
archivum status
status prints the counts of notes, wiki pages and transcripts (pending and dreamed), proposals, the home path and the space.
dream
| Flag | Meaning |
|---|---|
--budget TOKENS | Token budget for the run. Refuses to start when the estimate exceeds it (the message suggests --since, --max-inputs or a larger budget). Default 3,000,000. |
--instructions "..." | Extra guidance for the organizer, e.g. what to prioritise. |
--since DATE | Only transcripts whose updated_at is at or after DATE (2026-11-01 or a full ISO timestamp). A bad date exits 2. |
--max-inputs N | At most N transcripts, 1 to 200. Default 50. |
--if-due | Dream only when due (see below). Tune with --min-pending N (default 3), --idle-minutes M (default 10) and --cooldown-hours H (default 6). |
--yes | Skip the Proceed? [y/N] prompt (required when there is no TTY). |
--dry-run | Show the selection and estimate only. |
--apply | Apply right after a successful, non-partial run. Off by default. |
Selects the oldest pending transcripts (at most 50, or the --max-inputs value, and 6,000,000 characters) and unconsolidated notes (at most 300).
--if-due is for schedulers. It exits 0 after printing one line, not due: <reason>, unless at least --min-pending transcripts are pending, the newest transcript was last updated at least --idle-minutes ago and the last dream (the newest proposal) is at least --cooldown-hours old. When due it behaves like a normal dream: --yes is still required without a terminal and the result is still a proposal to review.
proposals, diff, apply, reject
| Flag | Meaning |
|---|---|
archivum proposals | List proposals. |
archivum diff [id] | Plain-text diff of the latest (or given) proposal against the current live wiki. |
archivum apply [id] [--force] | Write the proposal to the live wiki. Without --force, files changed since the dream started are skipped and listed. |
archivum reject [id] | Discard a proposal. |
restore, history, retention
| Flag | Meaning |
|---|---|
archivum restore <path> [--version N] | Restore a wiki file from history. |
archivum history [path] | List history entries. |
archivum retention [--days 30] | Delete transcripts dreamed more than N days ago. Also runs at the end of dream and apply with the 30-day default. |
doctor
archivum doctor [--space X] [--json] is a read-only health check. It prints one line per check, PASS, WARN or FAIL, with a hint where there is something to do, and exits 0 unless a check fails (then 1). With --json it prints an array of {name, status, detail, hint}. It makes no network call and never prints your API key (only set or missing).
| Check | What it looks at |
|---|---|
| node | Node 22 or newer (FAIL otherwise). |
| home | $ARCHIVUM_HOME exists and is writable, or can be created (FAIL otherwise). |
| space files | Every transcripts/*.json, the lines of notes.jsonl and history/log.jsonl, state.json and proposals/*/proposal.json parse. FAIL with the count of unreadable ones. |
| claude hooks | When ~/.claude exists, settings.json has SessionStart and Stop commands containing archivum hook (WARN otherwise). |
| mcp (claude), mcp (codex) | Only if the binary is on PATH: <bin> mcp list (5 second timeout) mentions archivum. A failure is a WARN. |
| llm config | Provider is anthropic or openai (FAIL otherwise); key set; openai notes the default base URL and needs both models; anthropic notes the default models. A missing key or model is a WARN. Not tested against the network. |
| pending work | Pending transcripts and proposals awaiting review. |
Troubleshooting
- Start with
archivum doctor. It tells you which file is unreadable, which hook is missing and what the LLM configuration lacks. - A
FAILon space files means a file in the space is damaged. Archivum skips unreadable records instead of crashing, but cannot repair them: restore the named file from a backup or delete it. - A
WARNon claude hooks or mcp: runarchivum initagain (it is idempotent). - A dream that says the estimate is above the budget: use
--since DATEor--max-inputs Nto dream fewer inputs, or raise--budget. - To dream on a schedule (cron, Task Scheduler) run
archivum dream --if-due --yes. See dream.
Common flags, exit codes, environment
--space X selects the space for the commands that act on one. A missing API key or model for dream exits with code 2 and a message saying what to set; hook always exits 0. Other failures exit non-zero with a message on stderr.
| Variable | Meaning |
|---|---|
ARCHIVUM_HOME | Storage root. Default ~/.archivum. |
ARCHIVUM_SPACE | Space name when --space is not given. |
ARCHIVUM_LLM_PROVIDER | anthropic (default) or openai (any OpenAI-compatible endpoint). |
ARCHIVUM_LLM_API_KEY | API key. Falls back to ANTHROPIC_API_KEY (anthropic) or OPENAI_API_KEY (openai). |
ARCHIVUM_LLM_BASE_URL | Endpoint base URL. For openai the default is http://localhost:20128/v1. |
ARCHIVUM_ANALYZER_MODEL | Model for analyzers. Default claude-haiku-5-5 for anthropic; required for openai. |
ARCHIVUM_ORGANIZER_MODEL | Model for the organizer. Same defaults as above. |
ARCHIVUM_DEBUG | Set to 1 to print hook errors to stderr. |
Examples
# preview what init would do
npx archivum init --dry-run
# a one-off dream with a smaller budget and a hint
archivum dream --budget 500000 --instructions "Focus on build and test commands" --yes
# log a transcript from an agent without hooks
cat session.json | archivum log - --source my-agent --id session-42
# review, then apply
archivum diff
archivum apply
MCP server
archivum mcp is a stdio MCP server (newline-delimited JSON-RPC 2.0, protocol 2025-06-18). It logs to stderr only. The space comes from ARCHIVUM_SPACE or the working directory, or --space.
| Tool | Arguments | Purpose |
|---|---|---|
remember | content, metadata? | Save a short note. Secrets are scrubbed. |
recall | query, limit? | Search notes and wiki (BM25); returns kind, title, snippet, score. |
context | max_chars? | The short digest of this project's memory. |
forget | id | Delete one note (never wiki pages). |
list_notes | limit? | The newest notes with their ids. |
read_document | path | Read one wiki page. |
search_documents | query, limit? | Search wiki pages only. |
list_documents | prefix? | List wiki pages with size and description. |
related_documents | path | Pages this page links to (flagging broken links) and pages that link to it. |
document_history | path | When a page changed and who changed it (you or a dream). |
memory_status | none | Counts, what is waiting to be dreamed, proposals awaiting review, last dream. |
list_proposals | none | Dream proposals and their state. |
show_proposal | id? | The diff of a proposal, so the agent can summarise it for you. |
All tools are read-only except remember and forget. By design there is no tool to start a dream or to apply a proposal: those spend your tokens or change your wiki, so you do them with the CLI.
It also exposes one resource, archivum://context, with the current context digest.
Claude Code
claude mcp add archivum -- npx -y archivum mcp
Codex CLI
Either use the command, or add the equivalent to ~/.codex/config.toml (see the Codex MCP docs):
codex mcp add archivum -- npx -y archivum mcp
[mcp_servers.archivum]
command = "npx"
args = ["-y", "archivum-cli", "mcp"]
Other clients
Clients that take an mcpServers JSON block, such as Antigravity, Hermes Agent, omp and OpenClaw, generally accept this shape:
{
"mcpServers": {
"archivum": {
"command": "npx",
"args": ["-y", "archivum-cli", "mcp"]
}
}
}
Where that goes differs per client; see Antigravity, Hermes Agent, omp and Codex.
Claude Code hooks
archivum init merges these into ~/.claude/settings.json; you can also add them yourself:
{
"hooks": {
"SessionStart": [
{ "hooks": [ { "type": "command", "command": "npx -y archivum-cli hook session-start" } ] }
],
"Stop": [
{ "hooks": [ { "type": "command", "command": "npx -y archivum-cli hook stop" } ] }
]
}
}
- SessionStart reads the hook JSON from stdin and prints the memory digest as
additionalContextso Claude sees it. The output is capped at 10,000 characters. If the space has no context yet it prints nothing. - Stop reads the session JSONL at
transcript_path, converts it to events, scrubs secrets and savestranscripts/<session_id>.json. If the same session is saved again with new content it becomes pending again. It prints nothing. - The space is
ARCHIVUM_SPACEif set, otherwise the basename of the hook'scwd. - Hooks never fail your session: they always exit 0, and errors go to stderr only when
ARCHIVUM_DEBUG=1.
For agents without hooks, log transcripts yourself with archivum log and read context with archivum context or the MCP tools. omp has no hooks of this kind: run archivum import omp (for example before archivum dream) to turn its session files into transcripts.
Dreaming
A dream is a background pass that checks the wiki against recent transcripts and notes, fixes stale or wrong facts (marking dates and staleness), merges duplicates, links pages and keeps _index.md current. Nothing changes in your live wiki until you apply the result.
How a run works
- Select. Pending transcripts (oldest first, at most 50 / 6,000,000 characters) and notes not yet consolidated (at most 300). Counts and a rough token estimate are printed and you confirm (or pass
--yes). The run refuses if the estimate exceeds the budget. - Stage. The live wiki is copied into
proposals/<id>/wiki, and the checksums of your live pages are remembered. - Analyze. One analyzer agent per input reads it against the staged wiki and writes what it learned. Large inputs are split.
- Organize. One organizer agent merges duplicates, resolves conflicts, links pages and updates the index.
- Propose. The result is saved as a proposal in
reviewstate. If the organizer fails after analyzers wrote, the proposal is still kept and marked partial. - Apply or reject. See below.
Providers
You bring the key. anthropic (default) uses the Messages API. openai works with any OpenAI-compatible /chat/completions endpoint that supports tool calling: a hosted provider, a local server, or a router such as 9router.
# Anthropic (default)
export ANTHROPIC_API_KEY="sk-ant-..."
# any OpenAI-compatible endpoint, e.g. a local router
export ARCHIVUM_LLM_PROVIDER=openai
export ARCHIVUM_LLM_BASE_URL="http://localhost:20128/v1"
export ARCHIVUM_LLM_API_KEY="..."
export ARCHIVUM_ANALYZER_MODEL="your-model"
export ARCHIVUM_ORGANIZER_MODEL="your-model"
Token budgets
Budgets are counted in tokens, not money; check your provider for pricing. The default budget is 3,000,000 tokens. Before running, dream prints a rough estimate from the size of the transcripts and existing wiki. It is an estimate only: actual usage depends on the model and how many turns the agents take. If a run hits the budget it stops with a budget-exhausted status and keeps what was staged for review.
Review first, apply skip rule, restore
- Dreaming never touches the live wiki. Use
archivum diff, thenapplyorreject. (--applyondreamis opt-in.) applywrites a file only if the live page is still exactly what the dream started from; otherwise it is skipped and listed.--forceoverrides that.- Applying records history, marks the proposal's transcripts dreamed and advances the notes marker.
- Every applied write is a version:
archivum restore <path> --version N.
Security model
- Transcripts are untrusted data. They are given to the model in a labelled format and the agents are instructed to treat them as data, not instructions. Instructions hidden in a transcript could still influence a model; this reduces that risk, it does not remove it.
- Document-only tools. Dream agents can only list, read, grep, write, edit, delete and rename wiki documents, and submit. They have no shell and no network access.
- Secret scrubbing. API keys, bearer tokens, PEM blocks, AWS, GitHub, Slack and Google keys and JWTs are replaced by
[REDACTED:<kind>]before transcripts are saved and on every wiki write. Pattern-based scrubbing cannot catch every secret. - Review before apply and versioned restore are the final safety net.
Search
recall, search_documents and archivum recall use BM25 ranking over notes and wiki pages, with unicode-aware tokenising, light stemming and a higher weight for page names and titles. Results are deterministic. There are no embeddings and no vector database.
Why: the wiki is small and written to be navigated. The model starts from _index.md, follows links and searches by keyword, much like a person with a folder of notes. That needs no extra model, no index service and nothing to send off your machine, and a result can be explained by the words it matched. The trade-off is that purely semantic queries with no shared words can miss; the dream's linking and naming are meant to cover that.
Simulation (/try/)
The /try/ page is an interactive demo of memory and dreaming in your browser: a chat with a pretend coding agent, an animated stage showing the analyzer and organizer at work, and a panel with the context, wiki, notes, transcripts and the proposal diff you approve or reject. It never reads or writes your local Archivum files.
- Recorded (default): a scripted scenario. Nothing is sent anywhere.
- Live: a real model, paid for by the site, so you need no key. It is rate-limited, and when a limit is hit the page tells you and returns to Recorded. Your messages go to the site and its model provider, so type nothing private. Your own CLI memory never goes through the site.
Privacy
| Data | Leaves your machine? |
|---|---|
| Wiki, notes, transcripts, history | No. They are files in your Archivum home. |
| MCP tools and hooks | No. They run locally; npx may download the package from the npm registry. |
archivum dream | Yes, to the LLM endpoint you configured: the selected transcripts, notes and wiki pages. With a local router, that is whatever the router forwards. |
| The /try/ simulation, Live mode | Yes, your messages go to this site's server and its model provider. Recorded mode sends nothing. |
| Archivum itself | No telemetry, no accounts, no hosted storage. |
Secrets are scrubbed before transcripts are stored, but the scrubber is pattern-based. See the privacy notice for the website.
FAQ
Does it cost anything?
Archivum is free. Dreaming spends tokens on your own LLM account; the simulation's Live mode is paid by the site owner within caps.
Do I need an account?
No. There are no accounts, and no hosted storage.
Can I use a model other than Anthropic's?
Yes, set ARCHIVUM_LLM_PROVIDER=openai with any OpenAI-compatible endpoint that supports tool calling. You must name the models.
Will dreaming overwrite my edits?
No. Dreams write to a proposal, and apply skips files you changed since the dream began unless you pass --force. Applied changes can be restored.
How do I remove it?
Delete the Archivum hooks from ~/.claude/settings.json (a backup is at settings.json.archivum-bak), run claude mcp remove archivum or codex mcp remove archivum, and delete the Archivum home folder.
How long are transcripts kept?
Transcripts dreamed more than 30 days ago are deleted by default; change it with archivum retention --days N. Wiki pages and notes are not deleted.
Does it work with my agent?
Claude Code (hooks and MCP) and Codex (MCP) are supported by init. Other MCP clients should work with the generic config but have not all been tested; for agents without hooks use archivum log.