diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json
index 4721c396..3e95968f 100644
--- a/.claude-plugin/marketplace.json
+++ b/.claude-plugin/marketplace.json
@@ -9,7 +9,7 @@
"name": "engraphis-memory",
"source": "./",
"description": "Discipline for giving agents durable, scoped, explainable memory across sessions and repos with the Engraphis MCP tools.",
- "version": "1.6"
+ "version": "1.7"
}
]
}
diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index 0bee82ea..c0831a73 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "engraphis-memory",
- "version": "1.6",
+ "version": "1.7",
"description": "Give agents durable, scoped, explainable memory across sessions and repos via the Engraphis MCP tools. Use when you learn something worth keeping, need prior context before acting, or ask why/how a fact changed. Covers remember/recall, why/timeline, forget/pin/correct, sessions, and code search.",
"author": {
"name": "The Engraphis Authors",
diff --git a/.claude-plugin/skill-assets.sha256 b/.claude-plugin/skill-assets.sha256
index 6c837646..b03f5321 100644
--- a/.claude-plugin/skill-assets.sha256
+++ b/.claude-plugin/skill-assets.sha256
@@ -1,6 +1,6 @@
-4c18cdb509babb853ac7e5283ca9b309e2669b82ff098f3acf33238a9e4c1114 .claude-plugin/marketplace.json
-94bfa06317a8fe6a6a7e204bb70c5abdc9e4bbc34d79dd6f8447a30140bc8b85 .claude-plugin/plugin.json
+cfff3064e31d0547e990f325d26fc172397d2d7b453230d5d52aebc7ea3cc79b .claude-plugin/marketplace.json
+02259d5c35da8c46aac9891655ae3623fc9cb4002aa65d429435714319999745 .claude-plugin/plugin.json
+4bc8979b9ffeb97190960e551dbf4ddc6f7aeeb7b86894fd2298a59ff0001efa skills/engraphis-memory/SKILL.md
055655db84af07561d002f0c69744313d8413c39f3e873f941f0fa0b1e76dc66 skills/engraphis-memory/references/CONVENTIONS.md
62019760766ff472a76a0f81437898f39e3c1fe2631732b7b7733e50c1ad837f skills/engraphis-memory/references/SCOPING.md
-fcb5b4d939bda7d18e4b75c0e9106df4240aa7f8eabe8218e4e41f0038fa3df8 skills/engraphis-memory/references/TOOLS.md
-0f98098df695b9a00dc78402911124ebf09a4a058f6c8bec2c6234ec61fac13a skills/engraphis-memory/SKILL.md
+d65721c1cc29faf975138a99f07bdee29ac49a9bc64b0737001781abc14407be skills/engraphis-memory/references/TOOLS.md
diff --git a/.env.example b/.env.example
index 087d70b9..77630758 100644
--- a/.env.example
+++ b/.env.example
@@ -7,6 +7,9 @@
# ── Server ──────────────────────────────────────────────────────────────────
ENGRAPHIS_HOST=127.0.0.1
ENGRAPHIS_PORT=8700
+# Port precedence for the dashboard bind: a platform-injected $PORT (Railway/Fly/Heroku)
+# wins over ENGRAPHIS_PORT; local and Compose runs without $PORT use ENGRAPHIS_PORT.
+# Docker Compose pins both PORT and ENGRAPHIS_PORT to ENGRAPHIS_COMPOSE_PORT (below).
# The public package supports only customer mode: dashboard, memory, and managed-service
# clients. Hosted vendor, relay, compute, and worker roles are not distributed here.
ENGRAPHIS_SERVICE_MODE=customer
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6f133e8a..1617b27d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -60,7 +60,7 @@ jobs:
- name: Full release gate
run: |
- python scripts/check_commercial_manifest.py
+ if [ -d website ]; then python scripts/check_commercial_manifest.py --website-root website; else python scripts/check_commercial_manifest.py; fi
python scripts/externalize_dashboard_assets.py
ruff check .
pyright
diff --git a/.gitignore b/.gitignore
index 43cd6286..c533ca3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,6 +88,9 @@ internal/
# tracked _smoke*.mjs / _measure_*.mjs must be removed with `git rm` (see audit handoff).
/_*.mjs
+# Generated screenshot from tools/manual_slider_test.js — throwaway test artifact.
+/dashboard_slider_test.png
+
# Local machine-specific launchers (absolute user paths / PM2 deploy specifics — not portable)
/Start-Engraphis-Dashboard.bat
/Engraphis Dashboard.lnk
diff --git a/BENCHMARKS.md b/BENCHMARKS.md
index 4ea7c9ea..74d023ae 100644
--- a/BENCHMARKS.md
+++ b/BENCHMARKS.md
@@ -1,380 +1,380 @@
-# Benchmarks
-
-This guide explains what Engraphis measures, how to reproduce each evaluation, and the limits of
-those results. When this document and the code disagree, the code is the source of truth.
-
-For the locked operator sequence for a public canonical run, see
-[`docs/PUBLIC_BENCHMARK_RUNBOOK.md`](docs/PUBLIC_BENCHMARK_RUNBOOK.md).
-
-### Public numeric evidence registry
-
-Every exact public aggregate retained below comes from the checked-in, public-safe
-[`offline-fixtures-v1.json`](docs/benchmark-evidence/offline-fixtures-v1.json) artifact. Its
-SHA-256 is
-`0f60b0868444f676fe14c5f94d7db2c475e22669930c4d760881d0842eaa6800`, also recorded in the
-adjacent `.sha256` file. The artifact contains no raw questions, answers, prompts, customer data,
-or per-record content fingerprints.
-
-The fixture-suite digest is
-`4d7e40607319cd4bf8caee3897f1e416dbe5b81998b37a7e4839409ee2923537`. The artifact defines
-the digest algorithm and records the SHA-256 of every suite and dataset file. Each evidence ID
-also binds its exact command through `sha256(UTF-8 exact command)`:
-
-| Evidence ID | Exact command | Config digest |
-|---|---|---|
-| `offline-chunking` | `python -m eval.chunking_eval --dataset eval/datasets/longdoc.jsonl --k 5` | `c1c8196aa7e1568ef3844a9fb2d76b87f342c39108e32d6ad144b885a76143b8` |
-| `offline-performance` | `python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10 --json` | `bbe4aca81e58d4830e50a8fc7729a1d15b71d97a6299bccd79432b7f119677d7` |
-| `offline-grounded` | `python -m eval.grounded` | `590442e51e3642c10489165759919dc86ffac62c182937330c153e7f8d5fc26f` |
-
-External, model-dependent, latency, consolidation, and productivity numbers are not published
-until a redacted immutable artifact with the same three bindings exists. Use the
-[public benchmark runbook](docs/PUBLIC_BENCHMARK_RUNBOOK.md) to produce that evidence; absence
-from this registry means no public number is claimed.
-
-## What we measure today (all offline, no API key)
-
-Most Engraphis evals score **retrieval**, not end-to-end QA. The separate productivity benchmark
-runs a complete offline agent attempt and correction loop, but it is not an official
-frontier-model QA score.
-
-- **Correctness gate**: `eval/harness.py` over `eval/datasets/sample.jsonl` and
- `codemem.jsonl` (conflict resolution) and `graph_multihop.jsonl` (multi-hop graph recall).
- Runs on the deterministic embedder, so it is a plumbing/regression floor, not a public
- performance claim. This is the gate CI enforces.
-- **Ablation**: `eval/ablation.py`: vector-only vs. 1-hop graph vs. Personalized-PageRank arm,
- to show the graph arm actually earns its place.
-- **External benchmarks**: `eval/external.py` loads **LoCoMo** and **LongMemEval** and pushes
- them through the *real* `MemoryEngine` write path (conflict resolution + evolution) and hybrid
- recall with a real sentence-transformers embedder. It reports `recall_at_k` / `hit_at_k` /
- `answer_token_recall`: i.e. *did the evidence come back*, not *did an LLM answer correctly*.
- It retains source categories and abstention/no-evidence questions as explicit exclusions from
- retrieval-only aggregates rather than silently dropping them. `eval.longmemeval_v2` is a local,
- text-only adapter for the official LongMemEval-V2 `insert(trajectory)` / `query(query,
- query_image=None)` memory interface; it does not download data or call a model.
-- **Grounded**: `eval/grounded.py`: answerable → cite, off-topic → abstain. Exact fixture
- outcomes are evidence ID `offline-grounded` in the registry above.
-- **Chunking (quality per token)**: `eval/chunking_eval.py` over `eval/datasets/longdoc.jsonl`
- ingests a multi-topic corpus twice: once as one memory per document (`whole`) and once with
- sub-file `ChunkingExtractor` (`chunked`), then queries both through the real recall pipeline.
- The checked-in corpus is explicitly marked trusted eval data so the measurement isolates
- chunking from the production trust gate, which excludes arbitrary raw imports from normal
- agent context. On the deterministic embedder, **recall@5 is 1.000 for both modes; mean
- retrieved top-5 content falls from 740.3 to 214.3 tokens (526.0 fewer, 71.1% lower, about
- 3.5× smaller), while the smallest returned evidence-holding memory falls from 162.2 to 42.4
- tokens (119.8 fewer, 73.9% lower, about 3.8× smaller).** These aggregates are evidence ID
- `offline-chunking` in the registry above. Pass `--embed-model
- sentence-transformers/all-MiniLM-L6-v2` to run a model-dependent experiment; do not publish
- that result without a new immutable artifact and pinned model revision.
-- **Full-pipeline latency + quality**: `eval/performance.py` times the shipped semantic +
- lexical + graph + fusion + scoring + rerank + packing path after warmup, with reinforcement
- disabled so repeated measurements do not mutate their corpus. It reports p50/p95/p99 latency,
- retrieval quality, packed context tokens, and full/compact JSON-shape payload proxies in one
- JSON-safe schema. Payload proxies are sampled once per question, independently of the number
- of timed iterations; they are not serialized MCP envelopes or transport responses. In the
- registered CodeMem run, 26 payload samples total **23,810** full-proxy
- `engraphis.regex.v1` tokens versus **10,202** compact-proxy tokens, avoiding **13,608** proxy
- tokens (**57.15% lower**), while 260 recalls are timed. Packed context across the same 26
- samples averages **85.38** tokens and reaches **108** under a 1,500-token cap; Recall@5,
- hit@5, and answer-token recall remain 1.000. These aggregates are evidence ID
- `offline-performance` in the registry above. `--filler-memories`, `--candidate-k`, and
- `--retrieval-profile` make scaling and routing experiments executable, but their results need
- separate evidence before publication.
-- **Exact vector scale envelope**: `eval/vector_scale.py` measures the production
- `NumpyVectorIndex` directly at requested corpus sizes with deterministic normalized vectors and
- queries. It records a corpus fingerprint, result hashes, environment, and observed
- p50/p95/p99 search envelopes. It intentionally has no pass/fail latency threshold: the output
- describes the measured machine and workload, not a universal capacity cutoff. Pair it with
- `eval/performance.py` before making a deployment decision because direct vector search excludes
- the rest of the recall pipeline. Its `engraphis-vector-scale/v1` JSON is a local diagnostic, not
- an `engraphis-benchmark/v2` public evidence artifact.
-- **Proactive ranking calibration**: `eval/proactive_ranking.py` compares the previous and current
- importance-retention floors on a small deterministic queryless-ranking fixture. It reports
- top-1 accuracy and minimum expected margins for that fixture only. It is a scoring regression,
- not evidence of general recall quality or user-task performance.
-- **Workload context economy**: `eval/context_economy.py` compares three executable strategies
- across every question in a workload: uncapped full-history replay, a contiguous recency window
- at the same hard budget, and shipped Engraphis hybrid recall + packing. It reports evidence and
- answer-token quality, cumulative reader-context tokens, a conservative total that charges one
- complete source-token pass to indexing, and the query-count break-even point. The default is
- deterministic/offline; `--embed-model` enables a real retrieval model, while
- `--format locomo|longmemeval` reuses the established external loaders.
-- **Agent productivity**: `eval/productivity.py` compares a capped full-history baseline,
- always-on retrieval, and
- adaptive context through a complete answer-and-correction loop. It reports completed tasks,
- first-attempt errors, abstentions, corrections, agent turns, memory calls, wall-clock latency,
- and all question/context/output tokens. The bundled agent is deterministic, receives no gold
- answer, and is identified in every report; inject a real agent callable for model-specific
- results. Optional provider telemetry is reported separately from the deterministic token
- counter and is not a provider billing estimate.
-- **Dashboard graph layout settle**: `eval/graph_every_bench.py` drives the Every-node
- dashboard engine's real worker (`engraphis-graph-every-worker.js`) through a
- `prepare → settled` round-trip over synthetic node/link loads and reports wall-clock settle
- time plus the scaling ratio across sizes. It measures initial layout cost only: camera pans
- and zooms never touch the worker (they are GPU-uniform updates), so no per-frame number can
- come out of this harness and none should be quoted. Results are host- and Node-version
- dependent local diagnostics, not registered public evidence; run the harness on the target
- class of machine before quoting a figure.
-
-The context-economy and productivity tools intentionally report when a small workload does not
-benefit from memory, and the external loaders expose retrieval-quality tradeoffs rather than
-hiding them. Their prior local results are not retained as public numbers because no matching
-redacted immutable artifact is checked in. Run the registered protocol and publish the resulting
-artifact before making a quantitative claim.
-
-### Reproduce
-
-```bash
-# Correctness gate (deterministic, no download)
-python -m pytest tests/ -q
-python -m eval.harness --dataset eval/datasets/sample.jsonl --k 5
-python -m eval.harness --dataset eval/datasets/codemem.jsonl --k 5
-python -m eval.harness --dataset eval/datasets/graph_multihop.jsonl --k 5
-python -m eval.ablation
-python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10
-python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 \
- --candidate-k 25 --candidate-depth adaptive --retrieval-profile auto --iterations 10
-python -m eval.context_economy --dataset eval/datasets/codemem.jsonl \
- --token-budget 512 --k 5
-python -m eval.productivity --dataset eval/datasets/codemem.jsonl \
- --max-context-tokens 512 --retrieval-token-budget 256
-python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 \
- --iterations 5 --filler-memories 1000
-# Direct NumPy search envelope at representative corpus sizes; timings are machine-specific.
-python -m eval.vector_scale --sizes 1000,10000,100000 --queries 20 --iterations 3 --json
-# Deterministic queryless-ranking calibration fixture.
-python -m eval.proactive_ranking
-# Canonical latency/resource protocol: requires >=1,000 queries and five processes.
-python -m eval.performance --dataset fixed-1000-plus.jsonl --acceptance-matrix --processes 5
-
-# External retrieval diagnostics (downloads all-MiniLM-L6-v2; not QA/leaderboard results)
-python -m eval.external --dataset longmemeval_s.json --format longmemeval --k 10
-python -m eval.external --dataset locomo10.json --format locomo --k 10
-# Complete external-dataset coverage with an immutable embedding revision. This remains a
-# private diagnostic; it is not an official benchmark-harness or public evidence artifact.
-python -m eval.external --dataset longmemeval_s.json --format longmemeval --canonical \
- --embed-revision <40-character-model-commit> --json external-longmemeval.json
-python -m eval.external --dataset locomo10.json --format locomo --canonical --no-resolve \
- --embed-revision <40-character-model-commit> \
- --locomo-repair-manifest eval/datasets/locomo10_repair_manifest.json \
- --json external-locomo.json
-python -m eval.context_economy --dataset locomo10.json --format locomo \
- --embed-model sentence-transformers/all-MiniLM-L6-v2 --token-budget 512 --k 10 --no-resolve
-```
-
-Canonical external mode requires an exact lowercase 40-character embedding commit and a semantic
-embedder; dependency or model-load failure is fatal instead of silently falling back to hashing.
-Every report records `embedding`, `dataset_sha256`, `source_cases`, `normalized_cases`, and
-`configuration` provenance so a result can be attributed to the actual data and retrieval setup.
-
-The official ten-conversation LoCoMo JSON contains delimiter-packed IDs, two mechanical ID
-typos, and three references that cannot be normalized syntactically. The adapter normalizes only
-the unambiguous forms. The checked-in repair manifest is bound to the official source SHA-256,
-names every remaining replacement/removal, must be fully consumed, and is recorded in the JSON
-report with its own hash. Any source update, unused repair, or unresolved ID fails the run. This
-repairs retrieval references only; it does not claim to correct LoCoMo's semantic answer labels.
-
-A private pinned retrieval diagnostic was inspected during development, but its result artifact is
-not checked into the public evidence registry. This document therefore publishes none of that
-run's workload counts or scores. Reproduce it from the hash-bound source and repair manifest,
-export a public-safe immutable artifact, and validate its checksum before adding quantitative
-claims. Any future values remain evidence-retrieval metrics, not end-to-end QA accuracy or an
-official LoCoMo leaderboard score.
-
-## What we do NOT yet claim
-
-- **No official end-to-end LLM QA accuracy.** The deterministic productivity agent measures the
- complete local control loop, not a frontier answering model. Official LoCoMo / LongMemEval QA
- still requires a pinned answering model and evaluator.
-- **No hosted-service latency comparison.** The in-repo p50/p95/p99 benchmark covers the local
- reference pipeline and records its environment; unlike environments are not compared.
-- **No neutral third-party ranking.** We have not run an external eval platform.
-- **No provider bill estimate.** Context-economy counts reader evidence under its named counter.
- It excludes system/tool prompts, questions, completions, prompt caching, provider pricing,
- compute, and storage. Its indexing-inclusive total is a conservative text-volume proxy.
-
-Every publishable run should emit the `engraphis-benchmark/v2` envelope: dataset/config hashes,
-per-question records, explicit exclusions, fixed-budget context curves, and deterministic
-stratified or paired bootstrap confidence intervals. Every run names its token counter.
-Noncanonical offline fixtures may identify a deterministic estimate; canonical public evidence
-requires the exact pinned reader tokenizer and immutable model revision. The lightweight CI
-fixtures validate that machinery; they are not a claim about external benchmark performance.
-
-The benchmark context metric reads strict recall usage fields rather than inferring prompt size:
-`budget_tokens`, `context_tokens`, `source_tokens`, `saved_tokens`, `savings_ratio`,
-`packed_count`, `omitted_count`, and `token_counter`. Use `engraphis_recall_context` for a
-hard-budget prompt packet; legacy `engraphis_recall` remains available in full or compact response
-mode for compatibility.
-
-### Canonical public artifacts
-
-Use `python -m eval.benchmark --input report.json --output artifacts/run.json` to validate a
-report and write sorted, immutable JSON plus `run.json.sha256`. The command permits an identical
-retry but refuses to replace a different artifact at the same path. For an official
-LongMemEval-V2 run, add `--canonical`: this requires a profile with an exact benchmark repository
-revision, dataset revision, reader model revision, and embedding model revision. The checked-in
-profile pins immutable upstream commits; replacing any revision with a mutable tag fails
-validation. Canonical profiles label the baseline (`no_retrieval`, `lexical_only`, `dense_only`,
-`dense_lexical_rrf`, `full_hybrid`, `full_history`, `no_graph`, `no_reranker`,
-`no_temporal_resolution`, or `whole_document`) and declare the required fixed context-budget
-matrix: 256, 512, 1024, 2048, and 4096 tokens. Canonical in-repo reports rerun every question at
-all five budgets and validate each aggregate against its per-question evidence. The checked-in
-LongMemEval-V2 memory-module configuration sets the official adapter's operating point to 1,024
-tokens; that single official point must not be presented as a five-point curve.
-
-`eval.external --canonical` refuses `--limit` and rejects a normalized output that omitted source
-cases. Retrieval-only abstention/no-evidence records remain visible in the artifact's
-`exclusions`; they are not counted as evidence-retrieval scores.
-
-Official LongMemEval-V2 output can be converted into a public-safe QA artifact with
-`python -m eval.longmemeval_v2_evidence`. The exporter requires the completion manifest written by
-the pinned runner after a successful, complete official run. It binds the exact per-question
-output, questions, haystack, trajectories, memory configuration, matrix manifest, seed, clean
-official checkout, and recorded environment. The public artifact keeps the official QA score,
-fixed-reader context token count, aggregate source-file digests, repository state, and artifact
-checksum. It removes raw questions, answers, prompts, reader output, and retrieved context, and
-does not publish per-record content fingerprints. See the
-[`public benchmark runbook`](docs/PUBLIC_BENCHMARK_RUNBOOK.md) for the end-to-end operator sequence.
-
-### LongMemEval-V2 memory-module adapter
-
-`eval.longmemeval_v2.EngraphisLongMemEvalV2Memory` follows the official
-`memory_modules.memory.Memory` interface at LongMemEval-V2 commit
-`6f020ac2fc3275e46c706d3406e02c3ed79b7be2`. When imported in that environment, its
-`@register_memory` decorator registers `memory_type="engraphis"`; use the checked-in
-[`eval/configs/longmemeval_v2_engraphis.json`](eval/configs/longmemeval_v2_engraphis.json)
-with the official harness. The config pins `Qwen/Qwen3-Embedding-8B` to revision
-`1d8ad4ca9b3dd8059ad90a75d4983776a23d44af`; mutable embedding revisions are rejected, and a
-canonical adapter run fails instead of relabeling the deterministic offline fallback as Qwen.
-First materialize the six declared variants at all five token budgets:
-
-```bash
-python -m eval.longmemeval_v2_matrix \
- --output "$ENGRAPHIS_EVIDENCE_RUN_DIR/configs"
-```
-
-This writes a 30-run manifest: balanced, planner, episodic-cap, planner-plus-episodic-cap, and
-matched `context_k=2` comparators for both capped variants, each at 256, 512, 1,024, 2,048, and
-4,096 evidence tokens. Run each manifest cell through `python -m eval.run_longmemeval_v2` with all
-eight `--engraphis-*` completion-receipt arguments. The wrapper imports the adapter before the
-official registry builds the memory module, forces the pinned reader processor revision, and
-delegates the remaining official harness arguments unchanged. Only after a successful return does
-it verify that the output question IDs exactly cover the source question IDs and write the
-immutable execution manifest.
-
-The checked-in configuration is canonical only when the adapter resolves the pinned Qwen reader
-processor at `c202236235762e1c871ad0ccb60c8ee5ba337b9a`. The wrapper refuses a dirty or non-pinned
-official checkout and refuses to start if the optional processor dependency or immutable revision
-is unavailable; the local regex counter is never silently relabeled as a reader budget. The
-recorded budget counts each returned context item's content with that reader tokenizer (without
-prompt framing or inter-item separators), so it is a hard **evidence-item content** budget, not a
-claim about total chat-prompt tokens. Packed sources are returned as separate context items,
-preserving the largest fitting evidence prefix instead of dropping one oversized monolithic item.
-Every official per-question row reports inserted and retrieved counts by memory type. A
-memory-type-cap claim additionally requires at least two populated inserted types, so a nominal cap
-over a single-type workload cannot qualify as evidence. The adapter does not download benchmark
-data or call the reader/evaluator; the official harness owns those steps.
-
-## External evidence status and remaining executions
-
-1. **Run the official LongMemEval-V2 reader and evaluator.** The adapter, pinned runner, and
- redacted evidence exporter are implemented. The exact upstream commit boots in an isolated
- Python 3.11 environment and the wrapper reaches the official harness CLI. The dataset, pinned
- Qwen reader, and embedding assets require substantial storage and compute; no canonical QA
- score is claimed until that run completes.
-2. **Publish production-backend latency.** Run `eval/performance.py` with the real embedder and
- sqlite-vec/backend configuration on a fixed machine class and corpus scale.
-3. **Run the fixed-budget curve on the complete official datasets.** The v2 harness now measures
- every question at 256, 512, 1,024, 2,048, and 4,096 evidence tokens and validates the
- per-question records, aggregates, and pinned reader-tokenizer identity. Publish the curve only
- after complete official runs produce immutable artifacts for every point.
-4. **Run an external evaluation platform** once (1)–(3) exist.
-
-Do not make all evidence lanes variants of explicit factual recall. Executable offline adapters
-now cover:
-
-- [MemoryAgentBench](https://github.com/HUST-AI-HYZ/MemoryAgentBench): incremental multi-turn
- learning, long-range understanding, and conflict/consolidation inputs.
-- [LoCoMo-Plus](https://github.com/xjtuleeyf/Locomo-Plus): an old implicit constraint must affect
- a later response even when the later cue does not restate the remembered fact.
-- [Mem2ActBench](https://github.com/Cantaloupe-M/Mem2ActBench): memory must select a tool and
- ground its arguments, not merely return a passage. The current adapter measures retrieval and
- expected tool-argument context coverage, not generated tool-call success.
-
-```bash
-python -m eval.agent_benchmarks --dataset memoryagentbench.json \
- --format memoryagentbench
-python -m eval.agent_benchmarks --dataset locomo_plus.json \
- --format locomo_plus
-python -m eval.agent_benchmarks --dataset qa_dataset.jsonl \
- --conversations toolmem_conversation.jsonl --format mem2actbench \
- --artifact artifacts/mem2actbench.json
-```
-
-Use `--artifact` on any of these commands to write a redacted, immutable evidence envelope plus
-an adjacent SHA256 file. The ordinary console/`--json` report is private run material and may
-contain source questions for debugging.
-
-### Upstream-data diagnostics awaiting public artifacts
-
-The LoCoMo-Plus, MemoryAgentBench, and Mem2ActBench adapters have been exercised against upstream
-data and exposed useful product gaps. Their earlier local envelopes are not present in the
-checked-in evidence registry, so this document withholds their case counts, retrieval scores,
-token coverage, and throughput measurements. Rerun each adapter with `--artifact`, publish the
-redacted immutable envelope and checksum, and add its suite/config binding before quoting a
-number. Until then these lanes demonstrate executable plumbing only, not leaderboard,
-answer-quality, or marketing results.
-
-The MemoryAgentBench loader accepts both its aligned public JSON export and the Hugging Face
-dataset-server `rows[].row` envelope. Rows without gold evidence remain useful for answer-token
-coverage, but are excluded from retrieval aggregates and counted separately as
-`retrieval_scored_questions`.
-
-For paired code-agent runs, execute the same tasks with the same model, tools, machine, and
-deterministic success oracle under `full_history` and `engraphis`. Then analyze the content-free
-run records with:
-
-```bash
-python -m eval.code_agent_ab --full-history full-history.jsonl \
- --engraphis engraphis.jsonl --output paired-report.json
-```
-
-The analyzer rejects unmatched task IDs and different success oracles, then reports paired
-bootstrap intervals for task success, input/output/tool tokens, retries, latency, and optional
-cost. Its aggregate output does not echo task IDs or oracle commands. It does not launch an agent
-or invent a task-success oracle.
-
-## Optimization experiments to run before changing defaults
-
-1. **Budget-aware packing**: compare full source, safe summary, sentence-aligned safe summary
- excerpt, and raw-source excerpt at fixed budgets. Gate on support/answer retention and
- qualifier preservation, not token count alone.
-2. **Adaptive retrieval work**: `--candidate-depth adaptive` is an opt-in performance experiment.
- It keeps wider graph/code pools and reduces routine lexical/balanced pools while reporting the
- requested and actual depth. A local experiment motivated this option, but no public number is
- retained because its machine-specific artifact is not in the evidence registry. Keep the
- default fixed until complete external categories meet predeclared quality margins.
-3. **Packing-pressure consolidation**: prioritize memory families that are frequently recalled,
- repeatedly omitted, or costly per useful token. Count write/index/storage cost as well as later
- reader-context savings.
-4. **Tokenizer-aware ingestion**: implemented behind the chunk extractor. The dependency-free
- default remains `engraphis.chars4.v1`; an explicitly configured Hugging Face reader tokenizer
- enforces prose chunk and overlap budgets and records its identity in chunk metadata. Continue
- measuring tokens-to-evidence, recall, and storage/index growth together before recommending a
- model-specific default.
-5. **Bulk ingestion**: add batch embedding plus a transaction-aware vector upsert path, then rerun
- the complete MemoryAgentBench Test-Time Learning input. Gate this on identical stored-memory,
- provenance, graph-link, and temporal-resolution outcomes, not throughput alone.
-6. **Scoped caches**: benchmark query embeddings and repeat-recall results keyed by workspace,
- repo, time anchors, profile, and corpus version. Test invalidation correctness before claiming
- latency gains.
-7. **Privacy-safe real usage**: use `engraphis_context_savings` to let each workspace inspect
- aggregate source/context/saved tokens already present in content-free receipts. Keep unlike
- token counters separate and require a valid receipt chain before treating totals as auditable.
-
-## Evaluation question
-
-The predeclared question is whether the full vector + lexical/BM25 + sparse PPR graph + calibrated
-rerank pipeline, bi-temporal resolution, and grounded abstention produce higher evidence recall
-per injected token than the registered baselines. The answer must come from a complete,
-machine-readable artifact with paired confidence intervals; otherwise the release reports
-“no demonstrated improvement.”
+# Benchmarks
+
+This guide explains what Engraphis measures, how to reproduce each evaluation, and the limits of
+those results. When this document and the code disagree, the code is the source of truth.
+
+For the locked operator sequence for a public canonical run, see
+[`docs/PUBLIC_BENCHMARK_RUNBOOK.md`](docs/PUBLIC_BENCHMARK_RUNBOOK.md).
+
+### Public numeric evidence registry
+
+Every exact public aggregate retained below comes from the checked-in, public-safe
+[`offline-fixtures-v1.json`](docs/benchmark-evidence/offline-fixtures-v1.json) artifact. Its
+SHA-256 is
+`8a74e9f48e25f33d625d4cc5c1b14fec3055891944adccf615c440e84e4b0255`, also recorded in the
+adjacent `.sha256` file. The artifact contains no raw questions, answers, prompts, customer data,
+or per-record content fingerprints.
+
+The fixture-suite digest is
+`4d7e40607319cd4bf8caee3897f1e416dbe5b81998b37a7e4839409ee2923537`. The artifact defines
+the digest algorithm and records the SHA-256 of every suite and dataset file. Each evidence ID
+also binds its exact command through `sha256(UTF-8 exact command)`:
+
+| Evidence ID | Exact command | Config digest |
+|---|---|---|
+| `offline-chunking` | `python -m eval.chunking_eval --dataset eval/datasets/longdoc.jsonl --k 5` | `c1c8196aa7e1568ef3844a9fb2d76b87f342c39108e32d6ad144b885a76143b8` |
+| `offline-performance` | `python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10 --json` | `bbe4aca81e58d4830e50a8fc7729a1d15b71d97a6299bccd79432b7f119677d7` |
+| `offline-grounded` | `python -m eval.grounded` | `590442e51e3642c10489165759919dc86ffac62c182937330c153e7f8d5fc26f` |
+
+External, model-dependent, latency, consolidation, and productivity numbers are not published
+until a redacted immutable artifact with the same three bindings exists. Use the
+[public benchmark runbook](docs/PUBLIC_BENCHMARK_RUNBOOK.md) to produce that evidence; absence
+from this registry means no public number is claimed.
+
+## What we measure today (all offline, no API key)
+
+Most Engraphis evals score **retrieval**, not end-to-end QA. The separate productivity benchmark
+runs a complete offline agent attempt and correction loop, but it is not an official
+frontier-model QA score.
+
+- **Correctness gate**: `eval/harness.py` over `eval/datasets/sample.jsonl` and
+ `codemem.jsonl` (conflict resolution) and `graph_multihop.jsonl` (multi-hop graph recall).
+ Runs on the deterministic embedder, so it is a plumbing/regression floor, not a public
+ performance claim. This is the gate CI enforces.
+- **Ablation**: `eval/ablation.py`: vector-only vs. 1-hop graph vs. Personalized-PageRank arm,
+ to show the graph arm actually earns its place.
+- **External benchmarks**: `eval/external.py` loads **LoCoMo** and **LongMemEval** and pushes
+ them through the *real* `MemoryEngine` write path (conflict resolution + evolution) and hybrid
+ recall with a real sentence-transformers embedder. It reports `recall_at_k` / `hit_at_k` /
+ `answer_token_recall`: i.e. *did the evidence come back*, not *did an LLM answer correctly*.
+ It retains source categories and abstention/no-evidence questions as explicit exclusions from
+ retrieval-only aggregates rather than silently dropping them. `eval.longmemeval_v2` is a local,
+ text-only adapter for the official LongMemEval-V2 `insert(trajectory)` / `query(query,
+ query_image=None)` memory interface; it does not download data or call a model.
+- **Grounded**: `eval/grounded.py`: answerable → cite, off-topic → abstain. Exact fixture
+ outcomes are evidence ID `offline-grounded` in the registry above.
+- **Chunking (quality per token)**: `eval/chunking_eval.py` over `eval/datasets/longdoc.jsonl`
+ ingests a multi-topic corpus twice: once as one memory per document (`whole`) and once with
+ sub-file `ChunkingExtractor` (`chunked`), then queries both through the real recall pipeline.
+ The checked-in corpus is explicitly marked trusted eval data so the measurement isolates
+ chunking from the production trust gate, which excludes arbitrary raw imports from normal
+ agent context. On the deterministic embedder, **recall@5 is 1.000 for both modes; mean
+ retrieved top-5 content falls from 740.3 to 214.3 tokens (526.0 fewer, 71.1% lower, about
+ 3.5× smaller), while the smallest returned evidence-holding memory falls from 162.2 to 42.4
+ tokens (119.8 fewer, 73.9% lower, about 3.8× smaller).** These aggregates are evidence ID
+ `offline-chunking` in the registry above. Pass `--embed-model
+ sentence-transformers/all-MiniLM-L6-v2` to run a model-dependent experiment; do not publish
+ that result without a new immutable artifact and pinned model revision.
+- **Full-pipeline latency + quality**: `eval/performance.py` times the shipped semantic +
+ lexical + graph + fusion + scoring + rerank + packing path after warmup, with reinforcement
+ disabled so repeated measurements do not mutate their corpus. It reports p50/p95/p99 latency,
+ retrieval quality, packed context tokens, and full/compact JSON-shape payload proxies in one
+ JSON-safe schema. Payload proxies are sampled once per question, independently of the number
+ of timed iterations; they are not serialized MCP envelopes or transport responses. In the
+ registered CodeMem run, 26 payload samples total **23,810** full-proxy
+ `engraphis.regex.v1` tokens versus **10,202** compact-proxy tokens, avoiding **13,608** proxy
+ tokens (**57.15% lower**), while 260 recalls are timed. Packed context across the same 26
+ samples averages **85.38** tokens and reaches **108** under a 1,500-token cap; Recall@5,
+ hit@5, and answer-token recall remain 1.000. These aggregates are evidence ID
+ `offline-performance` in the registry above. `--filler-memories`, `--candidate-k`, and
+ `--retrieval-profile` make scaling and routing experiments executable, but their results need
+ separate evidence before publication.
+- **Exact vector scale envelope**: `eval/vector_scale.py` measures the production
+ `NumpyVectorIndex` directly at requested corpus sizes with deterministic normalized vectors and
+ queries. It records a corpus fingerprint, result hashes, environment, and observed
+ p50/p95/p99 search envelopes. It intentionally has no pass/fail latency threshold: the output
+ describes the measured machine and workload, not a universal capacity cutoff. Pair it with
+ `eval/performance.py` before making a deployment decision because direct vector search excludes
+ the rest of the recall pipeline. Its `engraphis-vector-scale/v1` JSON is a local diagnostic, not
+ an `engraphis-benchmark/v2` public evidence artifact.
+- **Proactive ranking calibration**: `eval/proactive_ranking.py` compares the previous and current
+ importance-retention floors on a small deterministic queryless-ranking fixture. It reports
+ top-1 accuracy and minimum expected margins for that fixture only. It is a scoring regression,
+ not evidence of general recall quality or user-task performance.
+- **Workload context economy**: `eval/context_economy.py` compares three executable strategies
+ across every question in a workload: uncapped full-history replay, a contiguous recency window
+ at the same hard budget, and shipped Engraphis hybrid recall + packing. It reports evidence and
+ answer-token quality, cumulative reader-context tokens, a conservative total that charges one
+ complete source-token pass to indexing, and the query-count break-even point. The default is
+ deterministic/offline; `--embed-model` enables a real retrieval model, while
+ `--format locomo|longmemeval` reuses the established external loaders.
+- **Agent productivity**: `eval/productivity.py` compares a capped full-history baseline,
+ always-on retrieval, and
+ adaptive context through a complete answer-and-correction loop. It reports completed tasks,
+ first-attempt errors, abstentions, corrections, agent turns, memory calls, wall-clock latency,
+ and all question/context/output tokens. The bundled agent is deterministic, receives no gold
+ answer, and is identified in every report; inject a real agent callable for model-specific
+ results. Optional provider telemetry is reported separately from the deterministic token
+ counter and is not a provider billing estimate.
+- **Dashboard graph layout settle**: `eval/graph_every_bench.py` drives the Every-node
+ dashboard engine's real worker (`engraphis-graph-every-worker.js`) through a
+ `prepare → settled` round-trip over synthetic node/link loads and reports wall-clock settle
+ time plus the scaling ratio across sizes. It measures initial layout cost only: camera pans
+ and zooms never touch the worker (they are GPU-uniform updates), so no per-frame number can
+ come out of this harness and none should be quoted. Results are host- and Node-version
+ dependent local diagnostics, not registered public evidence; run the harness on the target
+ class of machine before quoting a figure.
+
+The context-economy and productivity tools intentionally report when a small workload does not
+benefit from memory, and the external loaders expose retrieval-quality tradeoffs rather than
+hiding them. Their prior local results are not retained as public numbers because no matching
+redacted immutable artifact is checked in. Run the registered protocol and publish the resulting
+artifact before making a quantitative claim.
+
+### Reproduce
+
+```bash
+# Correctness gate (deterministic, no download)
+python -m pytest tests/ -q
+python -m eval.harness --dataset eval/datasets/sample.jsonl --k 5
+python -m eval.harness --dataset eval/datasets/codemem.jsonl --k 5
+python -m eval.harness --dataset eval/datasets/graph_multihop.jsonl --k 5
+python -m eval.ablation
+python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10
+python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 \
+ --candidate-k 25 --candidate-depth adaptive --retrieval-profile auto --iterations 10
+python -m eval.context_economy --dataset eval/datasets/codemem.jsonl \
+ --token-budget 512 --k 5
+python -m eval.productivity --dataset eval/datasets/codemem.jsonl \
+ --max-context-tokens 512 --retrieval-token-budget 256
+python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 \
+ --iterations 5 --filler-memories 1000
+# Direct NumPy search envelope at representative corpus sizes; timings are machine-specific.
+python -m eval.vector_scale --sizes 1000,10000,100000 --queries 20 --iterations 3 --json
+# Deterministic queryless-ranking calibration fixture.
+python -m eval.proactive_ranking
+# Canonical latency/resource protocol: requires >=1,000 queries and five processes.
+python -m eval.performance --dataset fixed-1000-plus.jsonl --acceptance-matrix --processes 5
+
+# External retrieval diagnostics (downloads all-MiniLM-L6-v2; not QA/leaderboard results)
+python -m eval.external --dataset longmemeval_s.json --format longmemeval --k 10
+python -m eval.external --dataset locomo10.json --format locomo --k 10
+# Complete external-dataset coverage with an immutable embedding revision. This remains a
+# private diagnostic; it is not an official benchmark-harness or public evidence artifact.
+python -m eval.external --dataset longmemeval_s.json --format longmemeval --canonical \
+ --embed-revision <40-character-model-commit> --json external-longmemeval.json
+python -m eval.external --dataset locomo10.json --format locomo --canonical --no-resolve \
+ --embed-revision <40-character-model-commit> \
+ --locomo-repair-manifest eval/datasets/locomo10_repair_manifest.json \
+ --json external-locomo.json
+python -m eval.context_economy --dataset locomo10.json --format locomo \
+ --embed-model sentence-transformers/all-MiniLM-L6-v2 --token-budget 512 --k 10 --no-resolve
+```
+
+Canonical external mode requires an exact lowercase 40-character embedding commit and a semantic
+embedder; dependency or model-load failure is fatal instead of silently falling back to hashing.
+Every report records `embedding`, `dataset_sha256`, `source_cases`, `normalized_cases`, and
+`configuration` provenance so a result can be attributed to the actual data and retrieval setup.
+
+The official ten-conversation LoCoMo JSON contains delimiter-packed IDs, two mechanical ID
+typos, and three references that cannot be normalized syntactically. The adapter normalizes only
+the unambiguous forms. The checked-in repair manifest is bound to the official source SHA-256,
+names every remaining replacement/removal, must be fully consumed, and is recorded in the JSON
+report with its own hash. Any source update, unused repair, or unresolved ID fails the run. This
+repairs retrieval references only; it does not claim to correct LoCoMo's semantic answer labels.
+
+A private pinned retrieval diagnostic was inspected during development, but its result artifact is
+not checked into the public evidence registry. This document therefore publishes none of that
+run's workload counts or scores. Reproduce it from the hash-bound source and repair manifest,
+export a public-safe immutable artifact, and validate its checksum before adding quantitative
+claims. Any future values remain evidence-retrieval metrics, not end-to-end QA accuracy or an
+official LoCoMo leaderboard score.
+
+## What we do NOT yet claim
+
+- **No official end-to-end LLM QA accuracy.** The deterministic productivity agent measures the
+ complete local control loop, not a frontier answering model. Official LoCoMo / LongMemEval QA
+ still requires a pinned answering model and evaluator.
+- **No hosted-service latency comparison.** The in-repo p50/p95/p99 benchmark covers the local
+ reference pipeline and records its environment; unlike environments are not compared.
+- **No neutral third-party ranking.** We have not run an external eval platform.
+- **No provider bill estimate.** Context-economy counts reader evidence under its named counter.
+ It excludes system/tool prompts, questions, completions, prompt caching, provider pricing,
+ compute, and storage. Its indexing-inclusive total is a conservative text-volume proxy.
+
+Every publishable run should emit the `engraphis-benchmark/v2` envelope: dataset/config hashes,
+per-question records, explicit exclusions, fixed-budget context curves, and deterministic
+stratified or paired bootstrap confidence intervals. Every run names its token counter.
+Noncanonical offline fixtures may identify a deterministic estimate; canonical public evidence
+requires the exact pinned reader tokenizer and immutable model revision. The lightweight CI
+fixtures validate that machinery; they are not a claim about external benchmark performance.
+
+The benchmark context metric reads strict recall usage fields rather than inferring prompt size:
+`budget_tokens`, `context_tokens`, `source_tokens`, `saved_tokens`, `savings_ratio`,
+`packed_count`, `omitted_count`, and `token_counter`. Use `engraphis_recall_context` for a
+hard-budget prompt packet; legacy `engraphis_recall` remains available in full or compact response
+mode for compatibility.
+
+### Canonical public artifacts
+
+Use `python -m eval.benchmark --input report.json --output artifacts/run.json` to validate a
+report and write sorted, immutable JSON plus `run.json.sha256`. The command permits an identical
+retry but refuses to replace a different artifact at the same path. For an official
+LongMemEval-V2 run, add `--canonical`: this requires a profile with an exact benchmark repository
+revision, dataset revision, reader model revision, and embedding model revision. The checked-in
+profile pins immutable upstream commits; replacing any revision with a mutable tag fails
+validation. Canonical profiles label the baseline (`no_retrieval`, `lexical_only`, `dense_only`,
+`dense_lexical_rrf`, `full_hybrid`, `full_history`, `no_graph`, `no_reranker`,
+`no_temporal_resolution`, or `whole_document`) and declare the required fixed context-budget
+matrix: 256, 512, 1024, 2048, and 4096 tokens. Canonical in-repo reports rerun every question at
+all five budgets and validate each aggregate against its per-question evidence. The checked-in
+LongMemEval-V2 memory-module configuration sets the official adapter's operating point to 1,024
+tokens; that single official point must not be presented as a five-point curve.
+
+`eval.external --canonical` refuses `--limit` and rejects a normalized output that omitted source
+cases. Retrieval-only abstention/no-evidence records remain visible in the artifact's
+`exclusions`; they are not counted as evidence-retrieval scores.
+
+Official LongMemEval-V2 output can be converted into a public-safe QA artifact with
+`python -m eval.longmemeval_v2_evidence`. The exporter requires the completion manifest written by
+the pinned runner after a successful, complete official run. It binds the exact per-question
+output, questions, haystack, trajectories, memory configuration, matrix manifest, seed, clean
+official checkout, and recorded environment. The public artifact keeps the official QA score,
+fixed-reader context token count, aggregate source-file digests, repository state, and artifact
+checksum. It removes raw questions, answers, prompts, reader output, and retrieved context, and
+does not publish per-record content fingerprints. See the
+[`public benchmark runbook`](docs/PUBLIC_BENCHMARK_RUNBOOK.md) for the end-to-end operator sequence.
+
+### LongMemEval-V2 memory-module adapter
+
+`eval.longmemeval_v2.EngraphisLongMemEvalV2Memory` follows the official
+`memory_modules.memory.Memory` interface at LongMemEval-V2 commit
+`6f020ac2fc3275e46c706d3406e02c3ed79b7be2`. When imported in that environment, its
+`@register_memory` decorator registers `memory_type="engraphis"`; use the checked-in
+[`eval/configs/longmemeval_v2_engraphis.json`](eval/configs/longmemeval_v2_engraphis.json)
+with the official harness. The config pins `Qwen/Qwen3-Embedding-8B` to revision
+`1d8ad4ca9b3dd8059ad90a75d4983776a23d44af`; mutable embedding revisions are rejected, and a
+canonical adapter run fails instead of relabeling the deterministic offline fallback as Qwen.
+First materialize the six declared variants at all five token budgets:
+
+```bash
+python -m eval.longmemeval_v2_matrix \
+ --output "$ENGRAPHIS_EVIDENCE_RUN_DIR/configs"
+```
+
+This writes a 30-run manifest: balanced, planner, episodic-cap, planner-plus-episodic-cap, and
+matched `context_k=2` comparators for both capped variants, each at 256, 512, 1,024, 2,048, and
+4,096 evidence tokens. Run each manifest cell through `python -m eval.run_longmemeval_v2` with all
+eight `--engraphis-*` completion-receipt arguments. The wrapper imports the adapter before the
+official registry builds the memory module, forces the pinned reader processor revision, and
+delegates the remaining official harness arguments unchanged. Only after a successful return does
+it verify that the output question IDs exactly cover the source question IDs and write the
+immutable execution manifest.
+
+The checked-in configuration is canonical only when the adapter resolves the pinned Qwen reader
+processor at `c202236235762e1c871ad0ccb60c8ee5ba337b9a`. The wrapper refuses a dirty or non-pinned
+official checkout and refuses to start if the optional processor dependency or immutable revision
+is unavailable; the local regex counter is never silently relabeled as a reader budget. The
+recorded budget counts each returned context item's content with that reader tokenizer (without
+prompt framing or inter-item separators), so it is a hard **evidence-item content** budget, not a
+claim about total chat-prompt tokens. Packed sources are returned as separate context items,
+preserving the largest fitting evidence prefix instead of dropping one oversized monolithic item.
+Every official per-question row reports inserted and retrieved counts by memory type. A
+memory-type-cap claim additionally requires at least two populated inserted types, so a nominal cap
+over a single-type workload cannot qualify as evidence. The adapter does not download benchmark
+data or call the reader/evaluator; the official harness owns those steps.
+
+## External evidence status and remaining executions
+
+1. **Run the official LongMemEval-V2 reader and evaluator.** The adapter, pinned runner, and
+ redacted evidence exporter are implemented. The exact upstream commit boots in an isolated
+ Python 3.11 environment and the wrapper reaches the official harness CLI. The dataset, pinned
+ Qwen reader, and embedding assets require substantial storage and compute; no canonical QA
+ score is claimed until that run completes.
+2. **Publish production-backend latency.** Run `eval/performance.py` with the real embedder and
+ sqlite-vec/backend configuration on a fixed machine class and corpus scale.
+3. **Run the fixed-budget curve on the complete official datasets.** The v2 harness now measures
+ every question at 256, 512, 1,024, 2,048, and 4,096 evidence tokens and validates the
+ per-question records, aggregates, and pinned reader-tokenizer identity. Publish the curve only
+ after complete official runs produce immutable artifacts for every point.
+4. **Run an external evaluation platform** once (1)–(3) exist.
+
+Do not make all evidence lanes variants of explicit factual recall. Executable offline adapters
+now cover:
+
+- [MemoryAgentBench](https://github.com/HUST-AI-HYZ/MemoryAgentBench): incremental multi-turn
+ learning, long-range understanding, and conflict/consolidation inputs.
+- [LoCoMo-Plus](https://github.com/xjtuleeyf/Locomo-Plus): an old implicit constraint must affect
+ a later response even when the later cue does not restate the remembered fact.
+- [Mem2ActBench](https://github.com/Cantaloupe-M/Mem2ActBench): memory must select a tool and
+ ground its arguments, not merely return a passage. The current adapter measures retrieval and
+ expected tool-argument context coverage, not generated tool-call success.
+
+```bash
+python -m eval.agent_benchmarks --dataset memoryagentbench.json \
+ --format memoryagentbench
+python -m eval.agent_benchmarks --dataset locomo_plus.json \
+ --format locomo_plus
+python -m eval.agent_benchmarks --dataset qa_dataset.jsonl \
+ --conversations toolmem_conversation.jsonl --format mem2actbench \
+ --artifact artifacts/mem2actbench.json
+```
+
+Use `--artifact` on any of these commands to write a redacted, immutable evidence envelope plus
+an adjacent SHA256 file. The ordinary console/`--json` report is private run material and may
+contain source questions for debugging.
+
+### Upstream-data diagnostics awaiting public artifacts
+
+The LoCoMo-Plus, MemoryAgentBench, and Mem2ActBench adapters have been exercised against upstream
+data and exposed useful product gaps. Their earlier local envelopes are not present in the
+checked-in evidence registry, so this document withholds their case counts, retrieval scores,
+token coverage, and throughput measurements. Rerun each adapter with `--artifact`, publish the
+redacted immutable envelope and checksum, and add its suite/config binding before quoting a
+number. Until then these lanes demonstrate executable plumbing only, not leaderboard,
+answer-quality, or marketing results.
+
+The MemoryAgentBench loader accepts both its aligned public JSON export and the Hugging Face
+dataset-server `rows[].row` envelope. Rows without gold evidence remain useful for answer-token
+coverage, but are excluded from retrieval aggregates and counted separately as
+`retrieval_scored_questions`.
+
+For paired code-agent runs, execute the same tasks with the same model, tools, machine, and
+deterministic success oracle under `full_history` and `engraphis`. Then analyze the content-free
+run records with:
+
+```bash
+python -m eval.code_agent_ab --full-history full-history.jsonl \
+ --engraphis engraphis.jsonl --output paired-report.json
+```
+
+The analyzer rejects unmatched task IDs and different success oracles, then reports paired
+bootstrap intervals for task success, input/output/tool tokens, retries, latency, and optional
+cost. Its aggregate output does not echo task IDs or oracle commands. It does not launch an agent
+or invent a task-success oracle.
+
+## Optimization experiments to run before changing defaults
+
+1. **Budget-aware packing**: compare full source, safe summary, sentence-aligned safe summary
+ excerpt, and raw-source excerpt at fixed budgets. Gate on support/answer retention and
+ qualifier preservation, not token count alone.
+2. **Adaptive retrieval work**: `--candidate-depth adaptive` is an opt-in performance experiment.
+ It keeps wider graph/code pools and reduces routine lexical/balanced pools while reporting the
+ requested and actual depth. A local experiment motivated this option, but no public number is
+ retained because its machine-specific artifact is not in the evidence registry. Keep the
+ default fixed until complete external categories meet predeclared quality margins.
+3. **Packing-pressure consolidation**: prioritize memory families that are frequently recalled,
+ repeatedly omitted, or costly per useful token. Count write/index/storage cost as well as later
+ reader-context savings.
+4. **Tokenizer-aware ingestion**: implemented behind the chunk extractor. The dependency-free
+ default remains `engraphis.chars4.v1`; an explicitly configured Hugging Face reader tokenizer
+ enforces prose chunk and overlap budgets and records its identity in chunk metadata. Continue
+ measuring tokens-to-evidence, recall, and storage/index growth together before recommending a
+ model-specific default.
+5. **Bulk ingestion**: add batch embedding plus a transaction-aware vector upsert path, then rerun
+ the complete MemoryAgentBench Test-Time Learning input. Gate this on identical stored-memory,
+ provenance, graph-link, and temporal-resolution outcomes, not throughput alone.
+6. **Scoped caches**: benchmark query embeddings and repeat-recall results keyed by workspace,
+ repo, time anchors, profile, and corpus version. Test invalidation correctness before claiming
+ latency gains.
+7. **Privacy-safe real usage**: use `engraphis_context_savings` to let each workspace inspect
+ aggregate source/context/saved tokens already present in content-free receipts. Keep unlike
+ token counters separate and require a valid receipt chain before treating totals as auditable.
+
+## Evaluation question
+
+The predeclared question is whether the full vector + lexical/BM25 + sparse PPR graph + calibrated
+rerank pipeline, bi-temporal resolution, and grounded abstention produce higher evidence recall
+per injected token than the registered baselines. The answer must come from a complete,
+machine-readable artifact with paired confidence intervals; otherwise the release reports
+“no demonstrated improvement.”
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 934a999b..950fdb84 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
All notable changes to Engraphis are documented here. Format loosely follows
[Keep a Changelog](https://keepachangelog.com/); versions use SemVer.
-## [Unreleased]
+## [1.7] - 2026-09-03
### Added
@@ -200,10 +200,10 @@ All notable changes to Engraphis are documented here. Format loosely follows
the matching `RecallEngine(arm_candidate_k_cap=...)` constructor argument) that clamps both
the first-page widening (`candidate_k + min(250, candidate_k*3)`) and the second-page
ceiling, so operators can trade untrusted-scope widening for latency on the new k=50
- default without code changes. The accompanying benchmark test,
- `test_recall_arm_candidate_k_cap.py`, uses a 300-fact trusted corpus because both requested
- arm depths clamp to the same 49 rows on a smaller corpus and the timing assertion was
- unreliable. Default behaviour is unchanged.
+ default without code changes. The accompanying benchmark test,
+ `test_recall_arm_candidate_k_cap.py`, uses a 300-fact trusted corpus because both requested
+ arm depths clamp to the same 49 rows on a smaller corpus and the timing assertion was
+ unreliable. Default behaviour is unchanged.
- Import previews now page the source manifest exactly like execution, so vaults whose manifest
outgrew one list page (10k identities) no longer show manifest-only files as silently absent
from the preview plan; beyond-boundary rows are reported as `missing` instead of dropped.
diff --git a/README.md b/README.md
index 03b97dc3..4ac7de0d 100644
--- a/README.md
+++ b/README.md
@@ -1,853 +1,871 @@
-# Engraphis
-
-[](https://pypi.org/project/engraphis/)
-[](https://github.com/Coding-Dev-Tools/engraphis/blob/main/LICENSE)
-[](https://buymeacoffee.com/Jaixii)
-
-[https://engraphis.com/](https://engraphis.com/)
-
-[https://discord.com/invite/Wfr2ejBmY](https://discord.com/invite/Wfr2ejBmY)
-
-**Give your AI agents a memory. See it, search it, and maintain it, all in a beautiful WebUI on your own machine.**
-
-
-
-
- Knowledge Graph · run engraphis-dashboard to see it live
-
-
-**Grounded, not guessed.** Memory with receipts. Local by default.
-
----
-
-> **Open-core boundary:** this repository contains the free local engine, dashboard, MCP server,
-> and customer-side clients. Hosted sync, analytics, automation, and team services run on the
-> official hosted service; their server implementations are not distributed here.
-
-> **Support continued Engraphis development with Pro.** [Start a 3-day Pro trial](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_intro&trial=pro#billing)
-> or [subscribe to Pro](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_intro#billing).
-
----
-
-## Measured token and context savings
-
-### Runtime estimator
-
-The dashboard Overview and Audit/Receipts views also show a receipt-backed estimate from
-real context deliveries. It compares the host history or retrieved source baseline with the
-context Engraphis actually emitted, keeps token counters and release versions separate, and
-labels adaptive history reductions separately from packing savings. Receipts without estimator
-metadata remain historical/unclassified. This measures estimated prompt-context reduction; it
-does not measure provider billing. The `/context-savings` API and
-`engraphis_context_savings` MCP tool aggregate the complete history across all visible workspaces
-by default, or accept an explicit workspace plus optional `from_ts`, `to_ts`, and
-`release_version` filters.
-
-
-
-
- Less repeated history means more room for the task, tools, and useful evidence.
-
-
-
-See benchmark details and reproduce the results
-
-### Controlled before-and-after example
-
-| Retrieval mode | Mean returned memory content | Recall@5 |
-|---|---:|---:|
-| Whole documents | 740.3 tokens | 1.000 |
-| Engraphis structure-aware chunks | 214.3 tokens | 1.000 |
-
-The chunked mode returns the relevant passage instead of the whole document: **526.0 fewer tokens
-per question**. Under the same model-context budget, that leaves roughly **526 tokens** for task
-instructions or other relevant evidence. This is evidence ID `offline-chunking` in the registered
-artifact below.
-
-### Measurement details and reproducibility
-
-The table below contains every exact token/context aggregate currently published here and keeps
-its counting boundary explicit.
-
-| What is counted | Comparison | Measured reduction | Quality held constant |
-|---|---|---|---|
-| Retrieved top-5 memory content, averaged per question | Whole documents: **740.3** tokens → structure-aware chunks: **214.3** tokens | **526.0 fewer tokens per question** (**71.1% lower**, about **3.5× smaller**) | Recall@5 **1.000** in both modes across 6 documents and 18 questions |
-| Smallest returned memory that contains the reference evidence | Whole documents: **162.2** tokens → chunks: **42.4** tokens | **119.8 fewer tokens to evidence** (**73.9% lower**, about **3.8× smaller**) | The same 18 questions had a returned evidence-holding memory in both modes |
-| Full versus compact recall payload proxy across one 26-question pass within a 260-timed-recall CodeMem run | Full proxy: **23,810** `engraphis.regex.v1` tokens → compact proxy: **10,202** tokens | **13,608 proxy tokens avoided** (**57.15% lower**) | 26 payload samples; 260 timed recalls; Recall@5, hit@5, and answer-token recall all **1.000** |
-| Packed prompt-context usage in the same 26-question CodeMem sample pass | Hard budget: **1,500** tokens; observed mean: **85.38**; observed maximum: **108** | A hard cap prevents a recall from exceeding its configured context budget | This is usage accounting, not a before/after savings comparison |
-
-These values are evidence IDs `offline-chunking` and `offline-performance` in
-[`offline-fixtures-v1.json`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/benchmark-evidence/offline-fixtures-v1.json),
-SHA-256
-`0f60b0868444f676fe14c5f94d7db2c475e22669930c4d760881d0842eaa6800`.
-[`BENCHMARKS.md`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/BENCHMARKS.md#public-numeric-evidence-registry)
-records the matching suite digest, exact commands, and per-command config digests. External,
-model-dependent, consolidation, productivity, and latency results remain unpublished until the
-same evidence exists for them.
-
-The compact payload shape avoids duplicating full memory bodies when the packed context and source
-list are enough. The evaluator tokenizes JSON-shaped full and compact payload proxies built from
-recall results; it does **not** serialize the MCP envelope or measure a transport response. The
-fixture therefore does not measure model-provider charges, end-to-end task time, or customer cost
-savings.
-
-The measures are deliberately separate and **must not be added together**: chunking counts the
-content of retrieved memory records before `ContextPacker`, whereas compact recall counts a
-serialized JSON-shape payload proxy. “Tokens to evidence” is the size of the smallest
-retrieved memory record holding the reference evidence; it is not latency or end-to-end answer
-accuracy. Chunking creates more focused stored records, so this is a context-efficiency result,
-not a storage-reduction claim.
-
-Reproduce the registered quality and token/context measurements without a network connection or
-API key:
-
-```bash
-python -m eval.grounded
-python -m eval.chunking_eval --dataset eval/datasets/longdoc.jsonl --k 5
-python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10 --json
-```
-
-These are small deterministic correctness and efficiency fixtures, not official LoCoMo /
-LongMemEval QA scores or a third-party leaderboard result. Compact-response counts use the exact
-`engraphis.regex.v1` counter; the chunking evaluation uses its documented deterministic
-normalized-character estimator. Chunking measures retrieved memory content, while compact recall
-measures a serialized JSON-shape payload proxy, not an MCP transport response. See the registered
-artifact and [`BENCHMARKS.md`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/BENCHMARKS.md)
-for definitions, limitations, and canonical external-evaluation requirements.
-
-
-
----
-
-## Full Engraphis install: pip install "engraphis[all]"
-
-The complete `engraphis[all]` install is the default way to use Engraphis: it includes the local
-dashboard, Smart MCP server, documents, Cloud Sync client, and supported optional integrations.
-Python 3.10+ is required.
-
-```bash
-pip install "engraphis[all]"
-engraphis-dashboard
-```
-
-The dashboard opens at [http://127.0.0.1:8700](http://127.0.0.1:8700). Local memory needs no
-account or API key.
-
-### Smaller installation options
-
-Use a smaller package only when you intentionally need a limited surface. The NumPy-only core
-continues to support Python 3.9+.
-
-| Goal | Install | Start |
-|---|---|---|
-| Local dashboard and REST API | `pip install "engraphis[server]"` | `engraphis-dashboard` |
-| Coding-agent memory over Smart MCP | `pip install "engraphis[mcp]"` | `codex mcp add engraphis -- engraphis-mcp` |
-| Native SQLite vector acceleration | `pip install "engraphis[vector]"` | Server entrypoints select it automatically |
-| Offline Python library | `pip install engraphis` | `MemoryService.create("engraphis.db")` |
-
-For MCP clients other than Codex, configure a stdio server whose command is `engraphis-mcp`; see
-the [agent connection guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/AGENT_CONNECT.md).
-
-### Updating
-
-Use `engraphis-update` to upgrade the installation using its detected install method. Package
-metadata does not record which extras were selected, so the updater defaults to the safe
-superset `engraphis[all]` rather than silently dropping an optional surface. For a deliberate
-selection, set `ENGRAPHIS_UPDATE_EXTRAS` to a comma-separated list (for example
-`server,mcp`), or set it to `none` for the base package only.
-
-> **Upgrading to 1.4:** `engraphis-mcp` now exposes the nine-tool Smart gateway. Integrations that
-> require the former 35 direct tool names should run `engraphis-mcp-classic`. The SQLite schema
-> in the 1.4.0 release was version 9. Existing v7-to-v8 databases already contain `confidence`
-> and `pinned_at`/`unpinned_at`; v9 adds the `memory_tombstones` repository-scope column/table
-> and performs a one-time entity-canonicalization repair, then migrates automatically on first
-> open. A tombstone with a known `repo_id` is terminal only in that repository; legacy repo-less
-> tombstones remain global. See the [1.4.0 release notes](https://github.com/Coding-Dev-Tools/engraphis/blob/main/CHANGELOG.md#140---2026-08-02).
-
-> **Upgrading to 1.5:** schema 10 bounds legacy retention state and schema 11 backfills explicit
-> approval only for eligible pre-review local memories. Pending and quarantined evidence remains
-> gated. Existing 1.4.x databases migrate automatically when Engraphis 1.5 opens them; see the
-> [1.5 release notes](https://github.com/Coding-Dev-Tools/engraphis/blob/main/CHANGELOG.md#15---2026-08-04).
-
-> **Upgrading to 1.6:** existing 1.5 databases migrate automatically through schema 12, which
-> classifies content-free erasure markers before sync: existing markers become local-only
-> `never_export`, while new secure erasures become `remote_erasure` only for non-secret
-> `workspace`/`repo` records already eligible for sharing. Schema 13 adds per-memory hybrid
-> logical clocks for deterministic descriptive-state sync and durable, content-free proof that a
-> memory crossed a sync boundary. Schema 14 adds the Obsidian collection and import manifests;
-> schema 15 generalizes them to source-neutral local documents, preserves temporal source lineage
-> across re-imports, binds adapters and target scopes, and retains only bounded, content-free
-> per-job format/result metadata. The schema 16 migration persists each import job's optional session target
-> and requires source lineage and job-item attachments to remain in that exact session. See the
-> [1.6 release notes](https://github.com/Coding-Dev-Tools/engraphis/blob/main/CHANGELOG.md#16---2026-08-15).
-
----
-
-## What Engraphis gives an agent
-
-An agent should not have to reconstruct a project from scattered chat history on every task.
-Engraphis turns local project knowledge into scoped, time-aware memory; retrieves the evidence
-that supports the current question; and returns a bounded, attributable context packet.
-
-The core task is continuity: retrieve the current, supported project decision without dragging the
-whole history into the next prompt. See [measured token and context savings](#measured-token-and-context-savings)
-for the short version of how much less history an agent has to carry.
-
-| Agent need | What Engraphis changes |
-|---|---|
-| Remember a project across sessions | Stores typed memory in a `workspace → repo → session` hierarchy and provides a last-session handoff. |
-| Find support for the current task | Fuses vector, lexical, graph, and code-aware retrieval instead of relying on one search signal; `fast` can skip graph traversal for small or latency-sensitive vaults. |
-| Know what is true now and what changed | Preserves bi-temporal history and supersession chains instead of silently overwriting a fact. |
-| Avoid confident guesses | Returns cited evidence or explicitly abstains when support is too weak. |
-| Avoid dragging the whole project into every prompt | Packs context to a configured hard budget and can return a compact MCP response. |
-| Keep knowledge in the operator's control | Runs local-first and offline-capable, with scopes, audit records, and optional privacy-safe receipts. |
-
-## Dashboard and local UI
-
-The Engraphis dashboard opens `http://127.0.0.1:8700`. Local memory needs no cloud account,
-signup, or API key and stays in a SQLite file on your machine.
-
-**Ledger** is the primary local interface for recall, memories, graph exploration, provenance,
-workspaces, and manual consolidation. **Classic** preserves the former full tool suite; both use
-the same local data. Switch in **Manage → Settings → Interface** (Ledger) or **Settings →
-Appearance & Engine** (Classic).
-
-### Start it on every platform
-
-| Platform | How |
-|----------|-----|
-| **Windows** | Double-click **Engraphis Dashboard** on your Desktop or Start Menu (install: `engraphis-dashboard --install-shortcuts`) |
-| **macOS** | Double-click **Engraphis Dashboard.app** on your Desktop (install: same command) |
-| **Linux** | Desktop entry in Applications → Development (GNOME/KDE/etc.) |
-| **Docker** | `docker compose up`: see `docker-compose.yml` for the one-command deployment |
-| **Any** | `engraphis-dashboard` in a terminal |
-
-In a source checkout, `scripts/launch_dashboard.ps1` is only a Windows convenience wrapper. It
-delegates configuration, startup health, browser opening, and process lifecycle to the same
-`engraphis-dashboard` entrypoint rather than maintaining a second behavior path.
-
-### Accessibility-first inspection, built in
-
-Inspect memories, supersession diffs, recall scores, timelines, links, consolidation, and audit
-records in the dashboard. The offline graph renderer is vendored, and the interface is keyboard-
-navigable with light and dark themes. Graph exploration offers a focused **High quality** view and
-an explicit worker-backed **Every node** view for complete entity projections up to 20,000
-nodes and 200,000 relationships; see the [graph performance profiles](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/GRAPH_PERFORMANCE.md).
-
----
-
-## How it works
-
-Engraphis gives agents durable, scoped, *explainable* project knowledge. The local engine combines
-Ebbinghaus decay, bi-temporal facts, and hybrid vector/lexical/graph recall; it runs offline with
-SQLite, local embeddings, and `numpy` only.
-
-- **Grounded and governed:** deterministic conflict resolution, cited answers or abstention,
- explicit correction/promotion/forgetting, and a complete history.
-- **Agent-ready:** MCP tools, hard-budget context packets, handoffs, and code-aware retrieval.
-- **Auditable:** content-free receipt chains, provenance, and temporal/entity/code relationships.
-- **Practical:** local file and code ingest, optional PDF/OCR/transcription, and SQLCipher at rest.
-
-### Optional LLM providers
-
-The memory engine, embeddings, conflict resolution, and recall stay local without an LLM. An
-explicitly configured provider adds structured extraction, cited synthesis, consolidation, and
-retention supervision. Configure it in **Settings → Connect an LLM**. The activity view records
-outcomes, never keys, prompts, or raw provider responses. See the
-[LLM provider guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LLM_PROVIDERS.md) for setup and privacy choices.
-
-> Privacy boundary: text sent to an explicitly selected provider leaves the local process under
-> that provider's terms. Use `ENGRAPHIS_RETENTION_SUPERVISOR=none` (the default) and the offline
-> `chunk` extractor when ingestion must remain entirely local.
-
-Choose and configure an external LLM with the [LLM provider guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LLM_PROVIDERS.md),
-including OpenAI, Anthropic, Google, OpenRouter, Ollama, Cohere Command, Command Code Provider,
-and other compatible endpoints. The guide also covers Codex subscription MCP connections.
-
----
-
-## Install
-
-```bash
-pip install "engraphis[all]" # self-hosted dashboard, MCP, code graph, documents, transcription, PostgreSQL, and Cloud Sync
-pip install "engraphis[server]" # dashboard + REST API
-pip install "engraphis[mcp]" # MCP server only
-pip install "engraphis[documents]" # PDF + image OCR bindings
-pip install "engraphis[transcription]" # faster-whisper audio/video
-pip install "engraphis[postgres]" # PostgreSQL schema introspection
-pip install "engraphis[code]" # tree-sitter code graph indexing
-pip install "engraphis[vector]" # native sqlite-vec exact-KNN acceleration
-pip install "engraphis[cloud-sync]" # Cloud Sync client crypto/runtime
-pip install "engraphis[encryption]" # SQLCipher encryption-at-rest extra
-pip install engraphis # core library: numpy only, fully offline
-```
-
-The official Docker image includes the local Tesseract executable for image OCR. Outside
-Docker, the `documents` extra installs its Python bindings; install Tesseract through your
-operating system as well if you enable image OCR.
-
-The NumPy-only core library supports Python 3.9+. Current patched releases of the WebUI
-stack, MCP SDK, image parser, and Cloud Sync client require Python 3.10+, so use Python 3.10
-or newer for the `server`, `mcp`, `documents`, `cloud-sync`, or `all` installation paths.
-
-The default `NumpyVectorIndex` performs an exact full scan. There is no universal memory-count
-cutoff because latency depends on vector size, hardware, filters, and the rest of the recall
-pipeline. Measure your machine with `python -m eval.vector_scale --backend numpy`, then run
-`python -m eval.performance` on a representative corpus. If exact scans miss your latency target,
-install `engraphis[vector]`, create the engine with `vector_backend="sqlite-vec"`, and remeasure.
-The stable sqlite-vec `vec0` backend executes exact KNN in native code; it is acceleration, not a
-claim of sublinear ANN scaling. See [BENCHMARKS.md](https://github.com/Coding-Dev-Tools/engraphis/blob/main/BENCHMARKS.md) for the reproducible commands
-and reporting limits.
-
-Dashboard, REST, and MCP entrypoints default to `ENGRAPHIS_VECTOR_BACKEND=auto`: they use
-sqlite-vec when the `vector` extra is installed and compatible, then safely fall back to NumPy.
-Programmatic `MemoryEngine.create()` and `MemoryService.create()` retain the deterministic
-`numpy` default unless a backend is requested explicitly.
-Use `python -m eval.vector_scale --backend sqlite-vec` for an input-identical direct-search
-comparison; setup/index-build time is explicitly excluded from the timed search envelope.
-
-Persistent vectors fail closed unless the embedder can publish a durable, secret-free space
-fingerprint. Sentence Transformers use the loaded Hub commit or a manifest of local artifacts;
-when a remote model's immutable identity cannot be resolved, persistent vector recall remains
-gated instead of mixing spaces. For programmatic OpenAI-compatible embeddings, construct
-`ApiEmbedder` with an operator/provider `space_version`; without it the adapter remains usable for
-ephemeral embedding only. Its `base_url` may be a provider root or a `/v1` root and is normalized
-to exactly one `/v1/embeddings` endpoint.
-
-`sqlcipher3-binary` publishes CPython manylinux x86-64 wheels. On that target,
-`engraphis[encryption]` installs the driver. The cross-platform `all` extra deliberately
-omits it so `all` remains resolvable on macOS, Windows, Linux ARM, and musl; on those
-targets, provision a compatible SQLCipher driver separately before enabling a database
-key. The programmatic core remains plaintext unless a database key is configured. For a
-fresh database, `engraphis-init` enables SQLCipher automatically when a compatible driver is
-available, creates a private key sidecar, and can be overridden with `--no-encryption`.
-
-> **Linux / macOS:** if `pip install` fails with `error: externally-managed-environment`,
-> your system Python is marked read-only (PEP 668). Install into a virtual environment
-> instead. Run `python3 -m venv venv && source venv/bin/activate && pip install "engraphis[server]"`
-> Alternatively, use Docker (`docker compose up`). `pipx install "engraphis[server]"` also works.
-
-> First run downloads `all-MiniLM-L6-v2` (~80 MB). Without it, the engine falls back
-> to deterministic feature hashing so it always runs offline. That fallback captures lexical
-> overlap, not meaning: recall and grounded MCP responses set `degraded_mode=true` and
-> `semantic_support=false`, and disable vector retrieval plus semantic-cosine evidence. Install
-> a declared embedding model for semantic retrieval.
-
-> To require a model that is already local, set `ENGRAPHIS_EMBED_MODEL=local:/absolute/model/path`
-> or `local:`. This path never downloads a model. If it is unavailable, Engraphis
-> explicitly enters lexical degraded mode instead of presenting hash-vector scores as semantic.
-
----
-
-## Quickstart: dashboard
-
-```bash
-pip install "engraphis[server]"
-engraphis-dashboard # → http://127.0.0.1:8700
-engraphis-dashboard --install-shortcuts # → Desktop + Start Menu icons
-```
-
-### Docker
-
-```bash
-docker compose up # → http://127.0.0.1:8700
-```
-
-For Docker Compose persistence and loopback-port configuration, see the
-[Docker deployment guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/DOCKER.md).
-`engraphis-server` and `engraphis server` are headless compatibility aliases
-for this same v2 service, so every public surface has the same scoped recall and retention model.
-
-For optional LAN exposure, token configuration, and HTTP MCP setup, see the
-[Docker deployment guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/DOCKER.md).
-
-Set `ENGRAPHIS_API_TOKEN` to require API authentication and `ENGRAPHIS_DB_KEY` to encrypt
-the local database at rest. Hosted-plan credentials configure customer clients; they do not
-install premium server implementations into this image. See `docker-compose.yml` for options.
-
----
-
-## Quickstart: MCP server (for coding agents)
-
-```bash
-pip install "engraphis[mcp]"
-engraphis-init # writes ~/.engraphis/config.env + prints config snippets
-claude mcp add engraphis -- engraphis-mcp
-codex mcp add engraphis -- engraphis-mcp # Codex subscription
-
-```
-For Codex subscription setup and verification, see the [agent connection guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/AGENT_CONNECT.md)
-and the [LLM provider guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LLM_PROVIDERS.md).
-
-`engraphis-mcp` is zero-configuration Smart MCP: agents begin with nine compact tools for sessions,
-prompt-ready recall, durable memory, governed record read/update, conflict review, action discovery,
-and safe execution. For code graphs,
-governance, audit, or other advanced work, the agent calls `engraphis_discover_actions` and then
-the indicated read or action executor; no profile selection is required. The gateway validates
-the discovered capability again before it runs it, and clients remain responsible for their
-normal destructive-action approval boundary.
-
-Existing clients that pin the historical 35 named tools can use
-`engraphis-mcp-classic` (or `engraphis-mcp-http --classic`). The complete classic inventory,
-including `engraphis_check_update`, is in the [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md).
-
-### Pi extension
-
-For installation, configuration, lifecycle commands, and the local trust boundary, see the
-[Pi extension guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/integrations/pi/README.md).
-
-### Command Code SessionStart hook
-
-`integrations/commandcode/` ships a SessionStart hook that warms up a new
-session with bounded, recalled context from the local Engraphis gateway. Fails
-open on timeout and is installed via `python scripts/install_cc_hook.py`.
-
-### prime-agent fleet
-
-`integrations/prime_agent/` ships a first-party Python package for
-[PrimeIntellect prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
-that exposes the same nine Smart MCP tools, with a `PrimeAgentFleet` of eight
-named sub-agents (`researcher`, `planner`, `coder`, `reviewer`, `tester`,
-`documenter`, `monitor`, `integrator`) sharing one `engraphis-mcp` stdio
-subprocess. Install via `pip install ./integrations/prime_agent` and register
-with `python scripts/install_prime_agent.py`. See the
-[prime-agent integration guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/integrations/prime_agent/README.md).
-
-**What the integration is.** A `PrimeAgentFleet` is a thin Python layer
-around the same `engraphis-mcp` Smart gateway every other host uses. At
-runtime the fleet holds one shared `EngraphisMcpClient`, which owns one
-`engraphis-mcp` subprocess over JSON-RPC stdio. Each of the eight named
-sub-agents gets its own Engraphis session (started lazily on first tool use)
-and its own default `repo` scope, so per-role memory is isolated while the
-local gateway stays single-process. The eight sub-agent names
-(`researcher`, `planner`, `coder`, `reviewer`, `tester`, `documenter`,
-`monitor`, `integrator`) are the fixed default; pass `agent_names=[...]` to
-`PrimeAgentFleet(...)` for a custom set. Concurrent tool calls serialize at
-the JSON-RPC frame layer through an `asyncio.Lock`, so framework-level
-parallelism (eight sub-agents reasoning at once) is preserved while the
-underlying MCP transport remains one ordered stream. The only integration
-surface is `EngraphisPrimeAgent.register()` in
-`integrations/prime_agent/src/engraphis_prime_agent/agent.py` -- that is the
-single adapter point to override if prime-agent's tool-registration API
-differs from the assumed `target.register_tool(name, fn, schema=...)`
-contract.
-
-The design -- eight named sub-agents, one shared stdio subprocess,
-per-agent session bootstrap, and `ENGRAPHIS_*`-only environment forwarding
-to the gateway -- is recorded in `~/.commandcode/plans/prime-agent-integration.md`
-on the host where the integration was developed. When that host plan is not
-available (other contributor machines, CI), the same design is summarized in
-the PR description that introduced the integration and in the
-[prime-agent integration guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/integrations/prime_agent/README.md)
-("Architecture" and "Concurrency model" sections).
-
-## Quickstart: repository graph
-
-```bash
-pip install "engraphis[code]"
-engraphis-graph index -w acme -r api --root .
-engraphis-graph search -w acme -r api "UserService"
-# `query`/`explain` blend code search with your stored memories: query matches symbol
-# and file NAMES (a full question sentence won't match anything), and explain's answer
-# is drawn from memories recorded against the repo; both are empty on a fresh index.
-engraphis-graph query -w acme -r api "UserService"
-engraphis-graph explain -w acme -r api "why does deploy depend on approval?"
-engraphis-graph path -w acme -r api UserService DatabasePool
-engraphis-graph impact -w acme -r api --root . --git-range origin/main...HEAD
-engraphis-graph prs -w acme -r api --base main --head HEAD
-engraphis-graph export -w acme -r api -o engraphis-graph-out
-engraphis-graph install-merge-driver --root .
-```
-
-The export contains `graph.json`, a self-contained `graph.html`, and `GRAPH_REPORT.md`.
-Indexing supports Python, JavaScript, TypeScript, Go, Rust, Java, C#, C, C++, SQL, and
-Terraform. Tree-sitter is used when available; the dependency-free regex backend remains a
-functional fallback. Definitions, methods, calls, imports, ownership, variables,
-inheritance/implementation, and docstrings/comments are indexed. Indexing is incremental by
-content hash, honors `.engraphisignore`, and does not follow file symlinks outside the repository
-root. Call edges are name-based and best-effort rather than type-resolved. The optional Git merge
-driver validates bounded graph JSON and deterministically unions nodes and edges instead of
-choosing one export side.
-
-For a read-only recall and graph API that can be shared without exposing write operations:
-
-```bash
-pip install "engraphis[server]"
-engraphis-graph-server # API at http://127.0.0.1:8720; schema at /openapi.json
-```
-
-A non-loopback bind fails closed unless `ENGRAPHIS_GRAPH_TOKEN` (or
-`ENGRAPHIS_API_TOKEN`) is set. See [the v3 architecture/design document](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/ARCHITECTURE_V3.md).
-
----
-
-## Quickstart: Python library
-
-```python
-from engraphis.service import MemoryService
-
-mem = MemoryService.create("engraphis.db")
-mem.remember("Auth migrated from JWT to PASETO.", workspace="acme", repo="api")
-hit = mem.recall("why did we change auth?", workspace="acme", repo="api")
-print(hit["context"])
-```
-
-The same `MemoryService` backs the dashboard and the MCP server. The package root also
-intentionally exposes the low-level engine facade (`MemoryEngine`, `create_memory_engine`)
-for advanced composition, while `MemoryService` remains the high-level service API.
-
-New writes support `session`, `repo`, and `workspace` visibility. `scope="user"` is reserved and
-rejected until records carry an immutable owner identity; it must not be treated as private
-per-person memory. Historical user-scope rows remain workspace-bound for compatibility.
-
-After an upgrade, `stats()` reports prompt-eligibility counts and active embedding-space
-coverage. Zero-result recall identifies a review-gated scope instead of silently looking empty,
-and `engraphis-cli review list|approve` provides a dry-run-first local bulk workflow. Embedding
-model changes trigger a guarded rebuild; vector recall stays disabled until every stored vector
-matches the new fingerprint. See [recall recovery](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/RECALL_RECOVERY.md).
-
-Agent hosts can avoid retrieval when their existing history already fits:
-
-```python
-decision = mem.adaptive_context(
- "what should the agent do next?",
- current_history,
- workspace="acme",
- repo="api",
- max_context_tokens=8_192,
- retrieval_token_budget=1_024,
-)
-prompt_context = decision["context"]
-```
-
-The decision is `history_bypass` when the history fits, `retrieval` when compact evidence is
-strong, and `history_fallback` when weak retrieval should widen back to recent raw history.
-
-For an agent prompt, prefer `engraphis_recall_context`: it returns one hard-budget packed
-`context` plus compact `sources`, deterministic `usage` accounting (`budget_tokens`, `context_tokens`,
-`source_tokens`, `saved_tokens`, `savings_ratio`, `packed_count`, `omitted_count`, and
-`token_counter`), and optional diagnostics. Accounting is exact for the named counter; inject the
-reader's tokenizer when reader-model token parity is required. `engraphis_recall` remains the compatible full-recall
-surface; use `response_mode="compact"` when the packed context is enough and full memory bodies
-would duplicate it. For advanced query-planning configuration, see the
-[architecture guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/ARCHITECTURE_V3.md#query-planning).
-
-For bi-temporal reads, `valid_at` selects what was true at a Unix timestamp and `known_at` selects
-what Engraphis had learned then. `as_of` remains a compatibility alias for `valid_at`; supplying
-both is allowed only when they match.
-
-For a mutable claim, pass a stable `subject_key` and optional `claim_kind`, such as
-`subject_key="api.rate_limit", claim_kind="configured_value"`. Offline conflict resolution
-deterministically adds, reinforces, relates, or supersedes records while preserving temporal
-history; it does not need an LLM. Matching claim identities let it supersede substantially
-reworded mutable facts. Without them, the dependency-free lexical embedder cannot reliably infer
-that a paraphrase is a contradiction, so keep both records or use an explicit `correct` operation.
-
----
-
-## Govern memories without losing history
-
-Engraphis separates automatic write resolution from explicit human governance:
-
-| Operation | Use it when | What happens to history |
-|---|---|---|
-| `remember` | Adding or restating one fact | Adds, reinforces, safely supersedes, or relates an uncertain neighbor |
-| `correct` | Replacing one known-wrong memory | Closes the old validity window and links the replacement |
-| `promote` | A narrow learning now applies more broadly | Writes a wider-scope successor and closes/links the source instead of editing scope in place |
-| `merge` | Combining two or more overlapping memories | Retires every source and creates one memory that supersedes all of them |
-| `retire` | Removing a memory from live recall | Bi-temporally closes it; the audit/history record remains |
-| `consolidate` | Distilling recurring episodic memories automatically | Creates linked semantic digests; source episodes remain live |
-
-Manual N→1 merge is available through `MemoryService.merge()` and `POST /api/merge`:
-
-```python
-a = mem.remember("Deploys happen Friday at 3pm.", workspace="acme")
-b = mem.remember("We deploy Fridays around 15:00.", workspace="acme")
-
-merged = mem.merge(
- [a["id"], b["id"]],
- "Deploys ship every Friday at approximately 15:00.",
- workspace="acme",
- reason="deduplicate the deployment schedule",
-)
-print(merged["compaction"])
-```
-
-`retire` is intentionally not deletion: it preserves temporal history, FTS, and vector
-evidence for historical reads. If a credential was captured, new writes are blocked before
-storage; for a legacy leak use the explicitly destructive `MemoryService.secure_erase()` or
-`POST /api/secure-erase`/`engraphis_secure_erase`. That flow removes the one memory and local
-FTS/vector-index and derived graph/link rows, runs SQLite secure-delete, WAL checkpoint, and
-VACUUM, and scans recognised local SQLite recovery backups. It cannot erase exports, filesystem
-snapshots, remote peers, unknown backups, or information a running/compromised agent already
-read; rotate the credential. See [secure-erasure limits](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SECURE_ERASURE.md). `forget`
-remains a deprecated compatibility alias for `retire`.
-
-All sources must belong to the named workspace. The result inherits the strictest source
-sensitivity, remains untrusted if any source was untrusted, and stays pinned if any source was
-pinned. The full multi-predecessor chain remains visible through inspection, Why, and Timeline.
-
----
-
-## Free forever vs. hosted plans
-
-The core engine, local dashboard, MCP server, and manual consolidation are Apache-2.0 and free.
-**Pro and Team are services** that provide optional access to the official hosted service; its
-control-plane, billing, relay, compute, and Team identity modules live in a private repository.
-They do not limit the local core. See
-[hosted plans](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/HOSTED_PLANS.md), [licensing](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LICENSING.md), and
-[Cloud Sync](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SYNC.md) for service boundaries, lifecycle, and pricing.
-
-[Subscribe to Pro](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_pricing#billing)
-to support the project and add hosted services.
-
-[Compare hosted plans](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_intro#billing)
-when you are ready to evaluate the service boundary and billing options.
-
-| | Free (available now) | Pro: $10/mo or $100/yr | Team: $20/seat/mo or $200/seat/yr |
-|---|---|---|---|
-| Dashboard WebUI (with built-in inspector) | ✓ | ✓ | ✓ |
-| Memory engine + Smart MCP (Classic 35-tool compatibility) | ✓ | ✓ | ✓ |
-| Version-chain diffs, offline knowledge graph | ✓ | ✓ | ✓ |
-| Manual local consolidation (dry-run by default) | ✓ | ✓ | ✓ |
-| Local workspace export (portable v2 JSON: memories, source manifests, graph/code evidence, sessions, audit, and receipts) | ✓ | ✓ | ✓ |
-| Hosted Cloud Sync | | ✓ | ✓ |
-| Hosted Analytics | | ✓ | ✓ |
-| Hosted Auto Consolidation + retention policy | | ✓ | ✓ |
-| Hosted Auto Dreaming + managed proposals | | ✓ | ✓ |
-| Priority support | | ✓ | ✓ |
-| Hosted multi-user dashboard: invitations, logins, roles, seat management | | | ✓ |
-| Hosted Team audit log + CSV export | | | ✓ |
-| 72-hour pending invitations (resend/revoke) | | | ✓ |
-| Scoped, expiring per-user agent and sync tokens | | | ✓ |
-
----
-
-## MCP tools
-
-Engraphis exposes a zero-configuration Smart MCP gateway plus a 35-tool Classic compatibility
-server across memory, recall, code graphs, governance, sessions, and privacy-safe audit receipts.
-The focused [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md) is the source for
-the full inventory and parameters.
-
----
-
-## Graphs and privacy-safe receipts
-
-Memory, entity, and code relationships live in one local graph. Engraphis also provides
-content-free operation receipts for inspectable audit evidence. See the
-[architecture](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/ARCHITECTURE_V3.md), [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md), and
-[security policy](https://github.com/Coding-Dev-Tools/engraphis/blob/main/SECURITY.md) for the data model, tools, and guarantees.
-
----
-
-## Cloud sync
-
-Cloud Sync is an optional hosted Pro/Team service. The public package includes the customer client
-and deterministic merge implementation; hosted relay and account operations are separate. See
-[Cloud Sync](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SYNC.md) for setup, encryption, merge behavior, and the local folder exchange.
-
-The public package ships the same sync client as a console script and CLI verb:
-`engraphis-sync` (installed entry point), `engraphis sync ...`, and
-`python -m scripts.sync --status` for local-only state without network activity. See
-[Cloud Sync](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SYNC.md) for
-flags, encryption, merge behavior, and the local folder exchange.
-
----
-
-## Security and trust boundaries
-
-Engraphis is local-first and binds to loopback by default. Read the
-[security policy](https://github.com/Coding-Dev-Tools/engraphis/blob/main/SECURITY.md) before remote deployment or integrating external resources; it
-covers supported versions, data protections, threat model, and vulnerability reporting.
-
----
-
-## Encryption at rest
-
-Set `ENGRAPHIS_DB_KEY` (or `ENGRAPHIS_DB_KEY_FILE`) and install the extra:
-
-```bash
-pip install "engraphis[encryption]"
-```
-
-The entire main memory database file is transparently encrypted with AES-256 via SQLCipher;
-full-text search, the graph, and every query keep working unchanged. Customer authentication
-and managed-service state use their respective deployment protections. When a key is set for the
-main database, Engraphis **fails closed with an error** rather than silently falling back to
-plaintext. Generate a strong key:
-
-```bash
-python -c "import secrets; print(secrets.token_hex(32))"
-```
-
-When using `ENGRAPHIS_DB_KEY_FILE`, provision a regular secret file readable only by the
-service identity. Engraphis rejects links, reparse points, hard links, malformed text, and
-oversized key files rather than following an unexpected filesystem object.
-
-> An existing plaintext database cannot be opened with a key: migrate it (dump → import
-> into a fresh keyed DB). See `.env.example` for all encryption options.
-
----
-
-## Import files and folders
-
-The dependency-free universal core scans Markdown, plain text, RST, HTML, JSON/JSONL, CSV/TSV,
-configuration/XML text, source code, RTF, DOCX/ODT, XLSX/ODS, PPTX/ODP, and EPUB into the normal
-v2 memory path. Installed local resource adapters add PDF text, image OCR, and explicitly
-local-model audio/video transcription.
-Start with a zero-write
-preview, then confirm the same source collection explicitly:
-
-```bash
-engraphis import documents /path/to/collection --workspace acme --dry-run
-engraphis import documents /path/to/collection --workspace acme --repo product --yes
-```
-
-The CLI never downloads an embedding model during import. Use a model that is already cached,
-set `ENGRAPHIS_EMBED_MODEL=local:/absolute/model/path`, or explicitly set
-`ENGRAPHIS_EMBED_MODEL` to an empty value to use dependency-free deterministic hashing in
-lexical degraded mode.
-
-The dashboard’s **Import local documents** flow offers the same preview, target scope, source
-label, conflict policy, cancellation, and resumable progress. Re-imports are idempotent,
-preserve temporal history, and report source removals without hard-deleting memories. Obsidian
-remains the rich Markdown adapter for frontmatter, aliases, wikilinks, and attachment references:
-
-```bash
-engraphis import obsidian /path/to/vault --workspace acme --dry-run
-```
-
-See the [document import guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/DOCUMENT_IMPORT.md)
-for supported formats, source safety, resume and conflict behavior, optional adapters, and
-limitations; see the [Obsidian adapter guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/OBSIDIAN_IMPORT.md)
-for Markdown-specific behavior.
-
----
-
-## Consolidation and automation
-
-Manual consolidation is free, local, and dry-run by default; use the dashboard, SDK, CLI, or
-MCP. Hosted Pro and Team automation is optional managed compute that produces reviewable
-proposals rather than silently changing local data. See [hosted plans](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/HOSTED_PLANS.md),
-[licensing](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LICENSING.md), and the [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md) for scope and use.
-
----
-
-## Configuration
-
-Values come from the process environment. Engraphis also loads the owner-private
-`~/.engraphis/config.env`; `ENGRAPHIS_ENV_FILE` can select another absolute owner-private regular
-file. It never searches the working directory for `.env`, and explicit process variables win.
-
-| Env Var | Default | Description |
-|---------|---------|-------------|
-| `ENGRAPHIS_ENV_FILE` | `~/.engraphis/config.env` | Optional trusted config leaf selected before trusted values load. Its bounded dependency-free parser performs no interpolation. An explicit value must be an absolute path to an owner-private regular file; arbitrary working-directory `.env` files are ignored. |
-| `ENGRAPHIS_DB_PATH` | Source: `/engraphis.db`; installed: platform user-data directory | SQLite database file. Installed defaults are `%LOCALAPPDATA%\engraphis\engraphis.db` (Windows), `~/Library/Application Support/engraphis/engraphis.db` (macOS), and `$XDG_DATA_HOME/engraphis/engraphis.db` or `~/.local/share/engraphis/engraphis.db` (Linux). The environment variable overrides every default; a relative value is resolved from the trusted `~/.engraphis/config.env` directory so launch CWD cannot select a different workspace database. |
-| `ENGRAPHIS_HOST` | `127.0.0.1` | Server bind address |
-| `ENGRAPHIS_PORT` | `8700` | Dashboard port |
-| `ENGRAPHIS_SERVICE_MODE` | `customer` | The public package supports only `customer`; hosted vendor, relay, compute, and worker roles are not distributed here |
-| `ENGRAPHIS_API_TOKEN` | Not set | Optional bearer credential for this single-user local customer node; never reuse a hosted credential |
-| `ENGRAPHIS_CORS_ORIGINS` | loopback on `ENGRAPHIS_PORT` | Comma-separated REST CORS allow-list; defaults to `127.0.0.1` and `localhost` on the configured port |
-| `ENGRAPHIS_INDEX_ROOTS` | Working, home, and temporary directories | Optional path-separator-delimited absolute-path allow-list that replaces the default roots accepted by local code indexing |
-| `ENGRAPHIS_HTTP_INDEX_ROOT` | First `ENGRAPHIS_INDEX_ROOTS` entry, or current directory | Single root for dashboard and REST `POST /api/code/index`; submitted paths resolve beneath it. An explicit root (or fallback entry) must be absolute; an explicit HTTP root is included in the engine-approved set. MCP and CLI indexing continue to use `ENGRAPHIS_INDEX_ROOTS`. |
-| `ENGRAPHIS_DB_KEY` | Not set | Encrypt the database at rest (SQLCipher). Or use `ENGRAPHIS_DB_KEY_FILE` |
-| `ENGRAPHIS_EMBED_MODEL` | `sentence-transformers/all-MiniLM-L6-v2` | sentence-transformers model |
-| `ENGRAPHIS_EMBED_REVISION` | Not set | Optional immutable lowercase 40-hex Hugging Face commit for the embedding model. Loaded Hub commits or local artifact manifests identify persistent vector spaces; unresolved mutable identities keep vector recall fail-closed. |
-| `ENGRAPHIS_RERANK_MODEL` | Not set | Optional sentence-transformers cross-encoder reranker |
-| `ENGRAPHIS_RERANK_REVISION` | Not set | Optional immutable lowercase 40-hex Hugging Face commit for the reranker |
-| `ENGRAPHIS_REQUIRE_IMMUTABLE_MODELS` | `false` | When enabled, require a 40-hex commit before loading remote embedding models, rerankers, or chunk tokenizers; `local:` selectors and filesystem paths remain permitted |
-| `ENGRAPHIS_REQUIRE_EXACT_BACKENDS` | `false` | When enabled, dashboard and standalone MCP startup fails if a configured optional backend is unavailable instead of silently falling back |
-| `ENGRAPHIS_EXTRACTOR` | `none` | `none` = verbatim; `chunk` = offline structure-aware chunks; `llm` = free-form LLM facts; `llm_structured` = schema-validated facts + graph metadata |
-| `ENGRAPHIS_CHUNK_TOKENIZER_MODEL` | Not set | Optional Hugging Face tokenizer used to enforce chunk budgets with the downstream reader's real tokenization; requires the optional `transformers` package |
-| `ENGRAPHIS_CHUNK_TOKENIZER_REVISION` | Not set | Optional immutable tokenizer/model revision recorded in the chunk-counter identity; pin this for reproducible benchmark artifacts |
-| `ENGRAPHIS_GRAPH_EXTRACTOR` | `regex` | `regex` = offline heuristic NER; `none` = disable heuristic text extraction (validated `llm_structured` metadata still feeds the graph) |
-| `ENGRAPHIS_RETENTION_SUPERVISOR` | `none` | `none` = deterministic only; `llm` = sends a bounded excerpt to the configured provider for advisory ephemeral/normal/critical classification |
-| `ENGRAPHIS_ALLOW_AUTOMATIC_CRITICAL_RETENTION` | `false` | Opt in only when an LLM supervisor may automatically assign the long-lived `critical` class; explicit user-selected critical retention is unaffected |
-| `ENGRAPHIS_WHISPER_MODEL` | Not set | Enables local faster-whisper audio/video transcription |
-| `ENGRAPHIS_POSTGRES_DSN` | Not set | CLI-only PostgreSQL source; used for the connection and never stored |
-| `ENGRAPHIS_POSTGRES_CONNECT_TIMEOUT` | `10` | PostgreSQL introspection connection timeout in seconds (bounded to 1--120) |
-| `ENGRAPHIS_POSTGRES_STATEMENT_TIMEOUT_MS` | `30000` | Per-introspection PostgreSQL statement timeout in milliseconds (bounded to 1--300000) |
-| `ENGRAPHIS_GRAPH_TOKEN` | Not set | Bearer token for `engraphis-graph-server`; required off-loopback |
-| `ENGRAPHIS_GRAPH_HOST` / `ENGRAPHIS_GRAPH_PORT` | `127.0.0.1` / `8720` | Read-only graph/recall server bind address |
-| `ENGRAPHIS_LLM_PROVIDER` | `openai` | `openai \| anthropic \| google \| openrouter \| custom` |
-| `ENGRAPHIS_LLM_MODEL` | `gpt-4o-mini` | Model name (provider-specific) |
-| `ENGRAPHIS_LLM_API_KEY` | Not set | API key for chat/synthesis, `llm` / `llm_structured` extraction, and structured consolidation |
-| `ENGRAPHIS_LLM_BASE_URL` | Not set | Base URL for openrouter / custom OpenAI-compatible endpoints |
-| `ENGRAPHIS_LLM_AUTO_EXTRACT` | `0` | Opt in to switching the running engine to `llm_structured` after a successful live connection test; the dashboard's extraction Off button persists `0`, and its On button restores `1` |
-| `ENGRAPHIS_FORWARDED_ALLOW_IPS` | *(none)* | Proxies trusted for forwarded client/TLS headers (`*` only when the service is reachable exclusively through that proxy) |
-| `ENGRAPHIS_LOCAL_TRUSTED_PEERS` | *(none)* | Exact peers/CIDRs treated as local without forwarding headers; use only for trusted Docker/LAN peers, never public deployments |
-| `ENGRAPHIS_UPDATE_CACHE` | `86400` | Update-check cache TTL in seconds, bounded to `1..31622400`; this is never a cache-file path |
-| `ENGRAPHIS_UPDATE_CHECK` | Off | Opt-in release reminder surfaced in the dashboard, server startup log, and MCP. Update checks run only when this is set to an affirmative value; `0` keeps them off. |
-| `ENGRAPHIS_UPDATE_URL` | Not set | Overrides the release-check source URL; the outbound client accepts HTTPS and rejects private/reserved destinations. |
-| `ENGRAPHIS_CLOUD_CONTROL_URL` | hosted default | Official entitlement, organization, and credential control API. A saved rotating credential stays bound to the control endpoint recorded for its family; reconnect to change it. |
-| `ENGRAPHIS_CLOUD_COMPUTE_URL` | hosted default | Official Analytics and managed-automation API. A saved rotating credential stays bound to its recorded compute endpoint; reconnect to change it. |
-| `ENGRAPHIS_CLOUD_ORGANIZATION_ID` | Not set | Hosted organization bound to this customer session |
-| `ENGRAPHIS_CLOUD_REFRESH_CREDENTIAL` | Not set | Bootstrap-only rotating hosted credential; after first use the owner-only cloud session replacement takes precedence |
-| `ENGRAPHIS_CLOUD_TOKEN_SUBJECT` | `member` | Subject fixed during hosted bootstrap (`device` or `member`); set explicitly with an environment-only refresh credential |
-| `ENGRAPHIS_CLOUD_ACCESS_TOKEN` | Not set | Optional short-lived access token for ephemeral jobs |
-| `ENGRAPHIS_MANAGED_COMPUTE_CONSENT` | *(auto)* | Operator override only; default follows whether a cloud session is configured (connected = allowed, local-only = never). `0` opts a connected installation out; `1` permits local snapshot preparation but does not create a cloud credential or authorize an upload |
-
-The optional cross-encoder reranker is model- and hardware-dependent. Treat its quality and
-latency as deployment-specific until a versioned model identity, exact configuration, and
-reproducible evaluation artifact are available for the comparison being reported.
-
-See `.env.example` for the full variable inventory. Supply those values through the process
-environment or the trusted config file above; copying it to an arbitrary `./.env` does not make
-Engraphis load it.
-
-> **Ablation fixture:** `python -m eval.ablation` is an offline deterministic check that prints
-> `recall@5` comparisons for vector-only and hybrid retrieval, multi-hop graph arms, and
-> retrieval policies, plus ordinary-recall age and semantic-confidence checks. It does not
-> produce MRR, hit@5, or ms/query results. Use `python -m eval.reinforcement` for retention
-> trajectories, and register evidence before quoting any benchmark results.
-
----
-
-## Project structure
-
-```
-engraphis/
-├── engraphis/
-│ ├── core/ # v2 engine: interfaces, store, recall, scoring, schema, sync
-│ ├── backends/ # pluggable embedder / vector index / reranker / codegraph / sync transports / encryption
-│ ├── factory.py # outer v2 composition root; selects and injects concrete backends
-│ ├── service.py # validated MemoryService facade
-│ ├── mcp_server.py # Smart MCP gateway + 35-tool Classic compatibility server
-│ ├── dashboard_app.py # dashboard WebUI (FastAPI)
-│ ├── dashboard_assets/ # primary Ledger interface + graph engine
-│ ├── classic_assets/ # selectable full operator dashboard backup
-│ ├── read_only_api.py # token-protected recall/repository-graph HTTP surface
-│ ├── hosted_client.py # hosted URLs, plan labels, and endpoint validation only
-│ ├── licensing.py # compatibility facade for hosted presentation metadata
-│ ├── cloud_session.py # rotating hosted customer-session client
-│ ├── cloud_features.py # consented managed-feature protocol client
-│ ├── config.py / app.py # env settings / REST server
-│ └── static/ # compatibility dashboard asset paths
-├── eval/ # offline retrieval eval harness + datasets
-├── tests/ # offline-first pytest suite and release/security contracts
-├── scripts/ # dashboard, server, graph, CLI, connect, update, consolidation, sync
-├── docs/ # product, API, hosting, sync, and provider guides
-├── Dockerfile / docker-compose.yml
-└── pyproject.toml
-```
-
-New capability belongs in the v2 path (`engraphis/core/`, `engraphis/backends/`, and
-`MemoryService`) behind the interfaces in `core/interfaces.py`. Algorithm modules in `core/`
-remain backend-agnostic; `engraphis/factory.py` is the outer composition root used by
-`engraphis.create_memory_engine()` and the compatibility `MemoryEngine.create()` entry point, then
-injects the selected collaborators into `core/engine.py`. The flat-namespace v1 server under
-`engraphis/app.py`, `routes/`, `stores/`, and `engines/` remains a
-compatibility/reference surface; `engraphis-dashboard`, the MCP server, and the Python quickstart
-above use v2.
-
----
-
-## License
-
-Apache-2.0. See [LICENSE](https://github.com/Coding-Dev-Tools/engraphis/blob/main/LICENSE) and [NOTICE](https://github.com/Coding-Dev-Tools/engraphis/blob/main/NOTICE). "Engraphis" is a trademark of the
-Engraphis project; the license does not grant trademark rights. Code already distributed
-under Apache-2.0 keeps that grant; later releases cannot retroactively withdraw it. The
-official hosted control plane, its production credentials and records, managed operations,
-support, and future separately delivered commercial modules are outside the public source
-grant. See [`docs/LICENSING.md`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LICENSING.md) for the complete boundary.
+# Engraphis
+
+[](https://pypi.org/project/engraphis/)
+[](https://github.com/Coding-Dev-Tools/engraphis/blob/main/LICENSE)
+[](https://buymeacoffee.com/Jaixii)
+
+[https://engraphis.com/](https://engraphis.com/)
+
+[https://discord.com/invite/Wfr2ejBmY](https://discord.com/invite/Wfr2ejBmY)
+
+**Give your AI agents a memory. See it, search it, and maintain it, all in a beautiful WebUI on your own machine.**
+
+
+
+
+ Knowledge Graph · run engraphis-dashboard to see it live
+
+
+**Grounded, not guessed.** Memory with receipts. Local by default.
+
+---
+
+> **Open-core boundary:** this repository contains the free local engine, dashboard, MCP server,
+> and customer-side clients. Hosted sync, analytics, automation, and team services run on the
+> official hosted service; their server implementations are not distributed here.
+
+> **Support continued Engraphis development with Pro.** [Start a 3-day Pro trial](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_intro&trial=pro#billing)
+> or [subscribe to Pro](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_intro#billing).
+
+---
+
+## Measured token and context savings
+
+### Runtime estimator
+
+The dashboard Overview and Audit/Receipts views also show a receipt-backed estimate from
+real context deliveries. It compares the host history or retrieved source baseline with the
+context Engraphis actually emitted, keeps token counters and release versions separate, and
+labels adaptive history reductions separately from packing savings. Receipts without estimator
+metadata remain historical/unclassified. This measures estimated prompt-context reduction; it
+does not measure provider billing. The `/context-savings` API and
+`engraphis_context_savings` MCP tool aggregate the complete history across all visible workspaces
+by default, or accept an explicit workspace plus optional `from_ts`, `to_ts`, and
+`release_version` filters.
+
+
+
+
+ Less repeated history means more room for the task, tools, and useful evidence.
+
+
+
+See benchmark details and reproduce the results
+
+### Controlled before-and-after example
+
+| Retrieval mode | Mean returned memory content | Recall@5 |
+|---|---:|---:|
+| Whole documents | 740.3 tokens | 1.000 |
+| Engraphis structure-aware chunks | 214.3 tokens | 1.000 |
+
+The chunked mode returns the relevant passage instead of the whole document: **526.0 fewer tokens
+per question**. Under the same model-context budget, that leaves roughly **526 tokens** for task
+instructions or other relevant evidence. This is evidence ID `offline-chunking` in the registered
+artifact below.
+
+### Measurement details and reproducibility
+
+The table below contains every exact token/context aggregate currently published here and keeps
+its counting boundary explicit.
+
+| What is counted | Comparison | Measured reduction | Quality held constant |
+|---|---|---|---|
+| Retrieved top-5 memory content, averaged per question | Whole documents: **740.3** tokens → structure-aware chunks: **214.3** tokens | **526.0 fewer tokens per question** (**71.1% lower**, about **3.5× smaller**) | Recall@5 **1.000** in both modes across 6 documents and 18 questions |
+| Smallest returned memory that contains the reference evidence | Whole documents: **162.2** tokens → chunks: **42.4** tokens | **119.8 fewer tokens to evidence** (**73.9% lower**, about **3.8× smaller**) | The same 18 questions had a returned evidence-holding memory in both modes |
+| Full versus compact recall payload proxy across one 26-question pass within a 260-timed-recall CodeMem run | Full proxy: **23,810** `engraphis.regex.v1` tokens → compact proxy: **10,202** tokens | **13,608 proxy tokens avoided** (**57.15% lower**) | 26 payload samples; 260 timed recalls; Recall@5, hit@5, and answer-token recall all **1.000** |
+| Packed prompt-context usage in the same 26-question CodeMem sample pass | Hard budget: **1,500** tokens; observed mean: **85.38**; observed maximum: **108** | A hard cap prevents a recall from exceeding its configured context budget | This is usage accounting, not a before/after savings comparison |
+
+These values are evidence IDs `offline-chunking` and `offline-performance` in
+[`offline-fixtures-v1.json`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/benchmark-evidence/offline-fixtures-v1.json),
+SHA-256
+`8a74e9f48e25f33d625d4cc5c1b14fec3055891944adccf615c440e84e4b0255`.
+[`BENCHMARKS.md`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/BENCHMARKS.md#public-numeric-evidence-registry)
+records the matching suite digest, exact commands, and per-command config digests. External,
+model-dependent, consolidation, productivity, and latency results remain unpublished until the
+same evidence exists for them.
+
+The compact payload shape avoids duplicating full memory bodies when the packed context and source
+list are enough. The evaluator tokenizes JSON-shaped full and compact payload proxies built from
+recall results; it does **not** serialize the MCP envelope or measure a transport response. The
+fixture therefore does not measure model-provider charges, end-to-end task time, or customer cost
+savings.
+
+The measures are deliberately separate and **must not be added together**: chunking counts the
+content of retrieved memory records before `ContextPacker`, whereas compact recall counts a
+serialized JSON-shape payload proxy. “Tokens to evidence” is the size of the smallest
+retrieved memory record holding the reference evidence; it is not latency or end-to-end answer
+accuracy. Chunking creates more focused stored records, so this is a context-efficiency result,
+not a storage-reduction claim.
+
+Reproduce the registered quality and token/context measurements without a network connection or
+API key:
+
+```bash
+python -m eval.grounded
+python -m eval.chunking_eval --dataset eval/datasets/longdoc.jsonl --k 5
+python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10 --json
+```
+
+These are small deterministic correctness and efficiency fixtures, not official LoCoMo /
+LongMemEval QA scores or a third-party leaderboard result. Compact-response counts use the exact
+`engraphis.regex.v1` counter; the chunking evaluation uses its documented deterministic
+normalized-character estimator. Chunking measures retrieved memory content, while compact recall
+measures a serialized JSON-shape payload proxy, not an MCP transport response. See the registered
+artifact and [`BENCHMARKS.md`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/BENCHMARKS.md)
+for definitions, limitations, and canonical external-evaluation requirements.
+
+
+
+---
+
+## Full Engraphis install: pip install "engraphis[all]"
+
+The complete `engraphis[all]` install is the default way to use Engraphis: it includes the local
+dashboard, Smart MCP server, documents, Cloud Sync client, and supported optional integrations.
+Python 3.10+ is required.
+
+```bash
+pip install "engraphis[all]"
+engraphis-dashboard
+```
+
+The dashboard opens at [http://127.0.0.1:8700](http://127.0.0.1:8700). Local memory needs no
+account or API key.
+
+### Smaller installation options
+
+Use a smaller package only when you intentionally need a limited surface. The NumPy-only core
+continues to support Python 3.9+.
+
+| Goal | Install | Start |
+|---|---|---|
+| Local dashboard and REST API | `pip install "engraphis[server]"` | `engraphis-dashboard` |
+| Coding-agent memory over Smart MCP | `pip install "engraphis[mcp]"` | `codex mcp add engraphis -- engraphis-mcp` |
+| Native SQLite vector acceleration | `pip install "engraphis[vector]"` | Server entrypoints select it automatically |
+| Offline Python library | `pip install engraphis` | `MemoryService.create("engraphis.db")` |
+
+For MCP clients other than Codex, configure a stdio server whose command is `engraphis-mcp`; see
+the [agent connection guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/AGENT_CONNECT.md).
+
+### Updating
+
+Use `engraphis-update` to upgrade the installation using its detected install method. Package
+metadata does not record which extras were selected, so the updater defaults to the safe
+superset `engraphis[all]` rather than silently dropping an optional surface. For a deliberate
+selection, set `ENGRAPHIS_UPDATE_EXTRAS` to a comma-separated list (for example
+`server,mcp`), or set it to `none` for the base package only.
+
+> **Upgrading to 1.4:** `engraphis-mcp` now exposes the nine-tool Smart gateway. Integrations that
+> require the former 35 direct tool names should run `engraphis-mcp-classic`. The SQLite schema
+> in the 1.4.0 release was version 9. Existing v7-to-v8 databases already contain `confidence`
+> and `pinned_at`/`unpinned_at`; v9 adds the `memory_tombstones` repository-scope column/table
+> and performs a one-time entity-canonicalization repair, then migrates automatically on first
+> open. A tombstone with a known `repo_id` is terminal only in that repository; legacy repo-less
+> tombstones remain global. See the [1.4.0 release notes](https://github.com/Coding-Dev-Tools/engraphis/blob/main/CHANGELOG.md#140---2026-08-02).
+
+> **Upgrading to 1.5:** schema 10 bounds legacy retention state and schema 11 backfills explicit
+> approval only for eligible pre-review local memories. Pending and quarantined evidence remains
+> gated. Existing 1.4.x databases migrate automatically when Engraphis 1.5 opens them; see the
+> [1.5 release notes](https://github.com/Coding-Dev-Tools/engraphis/blob/main/CHANGELOG.md#15---2026-08-04).
+
+> **Upgrading to 1.6:** existing 1.5 databases migrate automatically through schema 12, which
+> classifies content-free erasure markers before sync: existing markers become local-only
+> `never_export`, while new secure erasures become `remote_erasure` only for non-secret
+> `workspace`/`repo` records already eligible for sharing. Schema 13 adds per-memory hybrid
+> logical clocks for deterministic descriptive-state sync and durable, content-free proof that a
+> memory crossed a sync boundary. Schema 14 adds the Obsidian collection and import manifests;
+> schema 15 generalizes them to source-neutral local documents, preserves temporal source lineage
+> across re-imports, binds adapters and target scopes, and retains only bounded, content-free
+> per-job format/result metadata. The schema 16 migration persists each import job's optional session target
+> and requires source lineage and job-item attachments to remain in that exact session. See the
+> [1.6 release notes](https://github.com/Coding-Dev-Tools/engraphis/blob/main/CHANGELOG.md#16---2026-08-15).
+
+---
+
+## What Engraphis gives an agent
+
+An agent should not have to reconstruct a project from scattered chat history on every task.
+Engraphis turns local project knowledge into scoped, time-aware memory; retrieves the evidence
+that supports the current question; and returns a bounded, attributable context packet.
+
+The core task is continuity: retrieve the current, supported project decision without dragging the
+whole history into the next prompt. See [measured token and context savings](#measured-token-and-context-savings)
+for the short version of how much less history an agent has to carry.
+
+| Agent need | What Engraphis changes |
+|---|---|
+| Remember a project across sessions | Stores typed memory in a `workspace → repo → session` hierarchy and provides a last-session handoff. |
+| Find support for the current task | Fuses vector, lexical, graph, and code-aware retrieval instead of relying on one search signal; `fast` can skip graph traversal for small or latency-sensitive vaults. |
+| Know what is true now and what changed | Preserves bi-temporal history and supersession chains instead of silently overwriting a fact. |
+| Avoid confident guesses | Returns cited evidence or explicitly abstains when support is too weak. |
+| Avoid dragging the whole project into every prompt | Packs context to a configured hard budget and can return a compact MCP response. |
+| Keep knowledge in the operator's control | Runs local-first and offline-capable, with scopes, audit records, and optional privacy-safe receipts. |
+
+## Dashboard and local UI
+
+The Engraphis dashboard opens `http://127.0.0.1:8700`. Local memory needs no cloud account,
+signup, or API key and stays in a SQLite file on your machine.
+
+**Ledger** is the primary local interface for recall, memories, graph exploration, provenance,
+workspaces, and manual consolidation. **Classic** preserves the former full tool suite; both use
+the same local data. Switch in **Manage → Settings → Interface** (Ledger) or **Settings →
+Appearance & Engine** (Classic).
+
+### Start it on every platform
+
+| Platform | How |
+|----------|-----|
+| **Windows** | Double-click **Engraphis Dashboard** on your Desktop or Start Menu (install: `engraphis-dashboard --install-shortcuts`) |
+| **macOS** | Double-click **Engraphis Dashboard.app** on your Desktop (install: same command) |
+| **Linux** | Desktop entry in Applications → Development (GNOME/KDE/etc.) |
+| **Docker** | `docker compose up`: see `docker-compose.yml` for the one-command deployment |
+| **Any** | `engraphis-dashboard` in a terminal |
+
+In a source checkout, `scripts/launch_dashboard.ps1` is only a Windows convenience wrapper. It
+delegates configuration, startup health, browser opening, and process lifecycle to the same
+`engraphis-dashboard` entrypoint rather than maintaining a second behavior path.
+
+### Accessibility-first inspection, built in
+
+Inspect memories, supersession diffs, recall scores, timelines, links, consolidation, and audit
+records in the dashboard. The offline graph renderer is vendored, and the interface is keyboard-
+navigable with light and dark themes. Graph exploration offers a focused **High quality** view and
+an explicit worker-backed **Every node** view for complete entity projections up to 20,000
+nodes and 200,000 relationships; see the [graph performance profiles](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/GRAPH_PERFORMANCE.md).
+
+---
+
+## How it works
+
+Engraphis gives agents durable, scoped, *explainable* project knowledge. The local engine combines
+Ebbinghaus decay, bi-temporal facts, and hybrid vector/lexical/graph recall; it runs offline with
+SQLite, local embeddings, and `numpy` only.
+
+- **Grounded and governed:** deterministic conflict resolution, cited answers or abstention,
+ explicit correction/promotion/forgetting, and a complete history.
+- **Agent-ready:** MCP tools, hard-budget context packets, handoffs, and code-aware retrieval.
+- **Auditable:** content-free receipt chains, provenance, and temporal/entity/code relationships.
+- **Practical:** local file and code ingest, optional PDF/OCR/transcription, and SQLCipher at rest.
+
+### Optional LLM providers
+
+The memory engine, embeddings, conflict resolution, and recall stay local without an LLM. An
+explicitly configured provider adds structured extraction, cited synthesis, consolidation, and
+retention supervision. Configure it in **Settings → Connect an LLM**. The activity view records
+outcomes, never keys, prompts, or raw provider responses. See the
+[LLM provider guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LLM_PROVIDERS.md) for setup and privacy choices.
+
+> Privacy boundary: text sent to an explicitly selected provider leaves the local process under
+> that provider's terms. Use `ENGRAPHIS_RETENTION_SUPERVISOR=none` (the default) and the offline
+> `chunk` extractor when ingestion must remain entirely local.
+
+Choose and configure an external LLM with the [LLM provider guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LLM_PROVIDERS.md),
+including OpenAI, Anthropic, Google, OpenRouter, Ollama, Cohere Command, Command Code Provider,
+and other compatible endpoints. The guide also covers Codex subscription MCP connections.
+
+---
+
+## Install
+
+```bash
+pip install "engraphis[all]" # self-hosted dashboard, MCP, code graph, documents, transcription, PostgreSQL, and Cloud Sync
+pip install "engraphis[server]" # dashboard + REST API
+pip install "engraphis[mcp]" # MCP server only
+pip install "engraphis[documents]" # PDF + image OCR bindings
+pip install "engraphis[transcription]" # faster-whisper audio/video
+pip install "engraphis[postgres]" # PostgreSQL schema introspection
+pip install "engraphis[code]" # tree-sitter code graph indexing
+pip install "engraphis[vector]" # native sqlite-vec exact-KNN acceleration
+pip install "engraphis[cloud-sync]" # Cloud Sync client crypto/runtime
+pip install "engraphis[encryption]" # SQLCipher encryption-at-rest extra
+pip install engraphis # core library: numpy only, fully offline
+```
+
+The official Docker image includes the local Tesseract executable for image OCR. Outside
+Docker, the `documents` extra installs its Python bindings; install Tesseract through your
+operating system as well if you enable image OCR.
+
+The NumPy-only core library supports Python 3.9+. Current patched releases of the WebUI
+stack, MCP SDK, image parser, and Cloud Sync client require Python 3.10+, so use Python 3.10
+or newer for the `server`, `mcp`, `documents`, `cloud-sync`, or `all` installation paths.
+
+The default `NumpyVectorIndex` performs an exact full scan. There is no universal memory-count
+cutoff because latency depends on vector size, hardware, filters, and the rest of the recall
+pipeline. Measure your machine with `python -m eval.vector_scale --backend numpy`, then run
+`python -m eval.performance` on a representative corpus. If exact scans miss your latency target,
+install `engraphis[vector]`, create the engine with `vector_backend="sqlite-vec"`, and remeasure.
+The stable sqlite-vec `vec0` backend executes exact KNN in native code; it is acceleration, not a
+claim of sublinear ANN scaling. See [BENCHMARKS.md](https://github.com/Coding-Dev-Tools/engraphis/blob/main/BENCHMARKS.md) for the reproducible commands
+and reporting limits.
+
+Dashboard, REST, and MCP entrypoints default to `ENGRAPHIS_VECTOR_BACKEND=auto`: they use
+sqlite-vec when the `vector` extra is installed and compatible, then safely fall back to NumPy.
+Programmatic `MemoryEngine.create()` and `MemoryService.create()` retain the deterministic
+`numpy` default unless a backend is requested explicitly.
+Use `python -m eval.vector_scale --backend sqlite-vec` for an input-identical direct-search
+comparison; setup/index-build time is explicitly excluded from the timed search envelope.
+
+Persistent vectors fail closed unless the embedder can publish a durable, secret-free space
+fingerprint. Sentence Transformers use the loaded Hub commit or a manifest of local artifacts;
+when a remote model's immutable identity cannot be resolved, persistent vector recall remains
+gated instead of mixing spaces. For programmatic OpenAI-compatible embeddings, construct
+`ApiEmbedder` with an operator/provider `space_version`; without it the adapter remains usable for
+ephemeral embedding only. Its `base_url` may be a provider root or a `/v1` root and is normalized
+to exactly one `/v1/embeddings` endpoint.
+
+`sqlcipher3-binary` publishes CPython manylinux x86-64 wheels. On that target,
+`engraphis[encryption]` installs the driver. The cross-platform `all` extra deliberately
+omits it so `all` remains resolvable on macOS, Windows, Linux ARM, and musl; on those
+targets, provision a compatible SQLCipher driver separately before enabling a database
+key. The programmatic core remains plaintext unless a database key is configured. For a
+fresh database, `engraphis-init` enables SQLCipher automatically when a compatible driver is
+available, creates a private key sidecar, and can be overridden with `--no-encryption`.
+
+> **Linux / macOS:** if `pip install` fails with `error: externally-managed-environment`,
+> your system Python is marked read-only (PEP 668). Install into a virtual environment
+> instead. Run `python3 -m venv venv && source venv/bin/activate && pip install "engraphis[server]"`
+> Alternatively, use Docker (`docker compose up`). `pipx install "engraphis[server]"` also works.
+
+> First run downloads `all-MiniLM-L6-v2` (~80 MB). Without it, the engine falls back
+> to deterministic feature hashing so it always runs offline. That fallback captures lexical
+> overlap, not meaning: recall and grounded MCP responses set `degraded_mode=true` and
+> `semantic_support=false`, and disable vector retrieval plus semantic-cosine evidence. Install
+> a declared embedding model for semantic retrieval.
+
+> To require a model that is already local, set `ENGRAPHIS_EMBED_MODEL=local:/absolute/model/path`
+> or `local:`. This path never downloads a model. If it is unavailable, Engraphis
+> explicitly enters lexical degraded mode instead of presenting hash-vector scores as semantic.
+
+---
+
+## Quickstart: dashboard
+
+```bash
+pip install "engraphis[server]"
+engraphis-dashboard # → http://127.0.0.1:8700
+engraphis-dashboard --install-shortcuts # → Desktop + Start Menu icons
+```
+
+> **Offline first run:** the first launch downloads the `all-MiniLM-L6-v2` embedding model
+> (~80 MB), then runs fully offline. To stay offline-only, set
+> `ENGRAPHIS_EMBED_MODEL=local:/absolute/model/path` (never downloads; unknown local models
+> enter lexical degraded mode instead of faking semantic scores). Extraction defaults to
+> `ENGRAPHIS_EXTRACTOR=none` (verbatim writes), the vector backend defaults to `auto` (native
+> acceleration when installed, otherwise NumPy), and recall without a usable semantic space
+> reports `degraded_mode=true` with lexical/graph recall. Run `engraphis-init --check` to
+> verify the install, extras, and database writability.
+
+### Docker
+
+```bash
+docker compose up # → http://127.0.0.1:8700
+```
+
+For Docker Compose persistence and loopback-port configuration, see the
+[Docker deployment guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/DOCKER.md).
+`engraphis-server` and `engraphis server` are headless compatibility aliases
+for this same v2 service, so every public surface has the same scoped recall and retention model.
+
+For optional LAN exposure, token configuration, and HTTP MCP setup, see the
+[Docker deployment guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/DOCKER.md).
+
+Set `ENGRAPHIS_API_TOKEN` to require API authentication and `ENGRAPHIS_DB_KEY` to encrypt
+the local database at rest. Hosted-plan credentials configure customer clients; they do not
+install premium server implementations into this image. See `docker-compose.yml` for options.
+
+---
+
+## Quickstart: MCP server (for coding agents)
+
+```bash
+pip install "engraphis[mcp]"
+engraphis-init # writes ~/.engraphis/config.env + prints config snippets
+claude mcp add engraphis -- engraphis-mcp
+codex mcp add engraphis -- engraphis-mcp # Codex subscription
+
+```
+
+> **Offline first run:** the first tool call lazily loads the `all-MiniLM-L6-v2` embedding
+> model (~80 MB, same download as the dashboard), then memory runs fully offline with no API
+> key. To stay offline-only, set `ENGRAPHIS_EMBED_MODEL=local:/absolute/model/path` (never
+> downloads); extraction defaults to `ENGRAPHIS_EXTRACTOR=none`, the vector backend `auto`
+> falls back to NumPy without the `vector` extra, and recall without a usable semantic space
+> reports `degraded_mode=true` with lexical/graph recall. Run `engraphis-init --check` to
+> verify the install and database path before registering the server.
+
+For Codex subscription setup and verification, see the [agent connection guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/AGENT_CONNECT.md)
+and the [LLM provider guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LLM_PROVIDERS.md).
+
+`engraphis-mcp` is zero-configuration Smart MCP: agents begin with nine compact tools for sessions,
+prompt-ready recall, durable memory, governed record read/update, conflict review, action discovery,
+and safe execution. For code graphs,
+governance, audit, or other advanced work, the agent calls `engraphis_discover_actions` and then
+the indicated read or action executor; no profile selection is required. The gateway validates
+the discovered capability again before it runs it, and clients remain responsible for their
+normal destructive-action approval boundary.
+
+Existing clients that pin the historical 35 named tools can use
+`engraphis-mcp-classic` (or `engraphis-mcp-http --classic`). The complete classic inventory,
+including `engraphis_check_update`, is in the [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md).
+
+### Pi extension
+
+For installation, configuration, lifecycle commands, and the local trust boundary, see the
+[Pi extension guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/integrations/pi/README.md).
+
+### Command Code SessionStart hook
+
+`integrations/commandcode/` ships a SessionStart hook that warms up a new
+session with bounded, recalled context from the local Engraphis gateway. Fails
+open on timeout and is installed via `python scripts/install_cc_hook.py`.
+
+### prime-agent fleet
+
+`integrations/prime_agent/` ships a first-party Python package for
+[PrimeIntellect prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
+that exposes the same nine Smart MCP tools, with a `PrimeAgentFleet` of eight
+named sub-agents (`researcher`, `planner`, `coder`, `reviewer`, `tester`,
+`documenter`, `monitor`, `integrator`) sharing one `engraphis-mcp` stdio
+subprocess. Install via `pip install ./integrations/prime_agent` and register
+with `python scripts/install_prime_agent.py`. See the
+[prime-agent integration guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/integrations/prime_agent/README.md).
+
+**What the integration is.** A `PrimeAgentFleet` is a thin Python layer
+around the same `engraphis-mcp` Smart gateway every other host uses. At
+runtime the fleet holds one shared `EngraphisMcpClient`, which owns one
+`engraphis-mcp` subprocess over JSON-RPC stdio. Each of the eight named
+sub-agents gets its own Engraphis session (started lazily on first tool use)
+and its own default `repo` scope, so per-role memory is isolated while the
+local gateway stays single-process. The eight sub-agent names
+(`researcher`, `planner`, `coder`, `reviewer`, `tester`, `documenter`,
+`monitor`, `integrator`) are the fixed default; pass `agent_names=[...]` to
+`PrimeAgentFleet(...)` for a custom set. Concurrent tool calls serialize at
+the JSON-RPC frame layer through an `asyncio.Lock`, so framework-level
+parallelism (eight sub-agents reasoning at once) is preserved while the
+underlying MCP transport remains one ordered stream. The only integration
+surface is `EngraphisPrimeAgent.register()` in
+`integrations/prime_agent/src/engraphis_prime_agent/agent.py` -- that is the
+single adapter point to override if prime-agent's tool-registration API
+differs from the assumed `target.register_tool(name, fn, schema=...)`
+contract.
+
+The design -- eight named sub-agents, one shared stdio subprocess,
+per-agent session bootstrap, and `ENGRAPHIS_*`-only environment forwarding
+to the gateway -- is recorded in `~/.commandcode/plans/prime-agent-integration.md`
+on the host where the integration was developed. When that host plan is not
+available (other contributor machines, CI), the same design is summarized in
+the PR description that introduced the integration and in the
+[prime-agent integration guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/integrations/prime_agent/README.md)
+("Architecture" and "Concurrency model" sections).
+
+## Quickstart: repository graph
+
+```bash
+pip install "engraphis[code]"
+engraphis-graph index -w acme -r api --root .
+engraphis-graph search -w acme -r api "UserService"
+# `query`/`explain` blend code search with your stored memories: query matches symbol
+# and file NAMES (a full question sentence won't match anything), and explain's answer
+# is drawn from memories recorded against the repo; both are empty on a fresh index.
+engraphis-graph query -w acme -r api "UserService"
+engraphis-graph explain -w acme -r api "why does deploy depend on approval?"
+engraphis-graph path -w acme -r api UserService DatabasePool
+engraphis-graph impact -w acme -r api --root . --git-range origin/main...HEAD
+engraphis-graph prs -w acme -r api --base main --head HEAD
+engraphis-graph export -w acme -r api -o engraphis-graph-out
+engraphis-graph install-merge-driver --root .
+```
+
+The export contains `graph.json`, a self-contained `graph.html`, and `GRAPH_REPORT.md`.
+Indexing supports Python, JavaScript, TypeScript, Go, Rust, Java, C#, C, C++, SQL, and
+Terraform. Tree-sitter is used when available; the dependency-free regex backend remains a
+functional fallback. Definitions, methods, calls, imports, ownership, variables,
+inheritance/implementation, and docstrings/comments are indexed. Indexing is incremental by
+content hash, honors `.engraphisignore`, and does not follow file symlinks outside the repository
+root. Call edges are name-based and best-effort rather than type-resolved. The optional Git merge
+driver validates bounded graph JSON and deterministically unions nodes and edges instead of
+choosing one export side.
+
+For a read-only recall and graph API that can be shared without exposing write operations:
+
+```bash
+pip install "engraphis[server]"
+engraphis-graph-server # API at http://127.0.0.1:8720; schema at /openapi.json
+```
+
+A non-loopback bind fails closed unless `ENGRAPHIS_GRAPH_TOKEN` (or
+`ENGRAPHIS_API_TOKEN`) is set. See [the v3 architecture/design document](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/ARCHITECTURE_V3.md).
+
+---
+
+## Quickstart: Python library
+
+```python
+from engraphis.service import MemoryService
+
+mem = MemoryService.create("engraphis.db")
+mem.remember("Auth migrated from JWT to PASETO.", workspace="acme", repo="api")
+hit = mem.recall("why did we change auth?", workspace="acme", repo="api")
+print(hit["context"])
+```
+
+The same `MemoryService` backs the dashboard and the MCP server. The package root also
+intentionally exposes the low-level engine facade (`MemoryEngine`, `create_memory_engine`)
+for advanced composition, while `MemoryService` remains the high-level service API.
+
+New writes support `session`, `repo`, and `workspace` visibility. `scope="user"` is reserved and
+rejected until records carry an immutable owner identity; it must not be treated as private
+per-person memory. Historical user-scope rows remain workspace-bound for compatibility.
+
+After an upgrade, `stats()` reports prompt-eligibility counts and active embedding-space
+coverage. Zero-result recall identifies a review-gated scope instead of silently looking empty,
+and `engraphis-cli review list|approve` provides a dry-run-first local bulk workflow. Embedding
+model changes trigger a guarded rebuild; vector recall stays disabled until every stored vector
+matches the new fingerprint. See [recall recovery](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/RECALL_RECOVERY.md).
+
+Agent hosts can avoid retrieval when their existing history already fits:
+
+```python
+decision = mem.adaptive_context(
+ "what should the agent do next?",
+ current_history,
+ workspace="acme",
+ repo="api",
+ max_context_tokens=8_192,
+ retrieval_token_budget=1_024,
+)
+prompt_context = decision["context"]
+```
+
+The decision is `history_bypass` when the history fits, `retrieval` when compact evidence is
+strong, and `history_fallback` when weak retrieval should widen back to recent raw history.
+
+For an agent prompt, prefer `engraphis_recall_context`: it returns one hard-budget packed
+`context` plus compact `sources`, deterministic `usage` accounting (`budget_tokens`, `context_tokens`,
+`source_tokens`, `saved_tokens`, `savings_ratio`, `packed_count`, `omitted_count`, and
+`token_counter`), and optional diagnostics. Accounting is exact for the named counter; inject the
+reader's tokenizer when reader-model token parity is required. `engraphis_recall` remains the compatible full-recall
+surface; use `response_mode="compact"` when the packed context is enough and full memory bodies
+would duplicate it. For advanced query-planning configuration, see the
+[architecture guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/ARCHITECTURE_V3.md#query-planning).
+
+For bi-temporal reads, `valid_at` selects what was true at a Unix timestamp and `known_at` selects
+what Engraphis had learned then. `as_of` remains a compatibility alias for `valid_at`; supplying
+both is allowed only when they match.
+
+For a mutable claim, pass a stable `subject_key` and optional `claim_kind`, such as
+`subject_key="api.rate_limit", claim_kind="configured_value"`. Offline conflict resolution
+deterministically adds, reinforces, relates, or supersedes records while preserving temporal
+history; it does not need an LLM. Matching claim identities let it supersede substantially
+reworded mutable facts. Without them, the dependency-free lexical embedder cannot reliably infer
+that a paraphrase is a contradiction, so keep both records or use an explicit `correct` operation.
+
+---
+
+## Govern memories without losing history
+
+Engraphis separates automatic write resolution from explicit human governance:
+
+| Operation | Use it when | What happens to history |
+|---|---|---|
+| `remember` | Adding or restating one fact | Adds, reinforces, safely supersedes, or relates an uncertain neighbor |
+| `correct` | Replacing one known-wrong memory | Closes the old validity window and links the replacement |
+| `promote` | A narrow learning now applies more broadly | Writes a wider-scope successor and closes/links the source instead of editing scope in place |
+| `merge` | Combining two or more overlapping memories | Retires every source and creates one memory that supersedes all of them |
+| `retire` | Removing a memory from live recall | Bi-temporally closes it; the audit/history record remains |
+| `consolidate` | Distilling recurring episodic memories automatically | Creates linked semantic digests; source episodes remain live |
+
+Manual N→1 merge is available through `MemoryService.merge()` and `POST /api/merge`:
+
+```python
+a = mem.remember("Deploys happen Friday at 3pm.", workspace="acme")
+b = mem.remember("We deploy Fridays around 15:00.", workspace="acme")
+
+merged = mem.merge(
+ [a["id"], b["id"]],
+ "Deploys ship every Friday at approximately 15:00.",
+ workspace="acme",
+ reason="deduplicate the deployment schedule",
+)
+print(merged["compaction"])
+```
+
+`retire` is intentionally not deletion: it preserves temporal history, FTS, and vector
+evidence for historical reads. If a credential was captured, new writes are blocked before
+storage; for a legacy leak use the explicitly destructive `MemoryService.secure_erase()` or
+`POST /api/secure-erase`/`engraphis_secure_erase`. That flow removes the one memory and local
+FTS/vector-index and derived graph/link rows, runs SQLite secure-delete, WAL checkpoint, and
+VACUUM, and scans recognised local SQLite recovery backups. It cannot erase exports, filesystem
+snapshots, remote peers, unknown backups, or information a running/compromised agent already
+read; rotate the credential. See [secure-erasure limits](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SECURE_ERASURE.md). `forget`
+remains a deprecated compatibility alias for `retire`.
+
+All sources must belong to the named workspace. The result inherits the strictest source
+sensitivity, remains untrusted if any source was untrusted, and stays pinned if any source was
+pinned. The full multi-predecessor chain remains visible through inspection, Why, and Timeline.
+
+---
+
+## Free forever vs. hosted plans
+
+The core engine, local dashboard, MCP server, and manual consolidation are Apache-2.0 and free.
+**Pro and Team are services** that provide optional access to the official hosted service; its
+control-plane, billing, relay, compute, and Team identity modules live in a private repository.
+They do not limit the local core. See
+[hosted plans](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/HOSTED_PLANS.md), [licensing](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LICENSING.md), and
+[Cloud Sync](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SYNC.md) for service boundaries, lifecycle, and pricing.
+
+[Subscribe to Pro](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_pricing#billing)
+to support the project and add hosted services.
+
+[Compare hosted plans](https://api.engraphis.com/account?plan=pro&interval=monthly&utm_source=engraphis&utm_medium=docs&utm_campaign=pro_conversion&utm_content=readme_intro#billing)
+when you are ready to evaluate the service boundary and billing options.
+
+| | Free (available now) | Pro: $10/mo or $100/yr | Team: $20/seat/mo or $200/seat/yr |
+|---|---|---|---|
+| Dashboard WebUI (with built-in inspector) | ✓ | ✓ | ✓ |
+| Memory engine + Smart MCP (Classic 35-tool compatibility) | ✓ | ✓ | ✓ |
+| Version-chain diffs, offline knowledge graph | ✓ | ✓ | ✓ |
+| Manual local consolidation (dry-run by default) | ✓ | ✓ | ✓ |
+| Local workspace export (portable v2 JSON: memories, source manifests, graph/code evidence, sessions, audit, and receipts) | ✓ | ✓ | ✓ |
+| Hosted Cloud Sync | | ✓ | ✓ |
+| Hosted Analytics | | ✓ | ✓ |
+| Hosted Auto Consolidation + retention policy | | ✓ | ✓ |
+| Hosted Auto Dreaming + managed proposals | | ✓ | ✓ |
+| Priority support | | ✓ | ✓ |
+| Hosted multi-user dashboard: invitations, logins, roles, seat management | | | ✓ |
+| Hosted Team audit log + CSV export | | | ✓ |
+| 72-hour pending invitations (resend/revoke) | | | ✓ |
+| Scoped, expiring per-user agent and sync tokens | | | ✓ |
+
+---
+
+## MCP tools
+
+Engraphis exposes a zero-configuration Smart MCP gateway plus a 35-tool Classic compatibility
+server across memory, recall, code graphs, governance, sessions, and privacy-safe audit receipts.
+The focused [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md) is the source for
+the full inventory and parameters.
+
+---
+
+## Graphs and privacy-safe receipts
+
+Memory, entity, and code relationships live in one local graph. Engraphis also provides
+content-free operation receipts for inspectable audit evidence. See the
+[architecture](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/ARCHITECTURE_V3.md), [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md), and
+[security policy](https://github.com/Coding-Dev-Tools/engraphis/blob/main/SECURITY.md) for the data model, tools, and guarantees.
+
+---
+
+## Cloud sync
+
+Cloud Sync is an optional hosted Pro/Team service. The public package includes the customer client
+and deterministic merge implementation; hosted relay and account operations are separate. See
+[Cloud Sync](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SYNC.md) for setup, encryption, merge behavior, and the local folder exchange.
+
+The public package ships the same sync client as a console script and CLI verb:
+`engraphis-sync` (installed entry point), `engraphis sync ...`, and
+`python -m scripts.sync --status` for local-only state without network activity. See
+[Cloud Sync](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/SYNC.md) for
+flags, encryption, merge behavior, and the local folder exchange.
+
+---
+
+## Security and trust boundaries
+
+Engraphis is local-first and binds to loopback by default. Read the
+[security policy](https://github.com/Coding-Dev-Tools/engraphis/blob/main/SECURITY.md) before remote deployment or integrating external resources; it
+covers supported versions, data protections, threat model, and vulnerability reporting.
+
+---
+
+## Encryption at rest
+
+Set `ENGRAPHIS_DB_KEY` (or `ENGRAPHIS_DB_KEY_FILE`) and install the extra:
+
+```bash
+pip install "engraphis[encryption]"
+```
+
+The entire main memory database file is transparently encrypted with AES-256 via SQLCipher;
+full-text search, the graph, and every query keep working unchanged. Customer authentication
+and managed-service state use their respective deployment protections. When a key is set for the
+main database, Engraphis **fails closed with an error** rather than silently falling back to
+plaintext. Generate a strong key:
+
+```bash
+python -c "import secrets; print(secrets.token_hex(32))"
+```
+
+When using `ENGRAPHIS_DB_KEY_FILE`, provision a regular secret file readable only by the
+service identity. Engraphis rejects links, reparse points, hard links, malformed text, and
+oversized key files rather than following an unexpected filesystem object.
+
+> An existing plaintext database cannot be opened with a key: migrate it (dump → import
+> into a fresh keyed DB). See `.env.example` for all encryption options.
+
+---
+
+## Import files and folders
+
+The dependency-free universal core scans Markdown, plain text, RST, HTML, JSON/JSONL, CSV/TSV,
+configuration/XML text, source code, RTF, DOCX/ODT, XLSX/ODS, PPTX/ODP, and EPUB into the normal
+v2 memory path. Installed local resource adapters add PDF text, image OCR, and explicitly
+local-model audio/video transcription.
+Start with a zero-write
+preview, then confirm the same source collection explicitly:
+
+```bash
+engraphis import documents /path/to/collection --workspace acme --dry-run
+engraphis import documents /path/to/collection --workspace acme --repo product --yes
+```
+
+The CLI never downloads an embedding model during import. Use a model that is already cached,
+set `ENGRAPHIS_EMBED_MODEL=local:/absolute/model/path`, or explicitly set
+`ENGRAPHIS_EMBED_MODEL` to an empty value to use dependency-free deterministic hashing in
+lexical degraded mode.
+
+The dashboard’s **Import local documents** flow offers the same preview, target scope, source
+label, conflict policy, cancellation, and resumable progress. Re-imports are idempotent,
+preserve temporal history, and report source removals without hard-deleting memories. Obsidian
+remains the rich Markdown adapter for frontmatter, aliases, wikilinks, and attachment references:
+
+```bash
+engraphis import obsidian /path/to/vault --workspace acme --dry-run
+```
+
+See the [document import guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/DOCUMENT_IMPORT.md)
+for supported formats, source safety, resume and conflict behavior, optional adapters, and
+limitations; see the [Obsidian adapter guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/OBSIDIAN_IMPORT.md)
+for Markdown-specific behavior.
+
+---
+
+## Consolidation and automation
+
+Manual consolidation is free, local, and dry-run by default; use the dashboard, SDK, CLI, or
+MCP. Hosted Pro and Team automation is optional managed compute that produces reviewable
+proposals rather than silently changing local data. See [hosted plans](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/HOSTED_PLANS.md),
+[licensing](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LICENSING.md), and the [MCP tool reference](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/MCP_TOOLS.md) for scope and use.
+
+---
+
+## Configuration
+
+Values come from the process environment. Engraphis also loads the owner-private
+`~/.engraphis/config.env`; `ENGRAPHIS_ENV_FILE` can select another absolute owner-private regular
+file. It never searches the working directory for `.env`, and explicit process variables win.
+
+| Env Var | Default | Description |
+|---------|---------|-------------|
+| `ENGRAPHIS_ENV_FILE` | `~/.engraphis/config.env` | Optional trusted config leaf selected before trusted values load. Its bounded dependency-free parser performs no interpolation. An explicit value must be an absolute path to an owner-private regular file; arbitrary working-directory `.env` files are ignored. |
+| `ENGRAPHIS_DB_PATH` | Source: `/engraphis.db`; installed: platform user-data directory | SQLite database file. Installed defaults are `%LOCALAPPDATA%\engraphis\engraphis.db` (Windows), `~/Library/Application Support/engraphis/engraphis.db` (macOS), and `$XDG_DATA_HOME/engraphis/engraphis.db` or `~/.local/share/engraphis/engraphis.db` (Linux). The environment variable overrides every default; a relative value is resolved from the trusted `~/.engraphis/config.env` directory so launch CWD cannot select a different workspace database. |
+| `ENGRAPHIS_HOST` | `127.0.0.1` | Server bind address |
+| `ENGRAPHIS_PORT` | `8700` | Dashboard port. A platform-injected `$PORT` (Railway/Fly/Heroku) takes precedence over this value for the dashboard bind; Compose pins both to `ENGRAPHIS_COMPOSE_PORT` so the mapping stays in sync |
+| `ENGRAPHIS_SERVICE_MODE` | `customer` | The public package supports only `customer`; hosted vendor, relay, compute, and worker roles are not distributed here |
+| `ENGRAPHIS_API_TOKEN` | Not set | Optional bearer credential for this single-user local customer node; never reuse a hosted credential |
+| `ENGRAPHIS_CORS_ORIGINS` | loopback on `ENGRAPHIS_PORT` | Comma-separated REST CORS allow-list; defaults to `127.0.0.1` and `localhost` on the configured port |
+| `ENGRAPHIS_INDEX_ROOTS` | Working, home, and temporary directories | Optional path-separator-delimited absolute-path allow-list that replaces the default roots accepted by local code indexing |
+| `ENGRAPHIS_HTTP_INDEX_ROOT` | First `ENGRAPHIS_INDEX_ROOTS` entry, or current directory | Single root for dashboard and REST `POST /api/code/index`; submitted paths resolve beneath it. An explicit root (or fallback entry) must be absolute; an explicit HTTP root is included in the engine-approved set. MCP and CLI indexing continue to use `ENGRAPHIS_INDEX_ROOTS`. |
+| `ENGRAPHIS_DB_KEY` | Not set | Encrypt the database at rest (SQLCipher). Or use `ENGRAPHIS_DB_KEY_FILE` |
+| `ENGRAPHIS_EMBED_MODEL` | `sentence-transformers/all-MiniLM-L6-v2` | sentence-transformers model |
+| `ENGRAPHIS_EMBED_REVISION` | Not set | Optional immutable lowercase 40-hex Hugging Face commit for the embedding model. Loaded Hub commits or local artifact manifests identify persistent vector spaces; unresolved mutable identities keep vector recall fail-closed. |
+| `ENGRAPHIS_RERANK_MODEL` | Not set | Optional sentence-transformers cross-encoder reranker |
+| `ENGRAPHIS_RERANK_REVISION` | Not set | Optional immutable lowercase 40-hex Hugging Face commit for the reranker |
+| `ENGRAPHIS_REQUIRE_IMMUTABLE_MODELS` | `false` | When enabled, require a 40-hex commit before loading remote embedding models, rerankers, or chunk tokenizers; `local:` selectors and filesystem paths remain permitted |
+| `ENGRAPHIS_REQUIRE_EXACT_BACKENDS` | `false` | When enabled, dashboard and standalone MCP startup fails if a configured optional backend is unavailable instead of silently falling back |
+| `ENGRAPHIS_EXTRACTOR` | `none` | `none` = verbatim; `chunk` = offline structure-aware chunks; `llm` = free-form LLM facts; `llm_structured` = schema-validated facts + graph metadata |
+| `ENGRAPHIS_CHUNK_TOKENIZER_MODEL` | Not set | Optional Hugging Face tokenizer used to enforce chunk budgets with the downstream reader's real tokenization; requires the optional `transformers` package |
+| `ENGRAPHIS_CHUNK_TOKENIZER_REVISION` | Not set | Optional immutable tokenizer/model revision recorded in the chunk-counter identity; pin this for reproducible benchmark artifacts |
+| `ENGRAPHIS_GRAPH_EXTRACTOR` | `regex` | `regex` = offline heuristic NER; `none` = disable heuristic text extraction (validated `llm_structured` metadata still feeds the graph) |
+| `ENGRAPHIS_RETENTION_SUPERVISOR` | `none` | `none` = deterministic only; `llm` = sends a bounded excerpt to the configured provider for advisory ephemeral/normal/critical classification |
+| `ENGRAPHIS_ALLOW_AUTOMATIC_CRITICAL_RETENTION` | `false` | Opt in only when an LLM supervisor may automatically assign the long-lived `critical` class; explicit user-selected critical retention is unaffected |
+| `ENGRAPHIS_WHISPER_MODEL` | Not set | Enables local faster-whisper audio/video transcription |
+| `ENGRAPHIS_POSTGRES_DSN` | Not set | CLI-only PostgreSQL source; used for the connection and never stored |
+| `ENGRAPHIS_POSTGRES_CONNECT_TIMEOUT` | `10` | PostgreSQL introspection connection timeout in seconds (bounded to 1--120) |
+| `ENGRAPHIS_POSTGRES_STATEMENT_TIMEOUT_MS` | `30000` | Per-introspection PostgreSQL statement timeout in milliseconds (bounded to 1--300000) |
+| `ENGRAPHIS_GRAPH_TOKEN` | Not set | Bearer token for `engraphis-graph-server`; required off-loopback |
+| `ENGRAPHIS_GRAPH_HOST` / `ENGRAPHIS_GRAPH_PORT` | `127.0.0.1` / `8720` | Read-only graph/recall server bind address |
+| `ENGRAPHIS_LLM_PROVIDER` | `openai` | `openai \| anthropic \| google \| openrouter \| custom` |
+| `ENGRAPHIS_LLM_MODEL` | `gpt-4o-mini` | Model name (provider-specific) |
+| `ENGRAPHIS_LLM_API_KEY` | Not set | API key for chat/synthesis, `llm` / `llm_structured` extraction, and structured consolidation |
+| `ENGRAPHIS_LLM_BASE_URL` | Not set | Base URL for openrouter / custom OpenAI-compatible endpoints |
+| `ENGRAPHIS_LLM_AUTO_EXTRACT` | `0` | Opt in to switching the running engine to `llm_structured` after a successful live connection test; the dashboard's extraction Off button persists `0`, and its On button restores `1` |
+| `ENGRAPHIS_FORWARDED_ALLOW_IPS` | *(none)* | Proxies trusted for forwarded client/TLS headers (`*` only when the service is reachable exclusively through that proxy) |
+| `ENGRAPHIS_LOCAL_TRUSTED_PEERS` | *(none)* | Exact peers/CIDRs treated as local without forwarding headers; use only for trusted Docker/LAN peers, never public deployments |
+| `ENGRAPHIS_UPDATE_CACHE` | `86400` | Update-check cache TTL in seconds, bounded to `1..31622400`; this is never a cache-file path |
+| `ENGRAPHIS_UPDATE_CHECK` | Off | Opt-in release reminder surfaced in the dashboard, server startup log, and MCP. Update checks run only when this is set to an affirmative value; `0` keeps them off. |
+| `ENGRAPHIS_UPDATE_URL` | Not set | Overrides the release-check source URL; the outbound client accepts HTTPS and rejects private/reserved destinations. |
+| `ENGRAPHIS_CLOUD_CONTROL_URL` | hosted default | Official entitlement, organization, and credential control API. A saved rotating credential stays bound to the control endpoint recorded for its family; reconnect to change it. |
+| `ENGRAPHIS_CLOUD_COMPUTE_URL` | hosted default | Official Analytics and managed-automation API. A saved rotating credential stays bound to its recorded compute endpoint; reconnect to change it. |
+| `ENGRAPHIS_CLOUD_ORGANIZATION_ID` | Not set | Hosted organization bound to this customer session |
+| `ENGRAPHIS_CLOUD_REFRESH_CREDENTIAL` | Not set | Bootstrap-only rotating hosted credential; after first use the owner-only cloud session replacement takes precedence |
+| `ENGRAPHIS_CLOUD_TOKEN_SUBJECT` | `member` | Subject fixed during hosted bootstrap (`device` or `member`); set explicitly with an environment-only refresh credential |
+| `ENGRAPHIS_CLOUD_ACCESS_TOKEN` | Not set | Optional short-lived access token for ephemeral jobs |
+| `ENGRAPHIS_MANAGED_COMPUTE_CONSENT` | *(auto)* | Operator override only; default follows whether a cloud session is configured (connected = allowed, local-only = never). `0` opts a connected installation out; `1` permits local snapshot preparation but does not create a cloud credential or authorize an upload |
+
+The optional cross-encoder reranker is model- and hardware-dependent. Treat its quality and
+latency as deployment-specific until a versioned model identity, exact configuration, and
+reproducible evaluation artifact are available for the comparison being reported.
+
+See `.env.example` for the full variable inventory. Supply those values through the process
+environment or the trusted config file above; copying it to an arbitrary `./.env` does not make
+Engraphis load it.
+
+> **Ablation fixture:** `python -m eval.ablation` is an offline deterministic check that prints
+> `recall@5` comparisons for vector-only and hybrid retrieval, multi-hop graph arms, and
+> retrieval policies, plus ordinary-recall age and semantic-confidence checks. It does not
+> produce MRR, hit@5, or ms/query results. Use `python -m eval.reinforcement` for retention
+> trajectories, and register evidence before quoting any benchmark results.
+
+---
+
+## Project structure
+
+```
+engraphis/
+├── engraphis/
+│ ├── core/ # v2 engine: interfaces, store, recall, scoring, schema, sync
+│ ├── backends/ # pluggable embedder / vector index / reranker / codegraph / sync transports / encryption
+│ ├── factory.py # outer v2 composition root; selects and injects concrete backends
+│ ├── service.py # validated MemoryService facade
+│ ├── mcp_server.py # Smart MCP gateway + 35-tool Classic compatibility server
+│ ├── dashboard_app.py # dashboard WebUI (FastAPI)
+│ ├── dashboard_assets/ # primary Ledger interface + graph engine
+│ ├── classic_assets/ # selectable full operator dashboard backup
+│ ├── read_only_api.py # token-protected recall/repository-graph HTTP surface
+│ ├── hosted_client.py # hosted URLs, plan labels, and endpoint validation only
+│ ├── licensing.py # compatibility facade for hosted presentation metadata
+│ ├── cloud_session.py # rotating hosted customer-session client
+│ ├── cloud_features.py # consented managed-feature protocol client
+│ ├── config.py / app.py # env settings / REST server
+│ └── static/ # compatibility dashboard asset paths
+├── eval/ # offline retrieval eval harness + datasets
+├── tests/ # offline-first pytest suite and release/security contracts
+├── scripts/ # dashboard, server, graph, CLI, connect, update, consolidation, sync
+├── docs/ # product, API, hosting, sync, and provider guides
+├── Dockerfile / docker-compose.yml
+└── pyproject.toml
+```
+
+New capability belongs in the v2 path (`engraphis/core/`, `engraphis/backends/`, and
+`MemoryService`) behind the interfaces in `core/interfaces.py`. Algorithm modules in `core/`
+remain backend-agnostic; `engraphis/factory.py` is the outer composition root used by
+`engraphis.create_memory_engine()` and the compatibility `MemoryEngine.create()` entry point, then
+injects the selected collaborators into `core/engine.py`. The flat-namespace v1 server under
+`engraphis/app.py`, `routes/`, `stores/`, and `engines/` remains a
+compatibility/reference surface; `engraphis-dashboard`, the MCP server, and the Python quickstart
+above use v2.
+
+---
+
+## License
+
+Apache-2.0. See [LICENSE](https://github.com/Coding-Dev-Tools/engraphis/blob/main/LICENSE) and [NOTICE](https://github.com/Coding-Dev-Tools/engraphis/blob/main/NOTICE). "Engraphis" is a trademark of the
+Engraphis project; the license does not grant trademark rights. Code already distributed
+under Apache-2.0 keeps that grant; later releases cannot retroactively withdraw it. The
+official hosted control plane, its production credentials and records, managed operations,
+support, and future separately delivered commercial modules are outside the public source
+grant. See [`docs/LICENSING.md`](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/LICENSING.md) for the complete boundary.
diff --git a/docs/DOCKER.md b/docs/DOCKER.md
index 1d62260a..cd664eb5 100644
--- a/docs/DOCKER.md
+++ b/docs/DOCKER.md
@@ -25,6 +25,11 @@ ENGRAPHIS_COMPOSE_PORT=8787
Then open `http://127.0.0.1:8787`. License issuance, trials, leases, and revocations remain on the private control plane.
+> Port precedence: the dashboard binds `$PORT` when the platform injects one, falling back
+> to `ENGRAPHIS_PORT` (then `8700`). Compose sets both from `ENGRAPHIS_COMPOSE_PORT` so the
+> published host port and the in-container bind stay in sync; a stray desktop `ENGRAPHIS_PORT`
+> cannot desynchronise them.
+
## LAN exposure and HTTP MCP
Compose publishes only on loopback by default. To expose it on a LAN, set a strong API token and
diff --git a/docs/DOCUMENT_IMPORT.md b/docs/DOCUMENT_IMPORT.md
index 6804eddc..4bff3949 100644
--- a/docs/DOCUMENT_IMPORT.md
+++ b/docs/DOCUMENT_IMPORT.md
@@ -55,8 +55,10 @@ name. This label is part of the local source identity, so unrelated collections
share a re-import lineage. Select a saved source when resuming or re-importing that collection.
The browser processes selected bytes locally and does not retain a dashboard upload copy. The
-trusted dashboard flow requires its local owner-browser/CSRF boundary and an
-`ENGRAPHIS_API_TOKEN`; in zero-token loopback mode, use the CLI.
+wizard always runs behind the local owner-browser/CSRF boundary. In token deployments that
+boundary is bound to the browser session minted from `ENGRAPHIS_API_TOKEN`; in zero-token
+loopback mode the same CSRF confirmation applies to the loopback-only runtime, so the wizard
+works without configuration.
## Supported formats
diff --git a/docs/MCP_TOOLS.md b/docs/MCP_TOOLS.md
index 2021a43b..32ebbec3 100644
--- a/docs/MCP_TOOLS.md
+++ b/docs/MCP_TOOLS.md
@@ -25,6 +25,17 @@ class, and execution revalidates availability, scope, authorization, and argumen
The Smart gateway exposes these nine tools directly; advanced capabilities remain available through
discovery and the validated executors.
+### Smart routine schemas are reduced by design
+
+The two routine Smart tools deliberately accept smaller allow-lists than their Classic
+namesakes; advanced controls are discoverable rather than routine:
+
+| Smart tool | Accepted parameters |
+|---|---|
+| `engraphis_remember` | `content`, `workspace`, `repo`, `session_id`, `mtype`, `importance`, `subject_key`, `claim_kind`; safe provenance is fixed internally |
+| `engraphis_recall_context` | `query`, `workspace`, `repo`, `session_id`, `k`, `token_budget`; always compact, no `response_mode` |
+
+
No user profile choice or tool switching is required. The dashboard `/mcp` endpoint and
`engraphis-mcp-http` use this Smart surface by default. `engraphis-mcp-classic` (or
`engraphis-mcp-http --classic`) preserves the 35 direct tools below for integrations that pin
@@ -84,7 +95,7 @@ the [memory write trust model](WRITE_REVIEW.md) and [recall recovery guide](RECA
| Write | `engraphis_ingest` | Applies the configured extractor (`chunk`, `llm`, or `llm_structured`). With `none`, it stores one verbatim memory. |
| Write | `engraphis_ingest_postgres_schema` | Stores a PostgreSQL schema snapshot and typed graph. The DSN is never stored. |
| Write | `engraphis_consolidate` | Runs a dry-run or live consolidation sweep. A live call can write resolved facts and receipts. |
-| Stateful read | `engraphis_recall_context` | Returns hard-budget context, compact sources, token usage, and optional diagnostics. Recommended for agent prompts. |
+| Stateful read | `engraphis_recall_context` | Returns hard-budget context, compact sources, token usage, and optional diagnostics. Recommended for agent prompts. Compact-only: it never accepts `response_mode` and never returns full memory bodies. |
| Stateful read | `engraphis_recall` | Runs hybrid vector, lexical, and graph recall. It records a receipt without strengthening weak matches. |
| Stateful read | `engraphis_recall_grounded` | Returns a cited answer or abstains when the evidence is too weak. It records a receipt and reinforces cited memories. |
| Stateful read | `engraphis_answer` | Backward-compatible alias for `engraphis_recall_grounded`. |
@@ -108,7 +119,8 @@ the [memory write trust model](WRITE_REVIEW.md) and [recall recovery guide](RECA
| Governance | `engraphis_pin` | Prevents future automatic decay or pruning. |
| Governance | `engraphis_correct` | Replaces memory content without losing the previous version; governed provenance remains pending unless separately approved. |
| Governance | `engraphis_promote` | Widens an explicitly approved memory's scope while preserving and linking its narrower history. |
-| Session | `engraphis_start_session` / `engraphis_end_session` | Starts or closes a work session. Exact retries are safe; `force_new=true` creates another session. |
+| Session | `engraphis_start_session` | Starts a work session. Exact retries are safe; `force_new=true` creates another session. |
+| Session | `engraphis_end_session` | Closes a work session with a summary and open threads. |
| Operations | `engraphis_stats` | Returns memory counts for health checks. |
| Operations | `engraphis_check_update` | Refreshes the release cache and reports whether a newer version is available. Update checks are OFF unless `ENGRAPHIS_UPDATE_CHECK` is set to an affirmative value; `=0` keeps them off. |
diff --git a/docs/OBSIDIAN_IMPORT.md b/docs/OBSIDIAN_IMPORT.md
index 8e398d84..e6742724 100644
--- a/docs/OBSIDIAN_IMPORT.md
+++ b/docs/OBSIDIAN_IMPORT.md
@@ -47,9 +47,11 @@ rejected.
A new browser vault requires a nonblank source label; folder selection prefills its root folder
name. Select the saved source identity when resuming or re-importing that vault.
-The trusted dashboard wizard uses the existing owner browser-session and CSRF
-confirmation boundary, so the local dashboard must have `ENGRAPHIS_API_TOKEN`
-configured. In zero-token loopback mode, use the CLI importer instead.
+The trusted dashboard wizard runs behind the existing owner browser-session and
+CSRF confirmation boundary. In token deployments that session is minted from
+`ENGRAPHIS_API_TOKEN`; in zero-token loopback mode the same CSRF confirmation
+applies to the loopback-only runtime, so the wizard works without
+configuration. The CLI importer remains available for scripted flows.
## What is imported
diff --git a/docs/SYNC.md b/docs/SYNC.md
index 5099f44b..51a6a795 100644
--- a/docs/SYNC.md
+++ b/docs/SYNC.md
@@ -1,201 +1,236 @@
-# Cloud Sync
-
-Engraphis remains local-first: the free engine stores memories in local SQLite and works
-without an account or network. **Cloud Sync** is a hosted Pro/Team service that connects
-authorized installations through Engraphis-managed relay storage.
-
-The public repository contains the customer-side protocol, deterministic merge engine, and
-relay client required to participate in that service. It does **not** contain the hosted relay,
-organization authorization, entitlement registry, storage credentials, automatic scheduler, or
-operations tooling. An environment variable cannot turn the public image into the official relay.
-
-## Product boundary
-
-| Layer | Public Apache package | Private hosted service |
-|---|---|---|
-| Local memory database and free engine | Yes | No requirement |
-| Deterministic bundle/merge protocol | Yes | Uses the same contract |
-| Customer relay client | Yes | Authenticates it |
-| Relay storage and tenant isolation | No | Yes |
-| Device registration and credential rotation | Client only | Authority |
-| Organization membership and named seats | No | Yes |
-| Automated cloud cadence and operations | No | Yes |
-
-The split is deliberate. Local checks in Apache-licensed code are not DRM and can be changed by
-a fork. The paid boundary is authorization to use the official private service and its operated
-infrastructure.
-
-Cloud Sync is available with hosted Pro and Team plans. See [local and hosted plans](HOSTED_PLANS.md)
-for pricing and included services.
-
-## Trial and grace
-
-The no-card Pro or Team trial begins after email confirmation and lasts **exactly 3 active
-days**.
-
-`workspace_write_grace` is separate and private-service enforced. It may preserve bounded
-hosted-account continuity operations for at most **24 hours** following an authoritative
-entitlement denial. It never extends the trial or subscription, and it never grants Cloud Sync,
-Analytics, Automation, Auto Dreaming, Auto Consolidation, Team access, seats, or credentials.
-Cloud access may stop immediately. The free local sync-folder primitive and local core are not
-gated by this hosted lifecycle state.
-
-## Configure a customer installation
-
-Hosted onboarding creates an owner-only cloud session under `~/.engraphis` (or
-`ENGRAPHIS_STATE_DIR`). For non-interactive clients, inject credentials through a secrets manager:
-
-```dotenv
-ENGRAPHIS_CLOUD_CONTROL_URL=https://api.engraphis.com
-ENGRAPHIS_CLOUD_COMPUTE_URL=https://compute.engraphis.com
-ENGRAPHIS_CLOUD_ORGANIZATION_ID=org_replace_me
-ENGRAPHIS_CLOUD_REFRESH_CREDENTIAL=
-```
-
-The refresh credential rotates. Refresh is serialized across threads and cooperating processes,
-and the client stores only the replacement needed for the next session in an owner-only file.
-After the first rotation, that saved replacement and its control/compute URLs are one credential
-family: they take precedence over environment bootstrap values, and environment URL changes
-cannot redirect that bearer credential. Reconnect with a fresh portal token to change endpoints.
-For unattended configuration, use process variables or the owner-private
-`~/.engraphis/config.env`; an explicit `ENGRAPHIS_ENV_FILE` must be an absolute owner-private
-regular file. Engraphis does not search the working directory for `.env`. Do not place credentials
-in source, documentation, container images, shell history, or support logs.
-
-The one-shot customer client remains available for explicit sync operations:
-
-```bash
-python -m scripts.sync \
- --db engraphis.db \
- --workspace acme \
- --relay https://relay.engraphis.com
-```
-
-Cloud Sync is fail-closed: install `engraphis[cloud-sync]` on Python 3.10+ and provision a
-32-byte URL-safe-base64 workspace key as `ENGRAPHIS_SYNC_E2EE_KEY` on every authorized device
-through a secrets manager. Generate it once on a trusted device and transfer it only through your
-own secure channel; Engraphis Cloud never receives, derives, or recovers this key. Relay
-authorization normally comes from the owner-only saved cloud session. An unattended
-`ENGRAPHIS_SYNC_TOKEN` also requires `ENGRAPHIS_SYNC_TOKEN_ORIGIN` matching the relay origin, so a
-credential cannot be redirected. The CLI intentionally has no secret-valued `--relay-token` or
-`--relay-e2ee-key` flags. A missing or malformed key stops Cloud Sync rather than uploading a
-plaintext bundle.
-
-```bash
-python -c "import base64, secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode().rstrip('='))"
-```
-
-The dashboard's **Sync now** action invokes the same customer protocol. The public package does
-not run a local auto-sync loop or ship a cron/Task Scheduler wrapper. Hosted automation belongs
-to the private service. A round with any incomplete workspace is a failure, even when other peers
-were applied successfully: the bounded report retains those good-peer totals, labels the result
-`incomplete`, and the CLI exits `1`. The dashboard therefore never presents a partial round as
-successful. An all-workspace entitlement denial still returns the hosted Pro/Team recovery CTA.
-
-### Local folder transport
-
-The public protocol also retains a manual folder transport for development, backup interchange,
-and offline testing:
-
-```bash
-python -m scripts.sync \
- --db engraphis.db \
- --workspace acme \
- --remote /path/to/shared-folder \
- --dry-run
-```
-
-This is a customer-controlled file exchange primitive, not the official Cloud Sync service. It
-has no hosted identity, seat, availability, support, or managed-storage guarantees.
-Folder caps, oversize omissions, and snapshot races are observable incomplete failures rather than
-successful partial backups.
-
-Anyone who can write to the shared folder can also choose the target `workspace_name`, so
-content arriving from a peer you do not control should be treated as untrusted: it is
-quarantined under local `trusted: false` provenance until you review and approve it.
-
-Operator note: the `operation_receipts`, `events`, and `audit` tables in the local SQLite
-database grow append-only by design - rows are hash-chained, and pruning them would break
-chain verification. Watch their size in the database file (for example with
-`sqlite3 engraphis.db "SELECT count(*) FROM operation_receipts"`) when planning capacity;
-the supported path for long-lived installations is archiving or rotating the whole database,
-not deleting rows.
-
-## Merge semantics
-
-Sync exchanges bounded workspace snapshots and merges them deterministically. Existing
-bi-temporal history is preserved: conflicts close validity windows or create explicit successor
-records rather than destructively overwriting facts. The public merge code is necessary so a
-customer can verify how their local database changes.
-
-Session scope is strictly device-local. Every exported workspace or repo bundle excludes both
-live and invalidated session-scoped rows, as well as `secret` rows, and includes a memory link only
-when both endpoints remain in the export. Inbound legacy or untrusted bundles cannot create,
-relabel, or overwrite session-scoped state because the sync format carries no authenticated
-session owner or lifecycle contract.
-
-Bundle format v3 preserves durable claim identity and the system-time at which a world-time
-invalidation was learned. It also carries a per-device `generation`, `previous_hash`,
-`state_hash`, and `tombstone_checkpoint`. Engraphis pulls its own device's remote snapshot before
-replacement and rejects an observed generation/hash-chain rollback. Current clients accept
-inbound v1 and v2 bundles for compatibility but export v3; older clients reject unknown versions
-instead of silently forwarding a downgraded snapshot.
-
-Erasure markers remain content-free and carry an `export_class`. Export includes only
-`remote_erasure` markers created for non-secret workspace/repo records that were eligible for
-sharing. Local `never_export` markers, including migrated legacy markers and erasures of secret,
-session, or reserved user-scope records, never leave the device. Bundle import rejects any
-tombstone not explicitly classified `remote_erasure`; a local `never_export` marker cannot later
-be upgraded to an exportable one.
-
-The first contact with a relay is deliberately `incomplete` and unanchored until the managed
-service supplies an authenticated workspace manifest/checkpoint. A local client can prove that an
-observed device chain did not roll back; it cannot prove that an untrusted relay did not withhold a
-device it has never observed.
-
-Bundle input is untrusted. The client validates schema and size limits before applying records,
-rechecks workspace scope, and retains provenance/audit evidence. Every inbound memory is re-homed
-under local `source: sync, trusted: false` provenance; a peer's serialized trust label, graph
-metadata, retention hints, or extractor output has no authority. Suspicious payloads are
-quarantined before indexing. A relay cannot inject a record outside the authorized workspace
-merely by changing bundle fields.
-
-An inbound bundle also cannot overwrite a locally approved memory with the same id. The local
-record remains the safe winner and a content-free `sync_trust_conflict` audit event records a
-competing peer payload. This intentionally favors integrity over automatic last-writer-wins for
-cross-trust collisions; promote/approve a fresh local record if the peer's information is verified.
-Likewise, unauthenticated bundle links may connect only records that remain in the untrusted
-replica; a peer cannot attach graph edges to locally approved memories.
-
-## Security and privacy
-
-- Local-only installations send no memory content to Engraphis. **Cloud Sync encrypts eligible
- shared-workspace changes end-to-end before they leave this device. Engraphis Cloud cannot read
- their contents; secret and session-scoped memories stay local.** Managed compute is separate:
- connecting an installation to Engraphis Cloud accepts its terms and enables it by default;
- operators may opt out with `ENGRAPHIS_MANAGED_COMPUTE_CONSENT=0`. It sends a readable, bounded
- snapshot over TLS because Engraphis Cloud must process that snapshot to produce results.
-- Treat cloud session and refresh files as credentials; keep their directory owner-only.
-- `secret` memories are excluded from managed uploads. Managed compute also rejects secret rows
- server-side.
-- Cloud Sync's end-to-end encryption applies to sync bundles, not to managed-compute snapshots or
- content deliberately submitted to a configured LLM provider. Those processors must be able to
- read the submitted content to perform the requested work.
-- Cloud Sync uses a fresh ChaCha20-Poly1305 nonce for each upload and authenticates the stored
- opaque bundle name plus workspace as associated data. The relay can store or replay ciphertext,
- but a tampered, renamed, cross-workspace, wrong-key, or legacy plaintext bundle is rejected
- before it reaches the merge engine.
-- Device credentials are not seats. Team seats are named organization members managed by the
- hosted control plane.
-- Revocation and expiry are authoritative server decisions. A locally modified client does not
- acquire service access without a valid hosted credential.
-
-## What Apache forks can do
-
-Apache-2.0 rights in code already published here are perpetual under that license and cannot be
-clawed back. A fork may alter or reuse the public client and merge protocol. That does not grant
-access to Engraphis-operated infrastructure, private service code, signing keys, customer data,
-support, or trademarks.
-
-This is why future defensible value lives in the private hosted relay, compute, identity,
-automation, security operations, and customer experience rather than in a local feature flag.
+# Cloud Sync
+
+Engraphis remains local-first: the free engine stores memories in local SQLite and works
+without an account or network. **Cloud Sync** is a hosted Pro/Team service that connects
+authorized installations through Engraphis-managed relay storage.
+
+The public repository contains the customer-side protocol, deterministic merge engine, and
+relay client required to participate in that service. It does **not** contain the hosted relay,
+organization authorization, entitlement registry, storage credentials, automatic scheduler, or
+operations tooling. An environment variable cannot turn the public image into the official relay.
+
+## Product boundary
+
+| Layer | Public Apache package | Private hosted service |
+|---|---|---|
+| Local memory database and free engine | Yes | No requirement |
+| Deterministic bundle/merge protocol | Yes | Uses the same contract |
+| Customer relay client | Yes | Authenticates it |
+| Relay storage and tenant isolation | No | Yes |
+| Device registration and credential rotation | Client only | Authority |
+| Organization membership and named seats | No | Yes |
+| Automated cloud cadence and operations | No | Yes |
+
+The split is deliberate. Local checks in Apache-licensed code are not DRM and can be changed by
+a fork. The paid boundary is authorization to use the official private service and its operated
+infrastructure.
+
+Cloud Sync is available with hosted Pro and Team plans. See [local and hosted plans](HOSTED_PLANS.md)
+for pricing and included services.
+
+## Trial and grace
+
+The no-card Pro or Team trial begins after email confirmation and lasts **exactly 3 active
+days**.
+
+`workspace_write_grace` is separate and private-service enforced. It may preserve bounded
+hosted-account continuity operations for at most **24 hours** following an authoritative
+entitlement denial. It never extends the trial or subscription, and it never grants Cloud Sync,
+Analytics, Automation, Auto Dreaming, Auto Consolidation, Team access, seats, or credentials.
+Cloud access may stop immediately. The free local sync-folder primitive and local core are not
+gated by this hosted lifecycle state.
+
+## Configure a customer installation
+
+Hosted onboarding creates an owner-only cloud session under `~/.engraphis` (or
+`ENGRAPHIS_STATE_DIR`). For non-interactive clients, inject credentials through a secrets manager:
+
+```dotenv
+ENGRAPHIS_CLOUD_CONTROL_URL=https://api.engraphis.com
+ENGRAPHIS_CLOUD_COMPUTE_URL=https://compute.engraphis.com
+ENGRAPHIS_CLOUD_ORGANIZATION_ID=org_replace_me
+ENGRAPHIS_CLOUD_REFRESH_CREDENTIAL=
+```
+
+The refresh credential rotates. Refresh is serialized across threads and cooperating processes,
+and the client stores only the replacement needed for the next session in an owner-only file.
+After the first rotation, that saved replacement and its control/compute URLs are one credential
+family: they take precedence over environment bootstrap values, and environment URL changes
+cannot redirect that bearer credential. Reconnect with a fresh portal token to change endpoints.
+For unattended configuration, use process variables or the owner-private
+`~/.engraphis/config.env`; an explicit `ENGRAPHIS_ENV_FILE` must be an absolute owner-private
+regular file. Engraphis does not search the working directory for `.env`. Do not place credentials
+in source, documentation, container images, shell history, or support logs.
+
+The one-shot customer client remains available for explicit sync operations:
+
+```bash
+python -m scripts.sync \
+ --db engraphis.db \
+ --workspace acme \
+ --relay https://relay.engraphis.com
+```
+
+Cloud Sync is fail-closed: install `engraphis[cloud-sync]` on Python 3.10+ and provision a
+32-byte URL-safe-base64 workspace key as `ENGRAPHIS_SYNC_E2EE_KEY` on every authorized device
+through a secrets manager. Generate it once on a trusted device and transfer it only through your
+own secure channel; Engraphis Cloud never receives, derives, or recovers this key. Relay
+authorization normally comes from the owner-only saved cloud session. An unattended
+`ENGRAPHIS_SYNC_TOKEN` also requires `ENGRAPHIS_SYNC_TOKEN_ORIGIN` matching the relay origin, so a
+credential cannot be redirected. The CLI intentionally has no secret-valued `--relay-token` or
+`--relay-e2ee-key` flags. A missing or malformed key stops Cloud Sync rather than uploading a
+plaintext bundle.
+
+```bash
+python -c "import base64, secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode().rstrip('='))"
+```
+
+The dashboard's **Sync now** action invokes the same customer protocol. The public package does
+not run a local auto-sync loop or ship a cron/Task Scheduler wrapper. Hosted automation belongs
+to the private service. A round with any incomplete workspace is a failure, even when other peers
+were applied successfully: the bounded report retains those good-peer totals, labels the result
+`incomplete`, and the CLI exits `1`. The dashboard therefore never presents a partial round as
+successful. An all-workspace entitlement denial still returns the hosted Pro/Team recovery CTA.
+
+### Local folder transport
+
+The public protocol also retains a manual folder transport for development, backup interchange,
+and offline testing:
+
+```bash
+python -m scripts.sync \
+ --db engraphis.db \
+ --workspace acme \
+ --remote /path/to/shared-folder \
+ --dry-run
+```
+
+This is a customer-controlled file exchange primitive, not the official Cloud Sync service. It
+has no hosted identity, seat, availability, support, or managed-storage guarantees.
+Folder caps, oversize omissions, and snapshot races are observable incomplete failures rather than
+successful partial backups.
+
+Anyone who can write to the shared folder can also choose the target `workspace_name`, so
+content arriving from a peer you do not control should be treated as untrusted: it is
+quarantined under local `trusted: false` provenance until you review and approve it.
+
+Operator note: the `operation_receipts`, `events`, and `audit` tables in the local SQLite
+database grow append-only by design - rows are hash-chained, and pruning them would break
+chain verification. Watch their size in the database file (for example with
+`sqlite3 engraphis.db "SELECT count(*) FROM operation_receipts"`) when planning capacity;
+the supported path for long-lived installations is archiving or rotating the whole database,
+not deleting rows.
+
+### Secure erasure, confirmation, and rotation
+
+`MemoryService.secure_erase()` (and `engraphis_secure_erase` / `POST /api/secure-erase`)
+is confirm-gated: it requires explicit local-operator confirmation
+(`confirmed=True`; `confirmed=true` over MCP). Without it the call fails closed with a
+validation error. `engraphis_forget` remains a deprecated retire-with-history alias: it never deletes,
+and its responses now say so and point at `secure_erase`.
+
+On success the response carries the Store's `impact` report alongside the erase result:
+`receipt_refs` / `event_refs` (content-free references touched by the erasure),
+`backup_note` (which recognised local recovery backups were scanned), and
+`wal_vacuum_status` (whether secure-delete/WAL/VACUUM maintenance completed). The
+erasure itself is recorded in the hash-chained audit trail.
+
+Rotation runbook for a leaked credential (erasure is local-only remediation, not
+universal deletion):
+
+1. Rotate or revoke the credential first: erasure cannot recall data an agent
+ already read.
+2. Run the confirmed `secure_erase` and read the `impact` report: confirm
+ `wal_vacuum_status`, note `receipt_refs` / `event_refs`, and follow `backup_note`.
+3. Remediate separately everything Engraphis cannot erase: filesystem snapshots,
+ copied/exported databases, cloud backups, and remote sync peers that have not yet
+ accepted an eligible `remote_erasure` marker. `never_export` markers (secret,
+ session, reserved user-scope, migrated legacy) stay local and never notify peers.
+
+Peer erasures are never applied blindly. A `remote_erasure` tombstone for a locally
+quarantined or pending-review row is *held* for operator review: local bytes stay
+quarantined (visible in the review queue), nothing is deleted, and the hold is
+reported as `tombstones_held` with a `sync_tombstone_held` audit event, never
+silently dropped. Operators may additionally configure `SyncEngine(...,
+erase_device_allowlist={...})` so erasures asserted by any other device are held the
+same way. These holds complement the per-device generation/hash-chain rollback gate,
+which still rejects stale or forked snapshots before anything is applied.
+
+## Merge semantics
+
+Sync exchanges bounded workspace snapshots and merges them deterministically. Existing
+bi-temporal history is preserved: conflicts close validity windows or create explicit successor
+records rather than destructively overwriting facts. The public merge code is necessary so a
+customer can verify how their local database changes.
+
+Session scope is strictly device-local. Every exported workspace or repo bundle excludes both
+live and invalidated session-scoped rows, as well as `secret` rows, and includes a memory link only
+when both endpoints remain in the export. Inbound legacy or untrusted bundles cannot create,
+relabel, or overwrite session-scoped state because the sync format carries no authenticated
+session owner or lifecycle contract.
+
+Bundle format v3 preserves durable claim identity and the system-time at which a world-time
+invalidation was learned. It also carries a per-device `generation`, `previous_hash`,
+`state_hash`, and `tombstone_checkpoint`. Engraphis pulls its own device's remote snapshot before
+replacement and rejects an observed generation/hash-chain rollback. Current clients accept
+inbound v1 and v2 bundles for compatibility but export v3; older clients reject unknown versions
+instead of silently forwarding a downgraded snapshot.
+
+Erasure markers remain content-free and carry an `export_class`. Export includes only
+`remote_erasure` markers created for non-secret workspace/repo records that were eligible for
+sharing. Local `never_export` markers, including migrated legacy markers and erasures of secret,
+session, or reserved user-scope records, never leave the device. Bundle import rejects any
+tombstone not explicitly classified `remote_erasure`; a local `never_export` marker cannot later
+be upgraded to an exportable one.
+
+The first contact with a relay is deliberately `incomplete` and unanchored until the managed
+service supplies an authenticated workspace manifest/checkpoint. A local client can prove that an
+observed device chain did not roll back; it cannot prove that an untrusted relay did not withhold a
+device it has never observed.
+
+Bundle input is untrusted. The client validates schema and size limits before applying records,
+rechecks workspace scope, and retains provenance/audit evidence. Every inbound memory is re-homed
+under local `source: sync, trusted: false` provenance; a peer's serialized trust label, graph
+metadata, retention hints, or extractor output has no authority. Suspicious payloads are
+quarantined before indexing. A relay cannot inject a record outside the authorized workspace
+merely by changing bundle fields.
+
+An inbound bundle also cannot overwrite a locally approved memory with the same id. The local
+record remains the safe winner and a content-free `sync_trust_conflict` audit event records a
+competing peer payload. This intentionally favors integrity over automatic last-writer-wins for
+cross-trust collisions; promote/approve a fresh local record if the peer's information is verified.
+Likewise, unauthenticated bundle links may connect only records that remain in the untrusted
+replica; a peer cannot attach graph edges to locally approved memories.
+
+## Security and privacy
+
+- Local-only installations send no memory content to Engraphis. **Cloud Sync encrypts eligible
+ shared-workspace changes end-to-end before they leave this device. Engraphis Cloud cannot read
+ their contents; secret and session-scoped memories stay local.** Managed compute is separate:
+ connecting an installation to Engraphis Cloud accepts its terms and enables it by default;
+ operators may opt out with `ENGRAPHIS_MANAGED_COMPUTE_CONSENT=0`. It sends a readable, bounded
+ snapshot over TLS because Engraphis Cloud must process that snapshot to produce results.
+- Treat cloud session and refresh files as credentials; keep their directory owner-only.
+- `secret` memories are excluded from managed uploads. Managed compute also rejects secret rows
+ server-side.
+- Cloud Sync's end-to-end encryption applies to sync bundles, not to managed-compute snapshots or
+ content deliberately submitted to a configured LLM provider. Those processors must be able to
+ read the submitted content to perform the requested work.
+- Cloud Sync uses a fresh ChaCha20-Poly1305 nonce for each upload and authenticates the stored
+ opaque bundle name plus workspace as associated data. The relay can store or replay ciphertext,
+ but a tampered, renamed, cross-workspace, wrong-key, or legacy plaintext bundle is rejected
+ before it reaches the merge engine.
+- Device credentials are not seats. Team seats are named organization members managed by the
+ hosted control plane.
+- Revocation and expiry are authoritative server decisions. A locally modified client does not
+ acquire service access without a valid hosted credential.
+
+## What Apache forks can do
+
+Apache-2.0 rights in code already published here are perpetual under that license and cannot be
+clawed back. A fork may alter or reuse the public client and merge protocol. That does not grant
+access to Engraphis-operated infrastructure, private service code, signing keys, customer data,
+support, or trademarks.
+
+This is why future defensible value lives in the private hosted relay, compute, identity,
+automation, security operations, and customer experience rather than in a local feature flag.
diff --git a/docs/benchmark-evidence/offline-fixtures-v1.json b/docs/benchmark-evidence/offline-fixtures-v1.json
index f7140efd..7ad25a5f 100644
--- a/docs/benchmark-evidence/offline-fixtures-v1.json
+++ b/docs/benchmark-evidence/offline-fixtures-v1.json
@@ -1,91 +1,93 @@
-{
- "schema": "engraphis-public-offline-fixtures/v1",
- "generated_on": "2026-08-08",
- "privacy": {
- "contains_raw_questions": false,
- "contains_answers": false,
- "contains_prompts": false,
- "contains_customer_data": false,
- "contains_per_record_fingerprints": false
- },
- "suite": {
- "digest": "4bfdfd6ccdf34ff7daa7441b8e788371c31985efe031b6520a265ef11f71ed1b",
- "digest_method": "sha256(canonical compact JSON mapping each sorted path to its file SHA-256)",
- "files": {
- "eval/chunking_eval.py": "a16544353940c0a8c40cea3b9932d3399b35ea5994b809b78f5dbe4a952c467f",
- "eval/datasets/codemem.jsonl": "341313023c22850a2e14f02742b571ad1deca824f886a1654a59541304c01f3c",
- "eval/datasets/longdoc.jsonl": "7f5ade95e1f283d0db8cf78e53ed8995d3534f847e616d2c0005fd8da37ac790",
- "eval/grounded.py": "75ba96a4427508f2718323d283f7889fc90901a6176f12c4b3518f1ede5d96dd",
- "eval/performance.py": "e17ea78095e4e592717bc5d9d8e34d55fd98c3fd28d1a8104a20c227d4d619c9"
- }
- },
- "runs": [
- {
- "id": "offline-chunking",
- "command": "python -m eval.chunking_eval --dataset eval/datasets/longdoc.jsonl --k 5",
- "config_digest": "c1c8196aa7e1568ef3844a9fb2d76b87f342c39108e32d6ad144b885a76143b8",
- "config_digest_method": "sha256(UTF-8 exact command)",
- "boundary": "Deterministic offline retrieval fixture; normalized-character token estimator; not external QA or provider billing.",
- "result": {
- "documents": 6,
- "questions": 18,
- "k": 5,
- "token_counter": "engraphis.chars4.v1",
- "whole": {
- "memories": 6,
- "recall_at_k": 1.0,
- "mean_context_tokens": 740.3,
- "mean_evidence_tokens": 162.2,
- "max_stored_tokens": 213
- },
- "chunked": {
- "memories": 24,
- "recall_at_k": 1.0,
- "mean_context_tokens": 214.3,
- "mean_evidence_tokens": 42.4,
- "max_stored_tokens": 59
- },
- "context_reduction_pct": 71.1
- }
- },
- {
- "id": "offline-performance",
- "command": "python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10 --json",
- "config_digest": "bbe4aca81e58d4830e50a8fc7729a1d15b71d97a6299bccd79432b7f119677d7",
- "config_digest_method": "sha256(UTF-8 exact command)",
- "boundary": "Deterministic offline CodeMem fixture; serialized JSON-shape payload proxies, not MCP transport responses, provider billing, or latency claims.",
- "result": {
- "dataset_cases": 14,
- "memories": 44,
- "questions": 26,
- "timed_recalls": 260,
- "k": 5,
- "token_budget": 1500,
- "token_counter": "engraphis.regex.v1",
- "recall_at_k": 1.0,
- "hit_at_k": 1.0,
- "answer_token_recall": 1.0,
- "mean_context_tokens": 85.38,
- "max_context_tokens": 108,
- "full_serialized_payload_tokens": 23810,
- "compact_serialized_payload_tokens": 10202,
- "saved_serialized_payload_tokens": 13608,
- "serialized_payload_savings_ratio": 0.5715
- }
- },
- {
- "id": "offline-grounded",
- "command": "python -m eval.grounded",
- "config_digest": "590442e51e3642c10489165759919dc86ffac62c182937330c153e7f8d5fc26f",
- "config_digest_method": "sha256(UTF-8 exact command)",
- "boundary": "Deterministic offline support/abstention fixture; not a frontier-model answer-quality score.",
- "result": {
- "answerable": 5,
- "grounded": 5,
- "off_topic": 5,
- "abstained": 5,
- "decision_accuracy": 1.0
- }
- }
- ]
-}
+{
+ "generated_on": "2026-09-03",
+ "privacy": {
+ "contains_answers": false,
+ "contains_customer_data": false,
+ "contains_per_record_fingerprints": false,
+ "contains_prompts": false,
+ "contains_raw_questions": false
+ },
+ "runs": [
+ {
+ "boundary": "Deterministic offline retrieval fixture; normalized-character token estimator; not external QA or provider billing.",
+ "command": "python -m eval.chunking_eval --dataset eval/datasets/longdoc.jsonl --k 5",
+ "config_digest": "c1c8196aa7e1568ef3844a9fb2d76b87f342c39108e32d6ad144b885a76143b8",
+ "config_digest_method": "sha256(UTF-8 exact command)",
+ "id": "offline-chunking",
+ "result": {
+ "chunked": {
+ "max_stored_tokens": 59,
+ "mean_context_tokens": 214.3,
+ "mean_evidence_tokens": 42.4,
+ "memories": 24,
+ "recall_at_k": 1.0
+ },
+ "context_reduction_pct": 71.1,
+ "documents": 6,
+ "k": 5,
+ "questions": 18,
+ "token_counter": "engraphis.chars4.v1",
+ "whole": {
+ "max_stored_tokens": 213,
+ "mean_context_tokens": 740.3,
+ "mean_evidence_tokens": 162.2,
+ "memories": 6,
+ "recall_at_k": 1.0
+ }
+ }
+ },
+ {
+ "boundary": "Deterministic offline CodeMem fixture; serialized JSON-shape payload proxies, not MCP transport responses, provider billing, or latency claims.",
+ "command": "python -m eval.performance --dataset eval/datasets/codemem.jsonl --k 5 --iterations 10 --json",
+ "config_digest": "bbe4aca81e58d4830e50a8fc7729a1d15b71d97a6299bccd79432b7f119677d7",
+ "config_digest_method": "sha256(UTF-8 exact command)",
+ "id": "offline-performance",
+ "result": {
+ "answer_token_recall": 1.0,
+ "compact_serialized_payload_tokens": 10202,
+ "dataset_cases": 14,
+ "full_serialized_payload_tokens": 23810,
+ "hit_at_k": 1.0,
+ "k": 5,
+ "max_context_tokens": 108,
+ "mean_context_tokens": 85.38,
+ "memories": 44,
+ "questions": 26,
+ "recall_at_k": 1.0,
+ "saved_serialized_payload_tokens": 13608,
+ "serialized_payload_savings_ratio": 0.5715,
+ "timed_recalls": 260,
+ "token_budget": 1500,
+ "token_counter": "engraphis.regex.v1"
+ }
+ },
+ {
+ "boundary": "Deterministic offline support/abstention fixture; not a frontier-model answer-quality score.",
+ "command": "python -m eval.grounded",
+ "config_digest": "590442e51e3642c10489165759919dc86ffac62c182937330c153e7f8d5fc26f",
+ "config_digest_method": "sha256(UTF-8 exact command)",
+ "id": "offline-grounded",
+ "result": {
+ "abstained": 6,
+ "answerable": 5,
+ "decision_accuracy": 1.0,
+ "grounded": 5,
+ "off_topic": 6,
+ "quarantine_hits": 1,
+ "quarantined": 1
+ }
+ }
+ ],
+ "schema": "engraphis-public-offline-fixtures/v1",
+ "suite": {
+ "digest": "f5544b56f009b2fc16dbae992039971899daf2b0095ee8d15bad5914c7f399a9",
+ "digest_method": "sha256(canonical compact JSON mapping each sorted path to its file SHA-256)",
+ "files": {
+ "eval/chunking_eval.py": "a16544353940c0a8c40cea3b9932d3399b35ea5994b809b78f5dbe4a952c467f",
+ "eval/datasets/codemem.jsonl": "341313023c22850a2e14f02742b571ad1deca824f886a1654a59541304c01f3c",
+ "eval/datasets/longdoc.jsonl": "7f5ade95e1f283d0db8cf78e53ed8995d3534f847e616d2c0005fd8da37ac790",
+ "eval/grounded.py": "053d5193b716a2c3e507fcd44057d392de910a4442b46bd7cc1f30ac0ba68541",
+ "eval/performance.py": "e17ea78095e4e592717bc5d9d8e34d55fd98c3fd28d1a8104a20c227d4d619c9"
+ }
+ }
+}
diff --git a/docs/benchmark-evidence/offline-fixtures-v1.json.sha256 b/docs/benchmark-evidence/offline-fixtures-v1.json.sha256
index ed19362f..4899fed6 100644
--- a/docs/benchmark-evidence/offline-fixtures-v1.json.sha256
+++ b/docs/benchmark-evidence/offline-fixtures-v1.json.sha256
@@ -1 +1 @@
-0f60b0868444f676fe14c5f94d7db2c475e22669930c4d760881d0842eaa6800 offline-fixtures-v1.json
+8a74e9f48e25f33d625d4cc5c1b14fec3055891944adccf615c440e84e4b0255 offline-fixtures-v1.json
diff --git a/docs/images/context-efficiency.svg b/docs/images/context-efficiency.svg
index 0df330b9..38a1d1e6 100644
--- a/docs/images/context-efficiency.svg
+++ b/docs/images/context-efficiency.svg
@@ -1,41 +1,41 @@
-
+
diff --git a/docs/images/evidence-backed-agent-examples.svg b/docs/images/evidence-backed-agent-examples.svg
index ebbe7588..078c9eed 100644
--- a/docs/images/evidence-backed-agent-examples.svg
+++ b/docs/images/evidence-backed-agent-examples.svg
@@ -1,51 +1,51 @@
-
+
diff --git a/engraphis/__init__.py b/engraphis/__init__.py
index 17214de7..cabaeb01 100644
--- a/engraphis/__init__.py
+++ b/engraphis/__init__.py
@@ -2,7 +2,7 @@
from importlib.metadata import PackageNotFoundError, version as _dist_version
-_SOURCE_VERSION = "1.6"
+_SOURCE_VERSION = "1.7"
try:
__version__ = _dist_version("engraphis")
@@ -14,7 +14,7 @@
except PackageNotFoundError: # source tree without an installed distribution
# Keep in step with [project] version in pyproject.toml — tests/test_packaging.py
# pins the two together so a release cannot ship them out of sync.
- __version__ = "1.6"
+ __version__ = "1.7"
def _default_memory_engine_factory(**kwargs):
diff --git a/engraphis/classic_assets/dashboard.js b/engraphis/classic_assets/dashboard.js
index d01462f1..f325b5c1 100644
--- a/engraphis/classic_assets/dashboard.js
+++ b/engraphis/classic_assets/dashboard.js
@@ -1236,7 +1236,7 @@ function loadGraphEngine(loadAll=false){
GRAPH_ENGINE_LOADING=new Promise((resolve,reject)=>{
const script=document.createElement('script');
const bust=GRAPH_ENGINE_RETRY>0?'&r='+GRAPH_ENGINE_RETRY:'';
- script.src='/v2-assets/engraphis-graph.js?v=20260902-slider-merge-1'+bust;
+ script.src='/v2-assets/engraphis-graph.js?v=20260903-rotation-balance-1'+bust;
/* A 200 that never registers the global is a corrupt/truncated asset, not a success —
resolving there would hand graphRenderEngine() an undefined EngraphisGraph. Failed
attempts drop the script node and clear the memo so the next call retries with a
diff --git a/engraphis/classic_assets/index.html b/engraphis/classic_assets/index.html
index fcca95be..d89b535a 100644
--- a/engraphis/classic_assets/index.html
+++ b/engraphis/classic_assets/index.html
@@ -6,7 +6,7 @@
Engraphis
-
+
Skip to main content
@@ -164,11 +164,11 @@
Forces
42
20
-
26
+
26
Appearance
3
12
-
0.7
+
0.7
30
Color by
@@ -349,6 +349,6 @@
graph view. dashboard.js fetches both on demand from graphRender(); see loadForceGraph()
and loadGraphEngine(). scripts/externalize_dashboard_assets.py enforces both halves:
they stay out of this file, and the lazy references still have to resolve. -->
-
+