Atheneum
Embedded graph database for agent coordination — episodic memory, knowledge persistence, and session accountability across coding sessions.
Part of the grounded-coding ecosystem. Used as the storage layer inside envoy.
Ecosystem
grounded-coding ── install + Claude Code plugin (skills, hooks, MCP)
│
├── magellan ── code graph indexer (symbols, call graph, CFG)
├── llmgrep ── semantic code search over magellan graphs
├── mirage ── CFG analysis (paths, loops, dominance)
├── splice ── span-safe refactoring
│
├── envoy ── HTTP coordination server (messaging, agent registry)
│ └── atheneum ◀── YOU ARE HERE
│ └── sqlitegraph ── SQLite graph engine
│
└── envoy-hook ── Claude Code hook binary (session + tool call logging)
Atheneum is the persistence layer. It stores what agents discovered, what sessions did, what tasks exist, and what knowledge is worth keeping — so the next agent doesn't start from scratch.
Install
Atheneum is a library. Production use is via agent-envoy which exposes all endpoints over HTTP (envoy binary). Direct embedding is for custom runtimes.
What's New In 0.11.0
seed_memory: a token-bounded, concept-grouped summary of the knowledge base.atheneum-mcpregenerates it on every session connect and folds it into the server instructions andnavigate/query_memory/searchtool descriptions, so a connecting client already knows what's in memory.update_memoryandupsert_memory_by_concept(add_memory): patch a memory or its owning concept in place instead of every correction becoming a new row.lint/maintain: deterministic graph-health lint (orphans, broken wikilinks, stalesuperseded_byedges) plus a mutating pass that rewires, stubs, or resolves what it finds.dream-semantic(semantic_consolidation): merges closely-related or redundant concepts via a local language-model prompt with a lexical-similarity fallback.- Memory pinning (
pin/unpin) and TTL-based archival viamaintain. models-list+ swap-guard config: discovers what's loaded on a local model server before running model-dependent operations, so they don't force an unwanted swap on a shared GPU.- Optional
dashboardweb UI (web-uifeature, off by default). - Query tracing (
navigate --trace,trace-get) for replaying past navigation queries.
What's New In 0.10.0
- Native
extract-decisionsnow ships inside the crate behind theextractfeature, with both Ollama-backed and--heuristicbackfill modes. sessions-recentcan hide noisy non-repo buckets with repeatable--exclude-project.- Lexical search now reranks mixed corpora toward authoritative wiki/discovery documents instead of changelog and transcript noise.
- The standard release gate now works from the repo root with checked-in
deny,gitleaks, andsemgrepconfig.
Quickstart
use AtheneumGraph;
use Path;
let graph = open?;
// Record a session
graph.record_session?;
// Store a discovery
use json;
graph.store_discovery?;
// Query recent sessions for a project
let sessions = graph.query_sessions?;
for s in &sessions
// Ingest a wiki article
let content = "---\ntitle: My Note\n---\n# My Note\nSee also [[Related Concept]].\n";
graph.ingest_wiki_page?;
What It Stores
| Domain | Types |
|---|---|
| Sessions | start, end, tool calls, file writes, commits, test runs, cost |
| Discoveries | facts, decisions, bugs, invariants — scoped by project |
| Knowledge | wiki pages, journal sections, wikilinks |
| Planning | tasks, requirements, blockers, kanban state |
| Handoffs | inter-agent state transfers with manifests |
| Ontology | class/property schemas for typed entity reasoning |
| Memory | keyed memories with scope, confidence, project scoping |
| Dream | reflective consolidation pass over memories (merge, deduplicate, promote) |
| Search index | FTS5 full-text + bag-of-tokens lexical scan; optional HNSW candidate index for human fuzzy lookup via semantic-search |
HTTP Access
When embedded in envoy, all atheneum operations are accessible over HTTP:
# Query recent sessions
# Store a discovery
# Get recent project context (for session bootstrap hooks)
See envoy's API.md for the full HTTP reference.
Operator Queries
The CLI has direct observability commands for the read paths that operators use most:
# One session: summary + recent events + recent tool calls
# Aggregate tool usage for that session
# Recent activity across the project
All of these return JSON and are designed to replace routine direct SQLite reads.
Session Digest
session-digest emits a bounded, ranked plain-text bootstrap packet (tool
calls, file writes, top files, decisions, open tasks, thread anchors) so a
new session can ground on what prior sessions in the same project did. It
computes activity from event_log (the sessions ledger columns are usually
zero), falls back across all projects when the --project filter is empty,
and truncates to a token budget. --json emits the structured report.
Decision Capture
Claude Code chat transcripts carry the structured-choice signals that are
genuinely decisions — AskUserQuestion (a human-answered choice),
ExitPlanMode (a plan approved for execution), TaskCreate, and TodoWrite.
Atheneum captures those as first-class Decision discovery rows so the
graph holds the decision chain, not just the chat text.
Model: each captured decision stores source (askuser / exitplan /
taskcreate / todowrite), chosen, alternatives, and rationale in the
discovery metadata, scoped to the session that made it. Dedup key is
session_id + sequence + target + source, so a decision is captured
once even if the same transcript is scanned repeatedly.
Three layers, one shape:
# Backfill: a standalone operator script runs a local LLM (Ollama qwen3.5)
# over each transcript and stores decision-shaped turns via `atheneum
# store-discovery`. One session, or --all (resumable).
# Live: the atheneum watcher tails transcripts in a loop, captures the
# Tier-1 structured signals deterministically (no LLM).
# Observe: the decisions captured for a session (any source)
A fourth, highest-fidelity layer ships as the plugin/atheneum-decisions/
Claude Code companion plugin: a record-decision skill that records a
decision as the model makes it (source = "skill"), a
/decision <target> <chosen> [rationale] manual fallback, and a non-blocking
Stop-gate that reminds you to record decisions. The skill/command layer
dedups on (session_id, target, source, chosen) via store-discovery --dedup
(it has no stable transcript sequence); see MANUAL.md for the install
command.
extract-decisions is the one-shot backfiller for decisions that lack a
Tier-1 structured signal. It ships two ways: a ~/.local/bin operator script
(the default, no special build needed) and a native atheneum extract-decisions subcommand (a Rust port, behind the extract feature —
--features extract or --all-features). The subcommand has two user-picked
backends: the default local Ollama LLM (qwen3.5, source = "llm-extract")
and a rule-based --heuristic mode (no LLM, no network, source = "heuristic") that catches decision-shaped sentences with an explicit
rationale clause — lower recall + some false positives, zero deps. Both
backends store each decision as a Decision discovery linked into the
session thread (caused_by / led_to) for free — the script shells out to
atheneum store-discovery, the subcommand stores in-process via
graph.store_discovery. Pick the backend per run with --heuristic /
--mode llm|heuristic / ATHENEUM_EXTRACT_MODE. atheneum watch-decisions is the always-on deterministic detector
(--once runs a single cold-cursor scan, safe for cron). The watcher is
detect-only at the Tier-1 layer — the SessionStop sync-claude-transcript
hook still owns full transcript ingest at session end. A Decision row
from any source (backfill script, watcher, or manual store_discovery) is
visible to chat --only-decisions and session-digest, deduped across
sources by the same key.
HopGraph
HopGraph is an optional retrieval mode: embeddings find the door, graph walk retrieves the room.
For grounded agent workflows, the default path is still direct graph traversal plus typed SQL reads. HopGraph exists for fuzzy human-style lookup when approximate vector entry points are useful enough to justify the extra index cost.
- A text query is embedded and matched against the lexical index to find entry-point entities.
- From each hit, a BFS walk expands the subgraph — following only allowed edge types (e.g.,
Explains,Wikilink). - The result is truncated to a token budget so it fits in a context window.
use ;
use Path;
let graph = open?;
// Token-budgeted HopGraph query — walk only Explains + Wikilink edges
let views = graph.hopgraph_query?;
for view in &views
// Switch to neural embeddings (requires ollama + nomic-embed-text)
Discovery Consolidation
// Merge all Discovery entities for a target into a single Knowledge entity
let knowledge_id = graph.consolidate_discoveries?;
// Consolidate all targets at once
let results = graph.consolidation_pass?;
for in &results
Bridge Wiki to Code Symbols
// Link wiki [[wikilinks]] to magellan-indexed code symbols
graph.link_wiki_to_symbols?;
Features
| Feature | Default | Description |
|---|---|---|
default |
✓ | Core graph, wiki, sessions, planning, search, thread — lexical (bag-of-tokens) search + BFS graph navigation |
semantic-search |
— | Optional HNSW candidate index for human fuzzy lookup in search (opt-in; heavy — index + embedder). Off by default; agent retrieval uses lexical search, graph traversal, and SQL payload queries |
neural-embed |
— | Ollama neural embeddings (requires ureq, ollama + nomic-embed-text) |
extract |
— | Native atheneum extract-decisions subcommand (Rust port of the operator script; LLM backend requires ureq + ollama, default qwen3.5; --heuristic backend needs no LLM/network) |
web |
— | Web dashboard (axum + askama templates) |
cli |
— | atheneum CLI binary |
async |
— | Async runtime support |
CLI
INGEST:
init <db> Initialize a new graph database
sync-wiki <db> <dir> [project] Ingest .md files as wiki pages
sync-journal <db> <dir> [project] Ingest .md files as journal sections
sync-logseq <db> <root> [project] Recursively ingest Logseq pages/ and journals/
sync-claude-transcript <db> <jsonl> [project] [agent] Import Claude transcript
store-discovery <db> <agent> <type> <target> [meta.json] Store a discovery
add-edge <db> <from> <to> <edge-type> [data.json] Create a relation
TASKS:
task-create <db> <title> [desc] [--project P] Create a new task
task-list <db> [--project P] [--status S] List tasks (default: non-archived)
task-update <db> <task-id> <status> Update task status
task-done <db> <task-id> Mark task as DONE
task-archive <db> <task-id> Archive a task
MEMORY:
memory-store <db> <key> <content> [--scope S] [--confidence N] [--project P] Store a memory
memory-get <db> <key> [--scope S] [--project P] Retrieve memory by key
memory-list <db> [--scope S] [--project P] [--offset N] [--limit N] List memories (paginated, default limit 1000)
memory-update <db> --id N [--content C] [--importance N] [--tags a,b --replace-tags] Patch an existing memory in place
pin <db> --id N Pin an entity (always in seed_memory, cache-eviction immune)
unpin <db> --id N Unpin an entity
LIBRARIAN:
lint <db-path> [--stale-days N] Graph-health check: orphans, broken wikilinks, stale superseded_by edges
maintain <db-path> [--apply] [--stale-days N] [--rewire-threshold F] [--broken-link-mode <stub|sever>] Rewire orphans, stub/sever broken links, resolve contradictions
models-list <db-path> List models loaded on a local model server
dashboard <db-path> [--port N] Web dashboard server (feature: web-ui)
DREAM:
dream <db> [--scope S] [--project P] [--dry-run|--auto-merge] Reflective memory consolidation
dream-semantic <db> [--apply] Merge closely-related/redundant concepts (local-model prompt, lexical fallback)
QUERY & NAVIGATION:
search <db> <query> [--k N] [--project P] [--max-tokens N] Lexical search (optional HNSW candidate index with --features semantic-search)
navigate <db> <query> [--k N] [--depth N] [--project P] [--kind K] [--max-tokens N] Search then walk subgraphs
thread <db> <query> [--k N] [--depth D=3] [--tokens T=1500] [--project P] [--json] Walk a decision chain (caused_by/led_to edges)
chat <db> --session <id> [--tokens T] [--direction recent|chrono] [--kinds K] [--role R] [--search Q] [--only-decisions] [--walk] [--offset N --limit L] [--json] Token-budgeted walk of a session's chat records (or just its decisions)
watch-decisions <db> [--once] [--interval S=2] [--config-dir D]... [--project P] [--agent A] [--dry-run] Live-tail transcripts, capture structured decisions
extract-decisions <db> [--all|<session-id>] [--dry-run] [--force] [--project P] [--agent A] [--model M] [--transcripts-dir D] [--max-chars N] [--ollama-url U] [--heuristic|--mode llm|heuristic] [--verbose] Backfill decisions (LLM or --heuristic; feature: extract)
wiki-search <db> <query> [--project P] [--limit N] Full-text search over wiki pages (FTS5, falls back to name match)
decision-search <db> <query> [--project P] [--limit N] Content search over Decision discoveries (target/chosen/why)
seed-memory <db> [--project P] [--tokens N] Token-bounded, concept-grouped knowledge-base summary
trace-get <db> --id N Replay a past navigate --trace query
query-wiki <db> <path> Query a wiki page by path
query-journal <db> <path> Query journal sections by path
query-knowledge <db> <target> [--project P] [--max-tokens N] Aggregated knowledge
query-sessions <db> [--project P] [--offset N] [--limit N] Session history
query-events <db> [--session <id>] [--type <t>] [--offset N] [--limit N] Event log
session-digest <db> [--project P] [--last N] [--tokens T] [--json] Bounded bootstrap digest
session-trace <db> --session <id> [--limit N] Session summary plus recent events
tool-usage <db> --session <id> [--limit N] Tool breakdown for one session
discoveries-recent <db> [--project P] [--agent A] [--session S] [--type T] [--limit N] Recent discoveries (filter by session and/or type)
handoffs-recent <db> [--project P] [--agent A] [--limit N] Recent handoffs
events-recent <db> [--session ID] [--type T] [--limit N] Recent events
sessions-recent <db> [--project P] [--agent A] [--limit N] [--exclude-project P ...] Recent sessions (hide non-repo project buckets)
list-pages <db> [--project P] [--offset N] [--limit N] List wiki pages (default limit 1000)
entity <db> <id> Print entity as JSON
edge <db> <id> Print edge as JSON
neighbors <db> <id> [--depth N] One-hop edges or BFS subgraph
graph-stats <db> Graph topology counts
MAINTENANCE:
reindex <db> Rebuild optional HNSW human-search index
consolidate <db> [target] [--project P] Merge discoveries into Knowledge
sync-logseq recursively ingests <wiki-root>/pages/**/*.md as wiki pages and
<wiki-root>/journals/**/*.md as journal sections. Wiki [[links]] become
first-class wikilink graph edges so navigate and neighbors can traverse article
relationships.
sync-claude-transcript imports a local Claude Code transcript JSONL into Atheneum's
session graph. It records prompt/chat summaries, observed tool calls, accessed
file edges for Read/Edit/Write, and session token/cache totals. Re-running the
command on the same append-only transcript imports only new lines.
Requirements
- Rust 1.75+
- SQLite 3.35+ with JSON1 (bundled via rusqlite)
Related
- envoy — HTTP server exposing atheneum over REST
- grounded-coding — Claude Code plugin using this ecosystem
- magellan — code graph indexer
- sqlitegraph — underlying SQLite graph engine
Resilience
The wiki_pages_fts FTS5 index self-heals on open. If an external SQLite writer (system sqlite3, Python, another tool) leaves the FTS5 shadow tables in an inconsistent state, AtheneumGraph::open() detects the corruption, recreates the virtual table and triggers on fresh connections, and rebuilds the index from wiki_pages. This keeps sync-wiki, search-wiki, and backfill-wiki working without manual repair.
License
GPL-3.0-only — see LICENSE.