A Acheron
v0.3.0
Operator's guide

One server for your agent's memory.

Everything Acheron can do: install it, point it at your notes, and let search and the knowledge graph do the compounding.

context_search — live response
// one call, reranked, no search loop
{
  "query": "how do we handle sync conflicts?",
  "ranking": "model",
  "fallback": false,
  "results": [
    { "title": "Decision — CRDT merge",
      "model_rank": 1 },
    { "title": "Sync Engine",
      "model_rank": 2 },
    { "title": "2025-11 Sync storm",
      "model_rank": 3 }
  ]
}
25 tools
1 search verb + 24 proxied, one surface
<1 min
Save a note and your agent can find it in under a minute.
Fail-open
model down ≠ retrieval down
MIT
local-first, replayable benchmark
01 — Architecture

Markdown is the database. Everything else is derived.

Acheron is one agent-facing MCP server in front of Basic Memory. Your notes stay plain markdown in ordinary folders; Basic Memory keeps a local index over them; Acheron gives every agent one clean surface with one search verb. Delete the index and it rebuilds from the files — nothing is trapped.

Your agents Claude Code · OpenCode · any MCP client one server entry, nothing else Acheron context_search · reranked, filter-aware 24 engine tools proxied as-is fail-open ranking policy Basic Memory local service · port 8765 SQLite + embeddings index file watcher Vault plain markdown source of truth watch: Save a note and your agent can find it in under a minute. one door for every agent

1 One surface, one search verb

The engine exposes many overlapping ways to search. Acheron absorbs them into context_search — query, filters, dates, tags, similarity — and reranks the results with a decision model. Every other tool is proxied under its original name, so nothing breaks.

2 Ranking is best-effort, retrieval never blocks

If the decision model errors or rate-limits, results come back in native order with fallback: true. A ranking outage degrades ordering — it never takes the agent offline. provider: none turns reranking off entirely.

Prefer motion? Two scrubbable explainers walk the same paths: the eleven-step search path (including the model-failure fallback) and the storage layer (file → index → relations graph).

02 — Quickstart

Running in about five minutes.

Two processes: the storage engine (Basic Memory, over HTTP) and Acheron itself (stdio, launched by your MCP client). Reranking is optional; without a key everything still works, in native order.

1

Prerequisites

Python 3.12+, uv, Basic Memory with at least one project of markdown notes. Nothing else is required. Reranking is optional: turn on the engine's built-in reranker for a no-key improvement, add a free OpenRouter key for Mercury Decide, or point ACHERON_PROVIDER=custom at any endpoint that speaks the System One API, including a local server.

2

Install and start the engine

uv sync
scripts/start-bm-http.sh      # engine on http://127.0.0.1:8765
# or: scripts/install-launchd.sh   (starts at login, kept alive, macOS)
3

Give it notes

Point a Basic Memory project at any folder of markdown — an Obsidian vault, a notes directory, a docs tree. Registering the folder is the whole import.

bm project add notes ~/Notes        # indexes existing files at add time
bm project index notes              # catch-up, if files arrived later; safe to rerun
bm status                           # confirm: "indexed and settled"
4

Wire it into an agent

Add Acheron as an MCP server. Do not also configure the engine's own MCP entry — this server proxies it, and two search tools is a per-turn decision tax.

# ~/.config/opencode/opencode.jsonc
"acheron": {
  "type": "local",
  "command": ["uv", "run", "--directory", "/path/to/acheron", "acheron"],
  "enabled": true
}
claude mcp add --scope user acheron -- /path/to/acheron/.venv/bin/acheron
{
  "mcpServers": {
    "acheron": { "command": "/path/to/acheron/.venv/bin/acheron" }
  }
}
5

Ask something

From the agent, one call:

context_search(query="what did we decide about caching?")

First run: pass tags, a status, or a date filter without a query and results come back in native order — ranking: "native".

04 — Surface

Twenty-five tools, one door.

Everything the engine exposes arrives on one server. Write tools keep their safety annotations (destructiveHint and friends), so client permission prompts keep working. Two overlapping search verbs are folded away; so are the ChatGPT-only connector adapters.

