dent8-core 0.3.2

Core fact-event model and invariants for dent8.
Documentation

dent8

A memory firewall for coding agents. dent8 sits between your agent and its long-term memory and refuses the writes that quietly corrupt it — a low-authority source overwriting a trusted fact, a stale value resurrecting itself, a poisoned source tainting everything derived from it. Every fact it keeps carries where it came from, and you can replay exactly why the agent believes it.

dent8 firewall walkthrough: a trusted fact is asserted, a low-authority override is rejected by the firewall, and explain replays the auditable receipt over a verified hash chain.

Most agent memory is newest-write-wins: the last thing written becomes the truth. That's how a scraped web page silently overwrites a decision your team made, and how a retracted source leaves its conclusions behind. dent8 treats memory as an append-only log of fact events — each carrying provenance, authority, and evidence — and arbitrates every write against what is already believed.

The 30-second proof

cargo install dent8 --locked
dent8 eval

dent8 eval runs an adversarial corpus against the real firewall and a recency-only baseline (newest-write-wins — the resolution Zep/Graphiti use):

attack firewall recency-only baseline
low-authority memory injection (MINJA) blocked ✓ compromised
authority laundering blocked ✓ compromised
canonical contradiction blocked ✓ compromised
Sybil corroboration blocked ✓ compromised
poisoned-source retraction blocked ✓ compromised

Five for five. The last one is the tell: retract a poisoned source and dent8 flags every fact derived from it — a dependency cascade a recency-only store structurally cannot express.

Try it

dent8 init --identity --source source:alice # local setup: env + authority + signed identity
set -a; . .dent8/env; set +a
. .dent8/identity-alice.env
dent8 authority add web:scrape low       # let this source write at Low, so the next rejection
                                         # is about arbitration, not a missing grant

# A trusted fact goes in.
dent8 assert repo:myproj deploy_target production

# A low-authority source tries to overwrite it — the firewall rejects it: Low can't override High.
dent8 supersede repo:myproj deploy_target staging --authority low --source web:scrape

# It is still production, and here is the receipt that proves why.
dent8 explain repo:myproj deploy_target

# Derive a fact from it, then retract the source — the derivative is flagged tainted.
dent8 derive service:api target production --basis repo:myproj deploy_target
dent8 retract repo:myproj deploy_target
dent8 verify

No services required — dent8 uses a local file log by default. For binaries, pinned installs, and feature builds, see Installation. From a clone, watch the whole firewall path run through the real CLI: DENT8="cargo run -q -p dent8 --" ./examples/firewall/demo.sh.

How it works

The primitive is a fact event, not a generic memory item. Every write that enters dent8 is arbitrated at the append boundary (EventStore::append) before it is persisted:

  • Authority-weighted arbitration — a write cannot override a fact of higher authority, and dent8 checks the actual authority behind a revision, not just the authority claimed by the event, so laundering a weak fact through a high-authority-looking event is caught.
  • Paraconsistent contradiction — disagreement is kept as a contested pair rather than silently resolved; but contradicting a canonical fact is a hard alarm, not a soft contest.
  • Earned entrenchment — a fact backed by more independent sources, or one that has survived challenges (rejected attacks are recorded on the fact itself), becomes harder to displace.
  • Freshness & valid-time — facts carry TTLs and asserted validity windows; reads flag stale and not-yet-valid facts, and can time-travel ("what did we believe last Tuesday, and was it fresh then?").
  • Tamper-evidence — a SHA-256 hash chain over the log, plus an optional off-host witness (Ed25519 signed tree heads) that catches a history rewrite an internal re-check cannot.
  • Signed identity — optional issuer-signed grants bind a source to a key; every accepted write carries a signature verify re-checks offline, backed by a hash-chained grant history with first-class revocation.

Nothing is a black box: dent8 replay shows the full event history behind any fact, and dent8 verify re-checks integrity, supersession lineage, and retraction taint.

Use it with your agent

dent8 speaks MCP, so agents read and write memory through the firewall:

dent8 init --agent codex --install-mcp     # signed identity + MCP config for Codex
dent8 doctor --agent codex --write-check   # smoke the installed server + prove the firewall path
dent8 doctor --all-agents --write-check    # check every installed agent profile in this bundle

Shortcuts exist for codex, claude-code, cursor, gemini, grok-build, cascade, and hecate. Several agents can share one belief base by using one globally installed dent8 binary and one shared DENT8_STORE_URL, while each profile keeps its own signed source identity:

