scone-cli 0.2.1

Scone: a local-first temporal memory engine โ€” CLI, MCP server, and HTTP API
Documentation

Your AI forgets everything between conversations, and the memory services that fix it want your memories in their cloud. Scone fixes both: a complete memory engine, episodic and semantic, temporal and searchable, that runs entirely on your machine and embeds in anything.

๐Ÿง  Temporal memory Facts extracted from what you store, with validity intervals. A contradiction closes the old fact with a recorded reason, so history stays queryable. Stale facts decay; recalled facts strengthen.
๐Ÿ•ฐ๏ธ Time travel search --as-of 2026-03-15 answers "what did I believe in March?". Validity is a WHERE clause, not a version-chain walk.
๐Ÿ” Hybrid search BM25, vectors, facts, and recency fused in one query, with provenance on every result. Local ONNX embeddings by default; it works on a plane.
๐Ÿท๏ธ Tags Tag anything on the way in (--tag research), then retrieve only that: papers, a client, one knowledge base. Works on the CLI, MCP, and HTTP surfaces.
๐Ÿ‘ค Profiles Identity facts + recent activity in one call, on the CLI, MCP, and HTTP surfaces.
๐Ÿ“‰ Context economy Every recall reports bytes returned vs stored ("97.7% saved"). Token optimization is a product surface, not a benchmark footnote.
๐Ÿ“ฆ Portable & embeddable scone export writes JSONL with full fact history. The C ABI (include/scone.h) embeds the engine in any language. Zero TypeScript.

Use Scone

๐Ÿง‘โ€๐Ÿ’ป I use AI tools

Give Claude Code (or any MCP client) persistent memory across sessions.

โ†’ Agent memory

๐Ÿ”ง I'm building

Embed the engine as a Rust crate or through the C ABI; or call the HTTP API.

โ†’ Build with Scone

๐Ÿ–ฅ๏ธ I run my own infra

One binary, one config file, Bearer keys each bound to a space.

โ†’ Self-host

Quickstart

Install with Homebrew:

brew install DrDrewCain/scone/scone

Or grab a prebuilt binary from Releases. Either way, no Rust toolchain is needed:

scone setup claude-code         # also: claude-desktop, cursor, vscode,
                                # windsurf, zed, codex, opencode, cline
scone add --note "hello, memory"

Building from source instead:

cargo install scone-cli

scone add --note "changed the oil on the truck"
scone search "vehicle maintenance"      # semantic hit, fully offline
scone watch ~/notes --once              # ingest a directory
scone add paper.pdf --tag research      # PDFs become searchable text
scone add --url https://example.com/post --tag reading
scone distill                           # extract temporal facts (any LLM)
scone facts list --all                  # history, with closure reasons
scone search "tools" --as-of 2026-03-15T00:00:00Z
scone search "attention" --tag research # narrow to what you tagged
scone tags                              # tags in this space, with counts
scone ask "when did I switch deploy targets?"
scone profile                           # identity + recent activity
scone status                            # stores, counts, index health
scone export > memory.jsonl             # your memory is portable

The semantic lane uses whatever LLM you configure (Ollama, OpenAI-compatible, or Anthropic) and pauses loudly when none is set. Episodic search never needs one. ~/.scone/config.toml:

[llm]
provider = "ollama"
model = "llama3.1:8b"

Running local models on a laptop, two lessons from our own benchmarks: derive a bounded-context variant (ollama create llama3.1-ctx8k from a Modelfile with PARAMETER num_ctx 8192) so an 8B reserves ~6GB instead of 22GB and stops tripping macOS memory kills, and wrap anything long-running in caffeinate -i so idle sleep cannot end a job hours in. Reasoning models (Gemma 4 and kin) need thinking disabled for short extraction calls or they return empty answers under token caps; scone sends Ollama's think: false when configured to.

Expect a local model to retrieve well and answer imperfectly. Retrieval lands the right session for 90 to 100% of questions in our benchmarks while an 8B reader converts under half of them into a correct answer, and the gap is entirely reasoning over evidence, not finding it. Attempts to close it by asking more of the model backfired: an evidence-chaining prompt cost 10 points, and splitting the work into extract-then-answer passes cost 13 and zeroed out temporal questions. Small readers improve when you shrink their job, not when you add structure to it. For answer quality beyond that ceiling, point the answer step at a larger model, or let your coding agent do the reading through the MCP server.

Give your AI memory

claude mcp add scone -- scone --space myproject mcp
scone setup claude-code-hooks   # real-time: inject memory each prompt,
                                # capture the session when it ends
Tool What it does
memory_store Save an observation; duplicates are recognized, facts distill immediately when an LLM is configured.
memory_recall Hybrid recall with your profile prepended, every line dated; as_of for time travel, tags to narrow it.
memory_facts_about What's currently known about an entity (aliases resolved).
memory_pending Episodes awaiting fact extraction. Your agent reads them.
memory_store_facts Your agent submits what it extracted; the engine applies contradiction closure and provenance.
memory_forget Close a fact with your reason. Recorded, never deleted.

Each --space is an isolated brain: one per project, per client, per team.

The last two tools are how Scone extracts facts without an API key. Your agent already reads well and you already pay for it, so it does the distillation on your existing subscription: memory_pending hands it the episodes, it reasons over them, memory_store_facts submits the result. The engine still owns the invariants; the agent only proposes. Configure an LLM instead if you want extraction to run unattended.

Build with Scone

cargo add scone-core
let mut engine = Engine::open(dir, Box::new(OnnxEmbedder::new(cache)?))?;
let space = auth::resolve(&mut engine, "notes", true)?;
engine.ingest(&space, IngestInput::Note { text: "โ€ฆ".into() })?;
let pack = engine.recall(&space, "what do I know about X", &RecallOpts::default())?;
API Purpose
Engine::ingest Store content: chunked, embedded, indexed, queued for distillation
Engine::recall Hybrid retrieval: facts, cited chunks, context economy
Engine::distill Drain the queue through your LLM into temporal facts
Engine::profile Identity facts + recent activity
Engine::export_jsonl / import_jsonl Full-fidelity portability
scone-ffi The same engine via C ABI, from any language

Self-host

# ~/.scone/config.toml
[server]
listen = "127.0.0.1:7437"
[[server.keys]]
key = "sk-alice"
space = "alice"

scone serve

POST /v1/episodes ยท GET /v1/recall (?as_of=, ?tags=) ยท GET /v1/facts ยท POST /v1/facts/{id}/close ยท GET /v1/profile ยท GET /v1/status ยท GET /v1/tags. Every key is bound to exactly one space, and the server refuses to start keyless.

How it works

SQLite is the single source of truth; tantivy (BM25) and usearch (HNSW) are derived, rebuildable indexes (scone doctor --rebuild). Ingestion is two lanes: episodic (synchronous, offline-complete) and semantic (async LLM distillation that never blocks a write). Four invariants are property-tested: chunks reassemble exactly; no two active facts share subject+predicate; contradiction closes intervals, never deletes; every fact carries provenance.

Measured on Apple Silicon (criterion): recall ~300 ยตs over 5k chunks, 3.6 ms end-to-end including local query embedding, ingest 2.9 ms/note.

License

MIT. Built by studying what came before and keeping the receipts.