Getting Started
dent8 is a repo-confined, versioned, authority-ranked shared fact base that your agents
read from and write to instead of hand-editing CLAUDE.md / AGENTS.md. Every fact carries
where it came from and how much authority it has, so a low-authority write can’t silently
overwrite a trusted decision, and nothing goes stale without you seeing it. If your repo has
several agents in flight — Claude Code sessions, CI bots, a teammate’s assistant — this is the
one non-stale source of truth they all share.
Target: first fact in under 2 minutes after dent8 is on PATH (typically under a
second of wall time for init → assert → explain). Timed check:
./examples/on-ramp/demo.sh. The sections below expand install, multi-agent wiring, and hooks.
Every command below was run against the real dent8 v0.8.0 binary; the output blocks are
trimmed but verbatim.
0. Sixty-second path (binary already installed)
Section titled “0. Sixty-second path (binary already installed)”In a git repository:
dent8 init --source source:humanset -a; . .dent8/env; set +adent8 assert repo:myproj deploy_target production --authority high --source source:humandent8 explain repo:myproj deploy_targetdent8 contextinit creates .dent8/ (file log + authority registry with human > CI > agent defaults, here
granting source:human at high), by default provisions a signed source identity (trust root +
issuer key + source key + grant, wired into .dent8/env) so signed above-agent writes work out of
the box, and, by default, wires the enforced PreToolUse native-memory guard into the agent’s
hook config (.claude/settings.json with no --agent, otherwise the selected agent’s hook file)
so raw agent edits to CLAUDE.md/AGENTS.md/… are blocked from the start. Opt out of either with
dent8 init --no-identity / --no-native-memory-guard. Above-agent authority now requires signing
by default (BREAKING): a write claiming --authority medium/high/canonical is rejected unless it
carries a valid signed identity — dent8 init sets this up; without it, use --authority low
(agent tier, still permissive) or configure signing. The wired command fails open when
the binary is absent (command -v dent8 >/dev/null 2>&1 || exit 0; …), so a fresh clone that has
the hook wired but no dent8 on PATH allows the write rather than bricking every edit. Per
write, DENT8_HOOK_ENFORCE=0 softens the guard to advisory and DENT8_ALLOW_NATIVE_MEMORY_WRITE=1
is the sanctioned bypass (the reviewed dent8 export --target path never sets it). You do not
need Postgres or MCP for the first fact, and the signing identity that above-agent writes require is
provisioned automatically by init (no extra setup).
Optional smoke: dent8 doctor --source source:human --write-check. To see the whole
thing — live fact table, integrity receipts, replay timelines, an interactive what-if —
run dent8 ui: a read-only control plane opens in your browser, served straight from
the binary (localhost-only; every payload comes from the same firewall path as the CLI).
1. Install
Section titled “1. Install”The stock binary needs no services — it uses a local file log by default, and concurrent
dent8 writers on that file serialize through the firewall via an exclusive file lock (so
two processes appending at once no longer race). MSRV is Rust 1.94.
Release binaries (recommended, v0.8.0+). The releases page ships prebuilt
archives for five targets, each with a .sha256 sidecar (built with postgres,sqlite):
dent8-v0.8.0-aarch64-apple-darwin.tar.gzdent8-v0.8.0-x86_64-apple-darwin.tar.gzdent8-v0.8.0-aarch64-unknown-linux-gnu.tar.gzdent8-v0.8.0-x86_64-unknown-linux-gnu.tar.gzdent8-v0.8.0-x86_64-pc-windows-msvc.zip
Download, verify, and install one target (Linux x86_64 shown):
BASE=https://github.com/xyzzylabs/dent8/releases/download/v0.8.0curl -LO "$BASE/dent8-v0.8.0-x86_64-unknown-linux-gnu.tar.gz"curl -LO "$BASE/dent8-v0.8.0-x86_64-unknown-linux-gnu.tar.gz.sha256"sha256sum -c dent8-v0.8.0-x86_64-unknown-linux-gnu.tar.gz.sha256tar xzf dent8-v0.8.0-x86_64-unknown-linux-gnu.tar.gzchmod +x dent8 && sudo mv dent8 /usr/local/bin/crates.io. The published CLI crate is dent8-cli (the dent8 crate name is the library
facade):
cargo install dent8-cli --lockeddent8 --versionThe
cargo install dent8-cli --version 0.8.0 --lockedpath was verified in a clean install root as part of cutting v0.8.0 (the built binary reportsdent8 0.8.0); a from-source build takes about 3 minutes. Only the Parquet analytical export (dent8 export <file>.parquet, for DuckDB) is feature-gated — it is not in the release archives and stays acargo install dent8-cli --features export --lockedbuild. Native-memory export (dent8 export --target CLAUDE.md) anddent8 importare stock: they ship in every build, including the release binaries, with no extra feature.
Full details, pinned/feature installs, and platform caveats: Installation.
2. dent8 init
Section titled “2. dent8 init”Run init at your repo root (it wants an enclosing git repo):
$ dent8 init --source source:humaninitialized dent8 in .../.dent8 authority: .../.dent8/authority.json (granted source:human max=high) store: file dev log at .../.dent8/memory.jsonl env: .../.dent8/env identity: .../.dent8/grants/source_human.grant.json (source key: .../.dent8/identities/source_human.key) identity env: .../.dent8/identity-human.env
Next (first fact in under a minute once `dent8` is on PATH): set -a . '.../.dent8/env' . '.../.dent8/identity-human.env' set +a dent8 assert repo:myproj deploy_target production --authority high --source source:human dent8 explain repo:myproj deploy_target dent8 doctor --source source:human --write-check
native-memory guard created (enforced PreToolUse hook): .../.claude/settings.jsonPlain dent8 init (no --source) provisions source:local instead; this walkthrough uses
source:human so the seeded facts match the human > CI > agent model below.
It provisions a .dent8/ directory holding the file dev store (memory.jsonl), the
authority profile (authority.json), the env pointers (env), and a signed source
identity — a trust root (trust.json), a source keypair (identities/), and its grant
(grants/, active-grants.json, grant-log.jsonl) wired into .dent8/env so above-agent
writes can be signed. It also installs the native-memory guard, a PreToolUse hook in
.claude/settings.json:
$ ls .dent8active-grants.json authority.json env grant-log.jsonl grants/identities/ identity-human.env memory.jsonl trust.json.dent8/env holds the pointers the CLI reads — the store and authority ceiling (DENT8_LOG,
DENT8_AUTHORITY, DENT8_REQUIRE_AUTHORITY=1) plus the signed-identity vars dent8 init now
provisions by default (DENT8_REQUIRE_IDENTITY=1, DENT8_TRUST, DENT8_ACTIVE_GRANTS,
DENT8_GRANT, DENT8_IDENTITY_KEY), so sourcing it makes this shell’s above-agent writes
signed. Load it once per shell:
set -a; . .dent8/env; set +aSince PR #12, repo-confined discovery resolves the store and authority registry without
sourcing anything (running any command from inside the repo finds .dent8/). Sourcing still
matters for the enforcement switch: DENT8_REQUIRE_AUTHORITY=1 lives in .dent8/env, so
load it when you want deny-by-default authority in the current shell.
init auto-seeds the authority profile. As of PR #12 you no longer run a follow-up
command — init writes the human > CI > agent ranking straight into authority.json
(here --source source:human grants the human source at high; plain dent8 init would add a
separate source:local at high instead):
$ dent8 authority listsource:agent max=lowsource:ci max=mediumsource:human max=highStore discovery is repo-confined. dent8 finds the nearest ancestor holding a .git, then
scans from your cwd up to the repo root for the first .dent8/ — never above the repo root,
and never above $HOME. If you’re not inside a git repo, only ./.dent8/ in the cwd is
considered. So dent8 context run from a subdirectory resolves the project store instead of
minting a parallel one, and a .dent8/ planted in an unrelated ancestor (e.g. /tmp) is
never silently adopted. Explicit DENT8_LOG / DENT8_STORE_URL / DENT8_AUTHORITY env
overrides bypass discovery entirely.
3. Seed real facts
Section titled “3. Seed real facts”There are three ways to get facts into the base. The walkthrough writes as the human > CI >
agent sources: init --source source:human already provisioned (and . .dent8/env loaded)
the human signing identity; add the CI source’s identity too, so its medium writes are signed
(the issuer key is the one init created, default ~/.config/dent8/issuer.key; agents write at
the low tier and need none):
dent8 identity agent-keygen source:ci --out .dent8/identities/source_ci.keydent8 identity grant-issue source:ci --public-key .dent8/identities/source_ci.key.pub \ --max medium --issuer owner --issuer-key ~/.config/dent8/issuer.key \ --out .dent8/grants/source_ci.grant.jsondent8 identity repair-env --source source:ci(a) By hand, with assert. Give each fact a subject (<kind>:<key>), a predicate, a
value, and an authority + source. These are signed as source:human, the identity this shell
loaded — v0.8.0 rejects an above-agent write without one. --ttl accepts human durations
(90d, 12h, 30m):
$ dent8 assert repo:dent8 msrv "1.94" --authority high --source source:human --ttl 90dACCEPTED repo:dent8 msrv = "1.94" (authority=high) seq=0 hash=c659103db121…
$ dent8 assert repo:dent8 build_command "cargo build --release" --authority high --source source:humanACCEPTED repo:dent8 build_command = "cargo build --release" (authority=high) seq=1 hash=7e0edc1225ba…
$ dent8 assert repo:dent8 commit.attribution "no Co-Authored-By trailers and no AI attribution" --authority high --source source:humanACCEPTED repo:dent8 commit.attribution = "no Co-Authored-By trailers and no AI attribution" (authority=high) seq=2 hash=062e40d99d4a…The firewall in action — a low-authority write cannot overwrite the high-authority MSRV fact
(this exits 1):
$ dent8 supersede repo:dent8 msrv "1.90" --authority low --source source:humanREJECTED: firewall rejected the write: insufficient authority: low may not override or remove an incumbent of high the incumbent recorded the survived challenge (fact.challenge_rejected)(b) In bulk, from a proposals file, with capture. Write one JSON proposal per line
(authority / source are optional). When a signed grant is active (the default), an
unattributed line inherits that grant’s source and max authority; captured without a
signing grant — as an agent’s own SessionEnd hook runs — it lands at source:agent @ low.
An agent queues proposals it can’t sign at human authority, so drain them unsigned:
$ ( unset DENT8_GRANT DENT8_IDENTITY_KEY DENT8_REQUIRE_IDENTITY DENT8_TRUST DENT8_ACTIVE_GRANTS echo '{"subject": "repo:dent8", "predicate": "lint_gate", "value": "cargo clippy --workspace --all-targets -- -D warnings"}' \ > .dent8/proposals.jsonl dent8 capture .dent8/proposals.jsonl --consume --keep-failed )line 1: ACCEPTED repo:dent8 lint_gate = "cargo clippy --workspace --all-targets -- -D warnings" (authority=low)captured 1 proposal(s): 1 accepted, 0 contested, 0 rejected, 0 invalidconsumed .dent8/proposals.jsonl--consume truncates the queue after processing; --keep-failed (requires --consume)
writes rejected or malformed lines back for retry. This is exactly the shape of the
SessionEnd hook (§5).
(c) From an existing CLAUDE.md, with import. dent8 import <file> ingests durable
facts from a CLAUDE.md / AGENTS.md / markdown file through the firewall — every
recovered fact runs the same authority / policy / content-check path as assert and
capture, so nothing is smuggled in. It reads three deterministic shapes and skips
everything else (free prose is never turned into a fact): a dent8 managed block (what
export --target writes), inline dent8://<kind>/<key>/<predicate> = <value> receipt markers
in prose, and fenced ```dent8 blocks of JSON capture proposals. Use --dry-run to see
what it would propose without writing:
$ dent8 import CLAUDE.md --dry-runline 5 [inline-marker]: would assert repo:dent8 build_tool = "cargo"dry run over CLAUDE.md: 1 proposal(s) would be imported, 0 malformed, 5 line(s) skipped (nothing written)To preview which native memory files are present first — a read-only inventory, not an ingest
— use the audit; import is what actually pulls the facts in:
$ dent8 native scan --agent claude-codedent8 native scan agent: claude-code root: .../demo guard: missing (no native-memory guard found at .../.claude/settings.json) files: 1 native memory/rules file(s), 0 with dent8 receipt markers - CLAUDE.md (claude_memory, 26 bytes, sha256=2b65fa708f01, receipt=no)The reverse direction — writing the believed facts back into a CLAUDE.md / AGENTS.md
managed block with dent8 export --target — is covered in
native-memory.md. Plain markdown bullets that carry no receipt marker are
still skipped by import; translate those into an assert or a capture proposal as in (a)
and (b).
4. Wire your agents
Section titled “4. Wire your agents”Every adapter reduces to two moves — context in (inject the believed facts before the model
runs) and capture out (flush proposed facts through the firewall after) — plus, where the
tool speaks it, the MCP server for live tool-mediated access. The matrix below maps common
tools to their adapter. The dent8 side of every bundled profile is verified in this repo:
the sample MCP configs (Claude Code, Cursor, grok-build, Gemini, Cascade, hecate) are validated
against the real server contract in tests, and the release-acceptance script initializes the
Codex profile and runs doctor --all-agents --write-check — a real signed write through every
bundled profile’s generated config. On top of that, dent8’s own development dogfoods several
rows at once: Claude Code and Grok Build run the full hook loop (SessionStart →
dent8 context, SessionEnd → dent8 capture — Claude’s wiring is tracked in
.claude/settings.json; Grok’s uses the same Claude-compatible
events from its machine-local .grok/), and Codex and Cursor work through the tracked
AGENTS.md contract (the fact base is authoritative for every agent) — all
four via machine-local MCP configs with per-agent signed identities, generated by
dent8 agent add and gitignored by design since they name identity paths. What is not
exercised here is each vendor’s half — whether their hook/rules engine fires as their docs
describe — so treat that side as documented per vendor.
| Agent / framework | Context in | Capture out | MCP | Adapter |
|---|---|---|---|---|
| Claude Code (dogfooded) | SessionStart → dent8 context |
SessionEnd → dent8 capture |
yes | .claude/settings.json, examples/agent-hooks/claude-code/ |
| Cursor (dogfooded) | .cursor/rules/*.mdc block (or AGENTS.md) |
stop hook → dent8 capture |
yes | examples/agent-hooks/cursor/ |
| Codex CLI (dogfooded) | AGENTS.md block |
notify wrapper (coarse) |
mcp_servers TOML |
examples/codex/, mcp-clients |
| Grok Build (dogfooded) | SessionStart hook → dent8 context |
SessionEnd hook → dent8 capture |
.grok/config.toml |
examples/grok-build/, agent-adapters |
| Windsurf / Cline / Zed | AGENTS.md or native rules block |
manual / wrapper | yes | examples/agent-hooks/generic/, mcp-clients |
| aider | AGENTS.md / --read file |
wrapper → dent8 capture |
no | examples/agent-hooks/generic/ |
| Any MCP client | (via MCP tools) | (via MCP tools) | yes | docs/mcp-clients.md |
| Any shell framework | pre-session.sh (dent8 context) |
post-session.sh (dent8 capture) |
— | examples/agent-hooks/generic/ |
The sub-sections below detail the load-bearing patterns — Claude Code hooks (a), the
universal dent8 context pipe (b), CI capture (c), and the MCP server (d).
(a) Claude Code hooks. dent8 init already writes the enforced PreToolUse native-memory
guard into .claude/settings.json for you (unless you passed --no-native-memory-guard); this
section shows the fuller loop you can layer on top. This repo ships its own wiring in
.claude/settings.json. The two load-bearing hooks are
SessionStart (inject the believed facts via dent8 context) and SessionEnd (flush
agent-queued proposals via dent8 capture). The full, hardened block — it guards on
command -v dent8 and sources .dent8/env before every call — is:
{ "hooks": { "SessionStart": [ { "matcher": "startup|resume", "hooks": [ { "type": "command", "command": "command -v dent8 >/dev/null 2>&1 || exit 0; if [ -f .dent8/env ]; then set -a; . .dent8/env; set +a; fi; DENT8_HOOK_MODE=session-start dent8 hook native-memory-guard", "timeout": 30 }, { "type": "command", "command": "command -v dent8 >/dev/null 2>&1 || exit 0; if [ -f .dent8/env ]; then set -a; . .dent8/env; set +a; fi; dent8 context", "timeout": 30 } ] } ], "PreToolUse": [ { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "command -v dent8 >/dev/null 2>&1 || exit 0; if [ -f .dent8/env ]; then set -a; . .dent8/env; set +a; fi; DENT8_HOOK_MODE=guard-native-memory-write DENT8_HOOK_ENFORCE=1 dent8 hook native-memory-guard", "timeout": 30 } ] } ], "PostToolUse": [ { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "command -v dent8 >/dev/null 2>&1 || exit 0; if [ -f .dent8/env ]; then set -a; . .dent8/env; set +a; fi; DENT8_HOOK_MODE=post-write-audit dent8 hook native-memory-guard", "timeout": 30 } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "command -v dent8 >/dev/null 2>&1 || exit 0; if [ -f .dent8/env ]; then set -a; . .dent8/env; set +a; fi; DENT8_HOOK_MODE=session-start dent8 hook native-memory-guard", "timeout": 30 } ] } ], "SessionEnd": [ { "hooks": [ { "type": "command", "command": "command -v dent8 >/dev/null 2>&1 || exit 0; if [ -f .dent8/env ]; then set -a; . .dent8/env; set +a; fi; dent8 capture .dent8/proposals.jsonl --consume --keep-failed", "timeout": 60 } ] } ] }}A teaching-clean minimal version (same hook events, no defensive guards) lives at
examples/agent-hooks/claude-code/settings.sample.json;
see Context & Capture for the details.
(b) Any other framework — pipe dent8 context. dent8 context emits a markdown pack
(each line stamped with authority, source, and a dent8:// receipt) that you inject into any
agent’s system context:
$ dent8 context## Project facts (dent8)
<!-- generated by `dent8 context` at 1783560209036; regenerate instead of hand-editing -->
Currently-believed facts from the dent8 memory firewall. Each carries its authority and source; verify one with `dent8 explain <subject> <predicate>`.
### repo:dent8
- `build_command` = "cargo build --release" (authority: high, source: source:human, ref: dent8://repo/dent8/build_command)- `commit.attribution` = "no Co-Authored-By trailers and no AI attribution" (authority: high, source: source:human, ref: dent8://repo/dent8/commit.attribution)- `lint_gate` = "cargo clippy --workspace --all-targets -- -D warnings" (authority: low, source: source:agent, ref: dent8://repo/dent8/lint_gate)- `msrv` = "1.94" (authority: high, source: source:human, ref: dent8://repo/dent8/msrv)- `test_command` = "cargo test --workspace" (authority: medium, source: source:ci, ref: dent8://repo/dent8/test_command)Use --output json for machine consumption.
(c) Capture facts from CI. Let CI assert facts at its own (capped) medium authority —
source:ci cannot mint high, so it can never overwrite a human decision:
name: publish factson: { push: { branches: [main] } }jobs: facts: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: cargo install dent8-cli --locked - name: record test command as a CI-sourced fact env: DENT8_CI_KEY: ${{ secrets.DENT8_CI_KEY }} # source:ci private signing key, a CI secret run: | set -a; . .dent8/env; set +a # The committed .dent8/ carries source:ci's grant + trust; its private key is # gitignored, so materialize it from the CI secret and point the identity at # source:ci — a medium write above the agent tier must be signed (see # docs/team-identity.md). source:ci is capped at medium, so it can never mint high. umask 077; printf '%s' "$DENT8_CI_KEY" > .dent8/identities/source_ci.key export DENT8_GRANT=.dent8/grants/source_ci.grant.json export DENT8_IDENTITY_KEY=.dent8/identities/source_ci.key dent8 assert repo:dent8 test_command "cargo test --workspace" \ --authority medium --source source:ci(d) MCP — live tool-mediated access. For any MCP-capable client, dent8 mcp serve exposes
the belief surface over JSON-RPC 2.0 stdio (17 tools; the 7 write tools go through the same
firewall as the CLI). Reading a fact via resources/read also records a fact.retrieved
audit event by default (opt out with DENT8_MCP_RECORD_RETRIEVAL=0) — so MCP retrieval is
replayable like dent8 context --record-retrieval. The canonical mcpServers block:
{ "mcpServers": { "dent8": { "command": "dent8", "args": ["mcp", "serve"], "env": {} } }}Zed uses context_servers instead of mcpServers, and Codex uses an mcp_servers TOML table —
see Connect any MCP client for the verified stdio handshake and per-client
configs, and examples/mcp/ for the belief model and env-var reference. For
a framework with no MCP client and no native hooks, the provider-neutral scripts in
examples/agent-hooks/generic/ provide the same context-in
/ capture-out loop plus an idempotent AGENTS.md writer.
5. Day-2 operations
Section titled “5. Day-2 operations”verify re-checks integrity, supersession lineage, and retraction taint (exit 0 when
healthy):
$ dent8 verifyOK: 9 event(s) across 6 subject(s) — STRUCTURAL integrity holds (uniqueness + lineage intact, no retraction taint or content-check flags, all events canonicalize). This does NOT detect a content edit to *unattested* events: the file dev store keeps no stored hash to compare against — use `dent8 witness verify` (or the Postgres backend) for tamper-detection.explain <subject> <predicate> gives the full receipt — note survived : 1 challenge(s)
from the rejected supersede above, and expires_at from the 90d TTL:
$ dent8 explain repo:dent8 msrvexplain repo:dent8 msrv value : "1.94" lifecycle : Active authority : High fresh : true expires_at : 1791336199745 evidence : 1 corroboration : 1 survived : 1 challenge(s) chain verified: truedoctor --write-check smoke-tests the whole setup end-to-end (exit 0; the WARN line is
expected on a no-witness file store — init provisions the signed identity, so those checks
pass):
$ dent8 doctor --source source:human --write-checkdent8 doctor OK binary: .../dent8 OK file dev store: .../.dent8/memory.jsonl (0 event(s)) OK authority: .../.dent8/authority.json (3 source(s); source:human max=high) OK identity trust: .../.dent8/trust.json (1 issuer(s)) OK identity grant: .../.dent8/grants/source_human.grant.json (source=source:human max=high issuer=owner scope=*) OK identity active grant: .../.dent8/active-grants.json (current for source:human) OK identity source: grant source matches doctor source source:human OK identity key: .../.dent8/identities/source_human.key (matches grant public key) WARN witness: not configured (optional; set DENT8_WITNESS_LOG + DENT8_WITNESS_PUBKEY for signed tree heads) OK verify: OK: 0 event(s) ... STRUCTURAL integrity holds ... OK mcp: `dent8 mcp serve` is available over stdio SKIP daemon: DENT8_DAEMON_SOCKET not set (CLI writes go to the local store) OK write-check: accepted trusted diagnostic:doctor-… dent8.write_check=ok at high, rejected below-ceiling tampered value, verify OK, probe retractedTaint. Derive a fact from another, then retract the basis — verify flags the derivative
and exits 1:
$ dent8 derive service:api min_toolchain "1.94" --basis repo:dent8 msrv --authority high --source source:humanACCEPTED service:api min_toolchain = "1.94" (authority=high, derived from repo:dent8 msrv)
$ dent8 retract repo:dent8 msrv --authority high --source source:humanACCEPTED retracted 1 believed fact of repo:dent8 msrv (authority=high)
$ dent8 verifyINTEGRITY ISSUES (1 found): TAINTED: fact:service:api:min_toolchain:9 derives from fact:repo:dent8:msrv:3 (now Retracted)Contested. contradict keeps both values as a live dispute (dent8 never silently picks
a winner); context flags it inline:
$ ( set -a; . .dent8/identity-ci.env; set +a dent8 contradict repo:dent8 test_command "cargo nextest run" --authority medium --source source:ci )CONTESTED repo:dent8 test_command: "cargo test --workspace" (incumbent) vs "cargo nextest run" (authority=medium) both are now believed; resolve with `supersede` (install a winner) or `retract`.
$ dent8 context --kind repo- `test_command` = "cargo test --workspace" **[contested — 1 rival value(s); check `dent8 conflicts` before relying on this]** (authority: medium, source: source:ci, ref: dent8://repo/dent8/test_command)Stale. context omits stale facts and counts them in a trailer; --include-stale
annotates them; explain shows fresh : false:
$ dent8 context --kind repo --key dent8... (fresh facts) ..._1 believed fact(s) omitted (1 stale, 0 not yet valid) — pass `--include-stale` to show them._
$ dent8 context --kind repo --key dent8 --include-stale- `nightly_snapshot` = "2026-01-01" **[stale — past its validity window]** (authority: medium, source: source:ci, ref: dent8://repo/dent8/nightly_snapshot)Content-check hook. dent8’s arbitration governs authority, provenance, and lifecycle — it
never reads a fact’s value text. To screen content (injected imperatives, exfil
strings), set DENT8_CONTENT_CHECK to an external scanner command; dent8 runs it on every
value-carrying write, fail-closed by default, before the write is arbitrated. dent8 ships no
classifier — the hook is the seam where you wire LLM Guard / Rebuff / Lakera. A demo scanner
(illustrative only, not a defense) lives at
examples/scanners/demo-content-check.sh; full
docs in content-check.md.
What dent8 does not do
Section titled “What dent8 does not do”
- It doesn’t inspect fact content. Arbitration is about authority and provenance, not the meaning of the value. Screening injected/obfuscated payloads requires a real scanner behind the content-check hook — dent8 provides the seam, not the classifier (content-check.md, threat-model.md).
Ttl::Neveris uncapped. A fact asserted with no TTL (on a predicate with no default) never expires. Use non-expiring facts sparingly and prefer an explicit--ttl.dent8 evalis a 5-scenario demo, not the eval tally. The CLI’sdent8 evalruns a 5-scenario firewall-vs-recency-only demonstration and prints “5/5 scenarios.” The headline 16 blocked / 4 detect-only / 27 out-of-model figure is a different artifact — the frozen 47-case adversarial corpus documented in evals.md, which lives in the test suite, not the CLI. Don’t conflate the two.