GroupToolsUse it for
Searchcontext_searchThe only search: query, filters, or both
Readread_note read_content view_note cat tail recent_activityOpen notes, files, recent changes — full or sliced
Graphbuild_contextWalk links and backlinks around a note (1–3 hops)
Writewrite_note edit_note move_note delete_noteCreate, edit in place, move, remove
Browselist_directory ls find grepDirectories, globs, metadata queries, content search
Schemaschema_infer schema_validate schema_diffLearn and enforce note shapes as your corpus matures
Projectscreate_memory_project list_memory_projects list_workspaces delete_projectRegister corpora, route between them
Systembasic_memory_diagnostics manHealth checks and the built-in manual
hidden: search_notes (folded) hidden: search / fetch (connector adapters) preserved: tool annotations
05 — Data model

One project per corpus. In place, never a copy.

A corpus is a folder tree registered as a Basic Memory project. Keep personal and work notes in separate projects and search can span them at once — or be routed to one.

What lives where

  • The folder is canonical. Obsidian, an editor, a script, an agent — anything that writes markdown is a valid write path.
  • The index is disposable. SQLite plus embeddings, rebuilt from the files. Move the folder and you lose nothing.
  • Wikilinks become edges. [[Note]] references are parsed into relations; build_context walks them. Tags and frontmatter become filters.
  • Renames: keep the old name in aliases: so search still finds the note.

Watcher behavior, verified

After a project's first index pass, new and changed files are picked up automatically — no sync command, no export step. Save a note and your agent can find it in under a minute. Files that arrive before that first pass need one bm project index <name> to catch up; reruns are safe.

bm project add work ~/Work/notes
bm project add home ~/Vault
bm project index work
Routing

Search defaults to the project the caller names, else the configured default (ACHERON_DEFAULT_PROJECT). Cross-project queries are supported by the engine — one call can span every indexed corpus.

06 — Write side

The memory skill teaches agents to write well.

Search only pays off if the corpus is written to be found: linked, typed, concise, deduplicated. skills/acheron-memory/ packages that discipline as three procedures an agent can run.

S Seed

Jumpstart a folder: inventory with corpus_scan.py, import in place, then enrich in batches — entity notes, links, hubs — every auto-created note flagged needs_review until confirmed.

R Remember

Mid-session capture: a decision with its reason, a durable fact, a lesson. Search before write, link what exists, confirm what was saved. At most five new notes per session.

W Wrap

End-of-session distillation: one session note, hub updates, proposed links. Never a transcript dump. The corpus grows by compounding, not by volume.

≈ corpus_scan.py

A dependency-free audit: file inventory, duplicate titles, broken wikilinks, orphans. Run it before and after any enrichment pass. --strict exits non-zero when links break.

cp -r skills/acheron-memory ~/.claude/skills/    # or your agent's skills directory
python3 skills/acheron-memory/scripts/corpus_scan.py links ~/Notes

Works two ways: through the MCP tools when connected, or directly on markdown files when not. The packaged skills/acheron-memory.zip suits clients that accept skill uploads.

07 — Recipes

Getting the most out of it.

Six patterns that turn Acheron from "search over notes" into a compounding knowledge system. Each one is small on purpose.

1

Seed an existing vault

one-time · ~an hour for a large vault

Point at the folder, let the skill inventory it, and enrich in checkpointed batches. Additive edits only — frontmatter, links, hub notes — so a failed batch leaves a working corpus.

bm project add vault ~/ObsidianVault && bm project index vault
# then ask your agent: "seed the vault project with the acheron-memory skill"
2

Run the session loop

daily · compounding

Mid-session, the agent captures decisions and facts as they land. At the end, it wraps: one session note, hubs updated, review flags proposed. Nothing important lives only in a chat log.

"remember this"  →  search, link, write, confirm
"wrap up"        →  session note + hub updates + open proposals
3

Answer from the graph, not just the page

every query

Two-step reads beat one-step reads: search finds the page; build_context hands back its neighborhood — the decision it implements, the people it concerns, the incidents it caused. Link generously and the neighborhood gets rich.

context_search(query="sync conflicts")
build_context(url="concepts/sync-engine", depth=2)
4

Keep corpora separate, search them together

setup once

One project per coherent corpus — work, personal, a team wiki. Route by naming the project, or let the default handle the common case. Cross-project search returns hits from all of them in one call.

ACHERON_DEFAULT_PROJECT=vault acheron
5

Go fully offline

a flag

No key, no network: reranking off, native order, everything else identical. Good for air-gapped runs, cost control, and comparing what the model actually buys you.

ACHERON_PROVIDER=none uv run acheron
6