dent8 init --agent codex --store sqlite --install-mcp
dent8 agent add --agent claude-code
dent8 agent add --agent cursor
dent8 doctor --all-agents --write-check

See examples/mcp/ and the per-agent example directories, or wire dent8 in over MCP from LangChain / the Vercel AI SDK.

Share one belief base over a daemon

Instead of one dent8 process per agent, run a per-user daemon and point writes at it:

set -a
. .dent8/env
. .dent8/identity-codex.env
set +a
dent8 daemon serve                       # foreground; default per-user Unix socket

In another shell with the same env loaded:

export DENT8_DAEMON_SOCKET="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/dent8/dent8.sock"
dent8 daemon status                      # check reachability and write authentication
dent8 assert repo:app deploy_target production

For a stdio-only MCP client that should use the same daemon, configure it to run:

dent8 mcp proxy

The installer can write that proxy command into known agent configs:

dent8 mcp install --agent codex --use-daemon
# or pin a non-default socket:
dent8 mcp install --agent codex --daemon-socket /path/to/dent8.sock

The proxy authenticates to the daemon once, then forwards the client's MCP frames over that connection.

Every connection proves the daemon-configured source identity with a signed session challenge, and the daemon arbitrates and attests each write as that source — so a daemon-written fact re-verifies offline exactly like a local one, and many processes build one firewalled belief base over one transport. Reads stay local. Run the whole path with DENT8="cargo run -q -p dent8 --" ./examples/daemon/demo.sh (see examples/daemon/). Today each daemon process is single-source: every client connection must prove the same source key the daemon holds, so this shares one identity across processes. Separate agent identities should use separate MCP subprocesses against the same backend, or separate daemon instances.

Status

dent8 is pre-1.0 and experimental — the CLI, the library API, the on-disk event format, and the Postgres storage schema may all still change between minor versions. The event format is versioned by CANON_VERSION, mixed into every hash so encodings can never collide. v0.3 introduces format v2 (the fact vocabulary — claim_idfact_id, lowercase authority); this is a deliberate one-time pre-1.0 break, so a v1 log does not carry forward and must be re-ingested from source. See the v0.3 upgrade note. From v2 onward the intent is again additive-only (new fields stay optional and out of the hash), but that stability is not guaranteed until 1.0. docs/STATUS.md is the single source of truth for what is runnable vs. library-only vs. design-only. In brief, runnable today:

  • The full belief lifecycle — assert / supersede / retract / contradict / reinforce / expire / derive / explain / replay — plus the operator surfaces facts list, verify, conflicts, eval, and export.
  • Three backends behind one contract: a local file dev log (default), embedded SQLite, and a DB-verified transactional Postgres adapter (--features postgres) — selected by DENT8_STORE_URL.
  • Signed identity with grant history + revocation, the witness transparency log, and an MCP server (dent8 mcp serve) — all in the stock binary.
  • MCP runtime_status diagnostics so agents can see the live binary, store, identity, authority, and witness configuration before trusting a long-running server.
  • Machine-readable --output json across the read/write/audit surface, shell completions, and Parquet export for offline DuckDB analysis (--features export).
  • Read-only native memory/rules audit with dent8 native scan --agent <profile> and receipt verification with dent8 native reconcile --agent <profile>; MCP exposes the same audits as native_scan / native_reconcile. Native import/export remain future work.

Run dent8 --help for the full command surface. The stock binary needs no services; opt-in builds add a Postgres backend (--features postgres) and Parquet export (--features export). The future desktop app is scoped as a debugger/control plane over these same surfaces, not a separate memory provider (ADR 0020).

(Origin: the dentate gyrus*, the hippocampal structure associated with pattern separation — keeping similar memories distinct.)*

Documentation

Start here

Design

Correctness & security

Planning & research

Development

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
DENT8="cargo run -q -p dent8 --" ./examples/firewall/demo.sh

# The Postgres adapter's integration tests are gated on DATABASE_URL (they skip without one):
docker compose up -d
DATABASE_URL=postgres://postgres:dent8@localhost:5432/dent8 \
  cargo test -p dent8-store-postgres --features adapter
docker compose down

CI (.github/workflows/ci.yml) runs the fmt/clippy/test gate across feature combinations and the adapter against a live Postgres service. Security reports: see SECURITY.md.

License

Licensed under either of Apache-2.0 or MIT at your option. Unless you state otherwise, any contribution you intentionally submit for inclusion in the work, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms.