Roadmap
The target user is a coding agent or long-running developer assistant that must remember project facts without silently retaining stale or contradicted context. The failure modes dent8 attacks: stale project facts, hidden contradiction, poisoned summaries, and unexplained context retrieval.
This roadmap is dependency-ordered: each item unlocks the next, and each is annotated with the integrity invariant it makes real. It supersedes the older MVP checklist.
The wedge is multiple coding agents (and a human) sharing one verified fact base about one repository (project-brief.md §MVP User).
Shipped: the v0.4–v0.6 near-term list
Section titled “Shipped: the v0.4–v0.6 near-term list”All five items of the previous near-term list landed by v0.6.1:
- Capture+inject loop ✅ —
dent8 context/dent8 capturewith read-audit events on every retrieval surface, including MCPresources/read. (Invariant: unexplained context retrieval becomes explainable.) - Default authority profile ✅ — human > CI > agent via
dent8 authority defaults; grant issuer/scope enforced at the write boundary (no self-escalation). (Invariant: authority is typed and policy-visible.) - On-ramp ✅ — value-first README/Getting Started; init → assert → explain timed under
the 2-minute budget by
examples/on-ramp/demo.sh. - External evaluation ✅ — the 47-case literature-adapted corpus with an honest
block/detect/out-of-model tally, plus the modeled Mem0/Zep integrity-axis comparison in
dent8 eval. (Invariant: the result generalizes beyond self-authored fixtures.) - Python/TS reachability ✅ — thin SDKs over the CLI’s JSON machine contract on PyPI and
npm (
sdks/), tested against the real binary in CI, released tokenless via Trusted Publishing. Bonus beyond the list:dent8 whatifsurfaced policy-counterfactual replay (novelty rank 2), and the docs now live at xyzzylabs.github.io/dent8.
Near-term focus (post-v0.6)
Section titled “Near-term focus (post-v0.6)”Priority order. The first item gates the rest — the frozen directions below unfreeze on evidence of users, not on more features.
- Launch and the feedback loop. Announce (the release is announceable: 2-minute on-ramp, honest evals, three registries, docs site), then treat the first weeks of issues and questions as the roadmap’s primary input. (No invariant — an unused firewall protects nothing.)
- Legitimate-traffic evaluation. ◑ The measurement is built: a designed benign-revision
corpus runs through the real firewall in
dent8 evaland reports the false-positive rate — currently 0 across 22 benign writes / 7 scenarios (run_legitimate_corpus, gated in the exit code and frozen as a test; see evals.md). What remains is feeding it real captured agent sessions instead of designed ones — still blocked only on trace data, which dogfooding and early users produce. (Invariant: the firewall does not tax legitimate revision — now measured, not just asserted.) - Concurrency load testing and tuning. ✅ Both backends:
scripts/load-test.sh(N parallel writers; a distinct-fact throughput phase plus a deliberate same-fact supersession herd) found and fixed three real defects — BUSY-at-connect classified fatal, stale-snapshot commits reported terminal instead of retried, and optimistic-retry livelock under sustained contention, fixed with a cross-process write lease per backend (SQLite sidecarBEGIN IMMEDIATE; Postgres session advisory lock — see storage.md). (Invariant held on both: every write eventually admitted, exactly one believed value,verifygreen.) - MCP
resources/subscribe. ✅ Both transports: subscribe to adent8://{kind}/{key}/{predicate}stream and receivenotifications/resources/updatedwhen it changes — immediately for writes through the same connection, within a poll tick for writes from any other process sharing the store. The daemon pushes per connection anddent8 mcp proxypumps frames bidirectionally, so daemon clients get pushes too. (Invariant held: an agent’s injected context cannot silently go stale between reads.) - Identity productization. ✅ All three platforms:
keychain:<account>is accepted wherever a key path is (DENT8_IDENTITY_KEY, keygen--out,--issuer-key,--public-key) — the key lives in the OS keychain (macOS Keychain; any Linux Secret Service — GNOME Keyring/KWallet — viasecret-tool; Windows Credential Manager), the public key derives from the private item, and keygen refuses to overwrite, same as files. (Invariant held: stealing a source identity now takes more than a same-user file read — no dotfile, backup, or synced-home copy exists.) The team key-distribution story is documented and exercised end to end in team-identity.md — commit the public artifacts, keys never travel, revocation is a reviewed PR.
Unfrozen — the control plane shipped: dent8 ui serves a read-only, human-first memory
dashboard from the stock binary (ADR 0020 steps 2+3: a stable localhost read/audit API plus
the web app). Four views organised around the belief base, not the plumbing: Memory (a
headline verdict + stat tiles + the believed facts as cards with values, freshness, and
contested pairs inline; click for the receipt + replay drawer), Activity (the event
feed), What-if (counterfactual re-fold), and Health (a status-page rollup that folds
doctor, witness coverage/tamper, native audit, and raw runtime detail behind one
healthy/attention banner). Light/dark, deep-linkable tabs, click-to-pause poll. The Tauri
desktop shell (step 4) and write actions (step 5) remain later packaging over this same
surface. Still explicitly frozen until the wedge has users: operated-witness hosting and
any training-substrate direction.
Where the code actually is
Section titled “Where the code actually is”See STATUS.md for the authoritative tier list. In summary, the MVP loop now runs end to end through the CLI and MCP surfaces:
- The firewall is enforced at the write boundary (
EventStore::appendviaarbitrate): authority-weighted supersession, the LFI canonical hard-alarm, and subject-aware anti-laundering — runnable via the lifecycle CLI commands,dent8 eval,examples/firewall/demo.sh, anddent8 mcp serve. - serde +
canonical_bytes+event_hash/hash_chainare wired into append and verification; the Postgres adapter stores and re-verifies the global chain. - The coding-agent predicate registry drives the firewall: per-predicate authority floor, default TTL, and uniqueness.
- The full lifecycle is runnable and persistent:
assert/supersede/retract/contradict/reinforce/expire/derive/explain/replay/facts list/snapshot/verify/conflicts/eval/export, plus MCP tools for the same belief surface. - Persistence runs over the local file dev store by default, or over the transactional
async backends selected by
DENT8_STORE_URL: embedded SQLite (stock build) and Postgres (--features postgres).
What remains to make it a hardened multi-user product:
- Signed identity operations. The stock CLI now includes the authn primitive:
dent8 init --identity/dent8 init --agent <profile>create issuer-signed grants binding source ids to source public keys, and every configured write checks source-key possession at the CLI/MCP boundary. Secret-store-backed keys shipped (keychain:<account>on all three platforms) and key distribution is documented and exercised (team-identity.md); signed key rotation/revocation and issuer-signed, hash-chained grant-log history (ADR 0014) are shipped too (dent8 identity rotate-source/revoke/backfill-grant-log). What remains is hardware-backed keys (HSM/YubiKey-class) and richer team policy workflows beyond the documented pattern. - Operated witness service.
dent8 witnessis a runnable signed-tree-head primitive; role doctor checks validate writer/signer separation,publishidempotently appends heads to an external JSONL sequence, andverify-publishedverifies externally saved heads so local witness-log rollback cannot erase retained evidence. The deployment is packaged inexamples/witness-operated/(Docker Compose signer / publisher / monitor split over a shared Postgres store, built from the repoDockerfile, plus hardened systemd units) with key-rotation and publication-channel guidance; what remains is hosting it — a managed signer/publication service instead of your own second host. - Production ergonomics under concurrency — done. The async adapters reserve
event:{n}id ranges from the database before signing (unique, not gap-free) and serialize appends, with an in-transaction final projection check for touched unique predicates; the load testing and tuning landed (cross-process write leases +scripts/load-test.sh, item 3 above). - Richer protocol/product surfaces. The v0 MCP server is useful today, the thin
Python/TS SDKs shipped (
sdks/),resources/subscribepushes fact-change notifications on both transports, and MCP-over-HTTP ships (dent8 mcp serve --http, ADR 0019); the officialrmcpSDK, streamable-HTTP push, prompts, and thedent8 uiTauri shell (ADR 0020) are later. - Remaining formal/eval work.
proptestsuites, golden replay fixtures, scenario-family fixtures, the adversarial corpus, andcargo-fuzztargets (the deserialize→fold→canonicalize path andCanonicalJsonidempotency, infuzz/, with a bounded 60s-per-target CI smoke) are built. The Stateright-style append/projection model remains open.
Operational persistence is no longer the gap — it is built and runnable on two backends
(Postgres and embedded SQLite, behind the AsyncEventStore boundary). The remaining gap is
productization: operating signed source identity well and running an operated witness
service.
Core Fold Work — Done For MVP
Section titled “Core Fold Work — Done For MVP”These are pure-dent8-core changes that make the integrity thesis true in the fold
itself, independent of storage. They are cheap and they are what makes dent8 more
than event-sourcing-with-nicer-words. They are also the prerequisite for every
defensible novelty direction (research/novelty.md): the
verified non-resurrection theorem proves a property of authority arbitration,
policy-counterfactual replay varies it, and earned entrenchment feeds it. The MVP
mechanisms are built; the remaining bullets here are refinements, not blockers.
- [DONE] Authority-as-entrenchment resolution.
apply_eventrejects aSupersededevent whose challenger authority is strictly below the incumbent’s (InsufficientAuthority), confidence kept separate. Tested directly and exhaustively over the 5×5 authority lattice, with a#[cfg(kani)]non-resurrection harness. (belief-revision.md §Adopt-2.) - [DONE] Earned entrenchment v0 (novelty rank 3).
FactStatetracks authority-weightedcorroborating_sources(corroboration_at_or_above, Sybil- resistant);SubjectProjection::unearned_supersessionsaudits each supersession against the replacing fact’s actual authority and earned entrenchment, flaggingAuthorityDowngradeandWeakerEntrenchment. The “survived-challenge” half is built too (ADR 0015): a rejected challenge is recorded on the incumbent’s stream asfact.challenge_rejected(with the challenger’s provenance and effective authority; Sybil-resistantsurvived_challenges_at_or_above), and both the always-on unearned-supersession audit and the opt-in earned-supersession gate (DENT8_ENTRENCHMENT_GATE=1) now weigh earned entrenchment — authority-weighted corroboration plus survived challenges (ADR 0017; the rejection reason isWeakerEntrenchment, the oldWeakerCorroborationstill deserializes). (research/novelty.md rank 3.) - [DONE] LFI “gentle-explosion” tier.
apply_event’sContradictedarm returnsCanonicalContradictionfor a contradiction against anAuthorityLevel::Canonicalfact; ordinary contradictions still localize toContested. Future: uniqueness- constrained predicates (no such flag in the model yet). (belief-revision.md §Adopt-3.) - [DONE] Read-time freshness evaluator + read surface.
FactState::is_fresh_at(now)bounds the full validity window[valid_from, expires_at)— TTL and the assertedvalid_to/valid_from(ADR 0016) — kept separate from the lifecycle, andexplain(CLI + the MCPexplaintool +resources/read) now applies it: a still-Activefact past its TTL orvalid_tois headline-flagged[stale — no longer valid], one whosevalid_fromis still in the future[not yet valid], and the receipt carriesfresh+not_yet_valid+ thevalid_from/expires_atwindow. (Invariant T4 in threat-model.md; remaining residuals tracked there.) - [DONE] Policy-counterfactual replay (novelty rank 2).
EpistemicPolicy(distrusted sources, authority floor, confidence floor) +replay_fact_with_policydiff_statesre-fold the same log under different trust assumptions, with zero model calls. (research/novelty.md rank 2.)
- [DONE] Cross-stream lineage check.
replay_entityfolds all of an subject’s fact streams into anSubjectProjection;lineage_issues()flags dangling supersession, supersession-by-an-invalidated-fact, and supersession cycles (including self-supersession).dent8 verifysurfaces lineage issues and retraction taint; a richer debugger/explain tree remains future product work. Contradiction-edge integrity is deliberately out of scope (a contradictor may live in another subject).
Canonical Serialization And Hash Chain — Done
Section titled “Canonical Serialization And Hash Chain — Done”Status. Built and tested in dent8-core/src/hash.rs:
serde derives on the FactEvent graph; canonical_bytes (sorted-key serde_json
form — not JCS); event_hash/hash_chain (SHA-256, injective length-framed leaf,
0x00 RFC 6962 domain separation); CANON_VERSION as the schema version. Tests cover
key-order independence, round-trip stability, injective genesis/previous, and
tamper-cascade. The migration’s DB-generated recorded_at/edge created_at are
dropped. See storage.md §Canonicalization and
ADR 0004.
Crates. serde, serde_json, sha2, hex (no serde_jcs — JCS interop is not
needed yet).
Remaining. No MVP blocker remains here. FactValue::Json canonicalization — ADR 0004
item 6 — is done via the CanonicalJson newtype. A real JCS implementation remains
deferred until there is a concrete cross-language interoperability requirement.
Postgres Store Adapter — Done
Section titled “Postgres Store Adapter — Done”Why. This is where dent8 becomes a store of record rather than an in-memory/file-backed developer loop.
Invariant. projection == fold(events) and append-atomicity.
Status. Built and DB-verified. PostgresEventStore uses sqlx, transactional append,
transaction-scoped advisory-lock serialization for the global chain, shared
arbitrate_events, JSONB event storage, and materialized projection/edge tables. The
adapter populates and verifies event_hash / previous_event_hash; DB-generated
event timestamps were removed so appender-supplied timestamps remain authoritative.
DATABASE_URL-gated tests pass against live postgres:16, including projection/edge
materialization and a live CLI-over-Postgres path.
Also done. The sync-vs-async decision is resolved as two traits: sync EventStore for
the file/in-memory path and feature-gated AsyncEventStore for async backends. Embedded
SQLite is implemented as the stock local async backend (sqlite://), proving Postgres is an
adapter, not the architecture.
Remaining. Richer per-column event tables /
uses_as_evidence edges, operational tuning, and identity operations (key distribution /
external signers) are future product work. (Source-key rotation (dent8 identity rotate-source), revocation (dent8 identity revoke), and append-only grant-log history —
ADR 0014 — are built.)
Replay / Explain CLI — Done
Section titled “Replay / Explain CLI — Done”Why. dent8 replay/dent8 explain are the demoable surface of the integrity thesis.
Both are built (real commands, not stubs), alongside facts list / verify /
conflicts / derive / eval and the full write lifecycle.
Invariant. Deterministic replay and auditability.
Status. Built as subject-first commands:
dent8 replay <subject> <predicate> and dent8 explain <subject> <predicate>. They run
over the file dev store and async backends, use the same trusted reload/integrity gates as
the write path, show provenance/authority/freshness/lifecycle information, and share the
same operation code as MCP. verify checks chain integrity, lineage issues, and retraction
taint. The CLI parser is now clap, with generated shell completions and a global
--color auto|always|never presentation flag. The write commands, explain, replay,
facts list, verify, conflicts, eval, init, agent add, authority,
identity <subcommand>, doctor, completions, export, schema postgres, and mcp install
support --output json for scripts/agents; other commands fail closed when
JSON is requested until their structured contract is designed.
Remaining. replay_runs persistence and a richer lineage/debugger view are future
work. (valid_to intervals and --as-of / --valid-at time-travel reads are built —
ADR 0016; the hook exit-code
contract and the witness JSON surface — including NDJSON streaming from serve — are
documented and pinned by tests; MCP is JSON-RPC by construction.)
Crates. clap, clap_complete, serde_json.
Evals Harness — Mostly Built
Section titled “Evals Harness — Mostly Built”Why. Integrity facts are only credible if measured.
Status. Mostly built. The dent8-evals adversarial corpus exists, and proptest suites
cover invariants (a): proptest_invariants.rs
(canonicalization/hash/anchor — idempotency + reload-stability over arbitrary JSON, serde
round-trips, tamper localization, anchor accept/reject) and
proptest_fold.rs (the stateful apply_event
fold vs an independent reference model: accept/reject + reason + lifecycle, terminal
absorption, value immutability, replay determinism, fact isolation). Golden replay
fixtures are built too: golden_replay.rs
freezes named event streams (tests/golden/replay/)
as canonical .events.jsonl + an .expected.json (chain head + replayed-state summary), so
an encoding/hash/fold change is caught as a snapshot mismatch (regenerate with
UPDATE_GOLDEN=1). The file-based scenario-family corpus under
evals/ is seeded too:
evals_corpus.rs freezes whole-stream firewall
outcomes (admitted vs rejected writes, per-fact end-state, read-time freshness, retraction
taint) for beginner_to_senior, ttl_expiry, summary_drift, consistency_required, and
low_authority_injection. Robustness tests cover adversarial deserialization and
panic-freedom over malformed but parseable event streams. cargo-fuzz is built: libFuzzer
targets over the deserialize→fold→canonicalize path (reload stability, hash determinism,
attestation-message independence, fold totality) and CanonicalJson idempotency live in
fuzz/, seeded from the golden fixtures, with a bounded CI smoke (60s/target).
Remaining: a Stateright-style append/projection model.
Invariant. All stated invariants, mechanized — see the property list in formal-verification.md §(a).
Concretely. evals/fixtures and evals/replay are seeded with the families from
evals.md — the supersession scenario (“beginner-in-January → senior-in-November”),
the consistency_required LFI family, the summary_drift retraction taint, ttl_expiry, and
low_authority_injection — each a frozen firewall outcome. The independent-reference-model
stateful fold harness is built in proptest_fold.rs; cargo-fuzz targets over the
deserialize→apply→canonicalize path are built (see above); still open is a model of
append/projection atomicity. Optionally
escalate terminal-immutability and fold-determinism to Kani/bolero (documented as bounded,
not universal).
Crates. proptest and cargo-fuzz + libfuzzer-sys are in use; optionally use
bolero/Kani and a Stateright-style model for append/projection atomicity.
MCP Adapter — V0 Built
Section titled “MCP Adapter — V0 Built”Why late. Pure orchestration over the store — it adds no integrity guarantee, so it
shipped after replay/explain proved the loop. A v0 is built: dent8 mcp serve runs a
synchronous, newline-delimited JSON-RPC 2.0 server over stdio (no async runtime, no new
heavy deps), handling initialize / tools/list / tools/call for the full belief
surface (assert / supersede / retract / contradict / reinforce / expire /
derive / explain / replay), read/audit tools (runtime_status / snapshot /
list_facts / verify / conflicts / native_scan / native_reconcile),
plus resources/list / resources/read (each fact stream as a dent8:// resource),
server instructions for MCP-aware agents, and JSON-RPC batch requests. The tools dispatch to
the shared op_* firewall path, so the same
arbitration applies over MCP as on the CLI (a low-authority write is refused, surfaced as a
tool error).
Role. Enforce the firewall at write time: it already rejects missing-provenance /
sub-floor / non-unique writes (T1) via op_*, across the full belief surface
(assert/supersede/retract/contradict/reinforce/expire/derive/explain/replay),
read/audit tools (runtime_status/snapshot/list_facts/verify/conflicts/native_scan/
native_reconcile),
plus resources/list / resources/read, server instructions, and JSON-RPC batch requests.
The freshness filter on reads (T4) is applied — explain headline-flags a stale fact and
the receipt carries fresh + expires_at.
Still to add: the official rmcp SDK / richer transports.
See interfaces.md.
Crate. v0 is hand-rolled on serde_json (zero new deps); the official Rust MCP SDK
(rmcp) is the upgrade path if richer protocol features (resources, sampling, batch) are
needed.
Dependency summary
Section titled “Dependency summary”DONE: core arbitration + freshness + policy replayDONE: serde canonical form + hash chainDONE: Postgres adapter + AsyncEventStore boundary + SQLite proof backendDONE: replay/explain CLI + full lifecycle + clap/completions/colorsDONE: v0 MCP stdio JSON-RPC surfaceDONE: signed source identity primitive + secure init pathONGOING: evals/formal hardening, mainly fuzzing + append/projection model checkingThe dependency chain that originally blocked the MVP is now complete, and the SDK link has
shipped. The next dependency chain is product hardening: identity operations -> operated
witness -> stable daemon/API contracts (started with snapshot) -> desktop
debugger/control plane and production deployment packaging.
Postgres multi-tenant partitioning ·
ATMS-style assumption-environment replay for the debugger (the core shipped as
dent8 whatif; the interactive debugger view remains) ·
first-class in-process framework adapters — done for the major frameworks: LangChain
(Python, dent8.langchain), LlamaIndex (Python, dent8.llamaindex), the Vercel AI SDK
(dent8/ai), and LangChain.js (dent8/langchain), all native tools over the SDKs, plus a
framework-agnostic dent8/tools (TS) / dent8ToolSpecs for anything else (see
examples/langchain, examples/llamaindex,
examples/vercel-ai-sdk, and
examples/langchain-js) ·
a TypeScript/Tauri desktop debugger/control plane for agents, receipts, native-memory audits,
witness status, and replay timelines ·
adapters for existing memory providers · a managed/hosted witness service (publication
channel, monitoring, key-rotation automation) for non-repudiation — the
published-signed-tree-head primitive itself (witness publish / verify-published, plus
the grant-log --grants lane) already ships.