Schedule consolidation, not capture

monthly-ish

Capture is cheap and constant; merging, promotion, and link repair are occasional passes. Run the audit, review the needs_review queue, promote session lessons into concept notes. Ten minutes, and the corpus stays navigable.

python3 maintain_vault.py review   # (or your corpus's equivalent)
python3 skills/acheron-memory/scripts/corpus_scan.py links ~/Notes
08 — Operations

It runs quietly. Here's how to keep it that way.

No telemetry and no Acheron daemon beyond the storage engine. By default, when Acheron finds an OpenRouter key (the OPENROUTER_API_KEY variable or OpenCode's stored key), each reranked search sends your query and each candidate's title and snippet to OpenRouter, capped at 500 characters for the query, 200 per title and 500 per snippet. With ACHERON_PROVIDER=custom the same text goes to the endpoint you configure instead, and stays on your machine if that endpoint is a local server. Set ACHERON_PROVIDER=none to send nothing. The operational surface is small on purpose.

Service lifecycle (macOS)

The engine runs under launchd: starts at login, kept alive, logs to ~/Library/Logs/basic-memory-http.log. Overridable via BM_BIN, BM_PORT, LABEL.

scripts/install-launchd.sh
launchctl kickstart -k gui/$(id -u)/local.basic-memory-http   # restart

Health checks

bm status shows per-stage readiness — files observed, relations extracted, embeddings built, pending counts. If a stage is short, bm project index <name> finishes it; it is incremental and safe to rerun.

Model & cost

Mercury Decide's free tier allows 20 requests/minute — benchmark runners pace themselves (--delay 3.2). provider: none makes no model calls; Perplexity Decider and Jev are paid presets, and custom reaches any other endpoint.

Index hygiene

Ignored folders and removed files are pruned on sync. If a corpus is ever rebuilt, delete the index and let the watcher re-derive it — the markdown is never at risk.

09 — Troubleshooting

Symptom → cause → fix.

SymptomUsually meansFix
context_search returns no candidates Engine down at startup, or the project has no index yet scripts/start-bm-http.sh; then bm project index <name>; restart the client to re-proxy tools
Proxied tools missing, but search works Acheron started while the engine was down — tools are discovered at startup Restart Acheron (the client's MCP entry); search keeps working meanwhile
New files not searchable Project never had its first index pass, so the watcher isn't tracking it bm project index <name> once; thereafter wait under a minute before searching for new files
Results look unordered Model unavailable (check fallback: true), or a key isn't set Set OPENROUTER_API_KEY (or ACHERON_DECISIONS_KEY for a custom endpoint), or accept native order deliberately with provider: none
Links broke after a rename Wikilinks point at old titles Add old titles to aliases:; find the rest with corpus_scan.py links
Two search tools in the client The engine's own MCP entry was configured alongside Acheron Remove the engine entry — Acheron proxies it by design
10 — Reference

Env vars, commands, glossary.

Configuration

VariableDefaultMeaning
ACHERON_BM_URLhttp://127.0.0.1:8765/mcpEngine HTTP MCP endpoint
ACHERON_PROVIDERmercurymercury · perplexity · jev · custom · none
ACHERON_MODELprovider defaultDecision model id; required for custom
ACHERON_DECISIONS_URLOpenRouterDecisions endpoint; required for custom; https unless local
ACHERON_DECISIONS_KEYnoneKey for a non-OpenRouter endpoint; omit for a local server
ACHERON_DEFAULT_PROJECTnoneProject scope when the caller passes none

CLI cheat sheet

bm project add <name> <path>   # register a folder (indexes existing files)
bm project index <name>         # catch-up / repair; incremental, safe to rerun
bm project list                  # all projects and paths
bm status                        # per-stage readiness for the current project
bm reindex --project <name>      # rebuild search index and embeddings
bm orphans                       # notes with no relations — wiring opportunities

Glossary

TermMeaning here
MCPModel Context Protocol — the standard your agent uses to call tools
ProjectA registered folder of markdown; the unit of indexing and routing
PermalinkA stable address for a note (e.g. vault/notes/decision-caching) that survives file moves
Forward referenceA [[wikilink]] — parsed into a relation edge at index time
Decision modelThe System One model that scores search candidates (Mercury by default)
Fail-openRanking failure degrades order and says so; retrieval still answers
Proxied toolAn engine tool re-exposed by Acheron under its original name and schema