Interfaces
dent8 should expose multiple interfaces over the same core model. Interfaces must not invent separate memory semantics.
The CLI is the first operator and developer surface.
Initial command groups:
dent8 schema postgresdent8 assert <subject> <predicate> <value> [--authority <level>] [--source <source>] [--valid-from <time>] [--valid-to <time>] [--ttl <duration>]dent8 reinforce <subject> <predicate> [--authority <level>] [--source <source>]dent8 contradict <subject> <predicate> <opposing-value> [--authority <level>] [--source <source>] [--valid-from <time>] [--valid-to <time>] [--ttl <duration>]dent8 supersede <subject> <predicate> <new-value> [--authority <level>] [--source <source>] [--valid-from <time>] [--valid-to <time>] [--ttl <duration>]dent8 expire <subject> <predicate> [--authority <level>] [--source <source>]dent8 retract <subject> <predicate> [--authority <level>] [--source <source>]dent8 derive <subject> <predicate> <value> --basis <subject> <predicate> [--authority <level>] [--source <source>] [--valid-from <time>] [--valid-to <time>] [--ttl <duration>]dent8 replay <subject> <predicate> [--as-of <time>] [--valid-at <time>]dent8 whatif <subject> <predicate> [--distrust <source>]... [--authority-floor <level>] [--confidence-floor <millis>]dent8 explain <subject> <predicate> [--as-of <time>] [--valid-at <time>]dent8 snapshot [--include-diagnostics]dent8 conflictsdent8 completions <bash|elvish|fish|powershell|zsh>dent8 mcp serve
<subject> is written as <kind>:<key>, for example person:alice or repo:dent8.
Authority and source are provenance metadata, not part of the fact’s
subject/predicate/value. They can be passed explicitly or defaulted from the active signed
source grant.
--ttl takes a human duration (ms/s/m/h/d suffixes, e.g. 90d, 12h) and sets the
fact’s retention freshness. It is bounded by the predicate’s retention ceiling — a --ttl
beyond the effective ceiling (a per-predicate override, else the 90-day global default) is
rejected, not clamped. Omitting it leaves the predicate’s default TTL (or non-expiring).
Every <time> flag (--valid-from/--valid-to, --as-of/--valid-at, --expires-at)
accepts raw unix milliseconds (the machine form — what the MCP tools take), now, a
±duration offset from now (-7d, +12h), RFC 3339 with an offset
(2026-07-11T12:00:00Z), or a bare UTC date/datetime (2026-07-11, 2026-07-11T12:00).
Bare forms are UTC, not local time, so the same command names the same instant on every
machine.
The CLI should show integrity metadata by default: lifecycle, freshness (TTL and asserted
valid_to), authority, evidence count, contradiction count, survived-challenge count,
supersession lineage, and replay position. Reads accept --as-of (fold the log as of a
transaction-time instant) and --valid-at (evaluate freshness/validity at a valid-time
instant) — ADR 0016.
Human-facing output supports --color auto|always|never; structured adapter surfaces
should keep using plain data fields rather than ANSI formatting.
dent8 whatif is policy-counterfactual replay: it re-folds the same immutable log under
a swapped epistemic trust policy (--distrust <source>, --authority-floor,
--confidence-floor — at least one required) and reports the believed set under the real
fold vs the counterfactual, plus a per-fact structural diff. Read-only and deterministic
(replay_subject_with_policy + diff_states in dent8-store); freshness is deliberately
not a policy knob.
MCP is an adapter, not the product boundary.
The Model Context Protocol lets servers expose tools that language models can call. Tool definitions include names, descriptions, input schemas, optional output schemas, and structured or unstructured results. The spec also calls out human-in-the-loop and security expectations for tool invocation.
Source: MCP tools specification
Current v0 MCP tools:
runtime_statussnapshotlist_factsverifyconflictsnative_scannative_reconcileassertsupersederetractcontradictreinforceexpirederiveexplainreplaywhatif
runtime_status is read-only and reports the live server binary, cwd, selected store
URL/path, event count, authority registry, signed identity, and witness configuration.
It exists so agents can detect stale MCP subprocesses or wrong stores before relying on
project memory.
snapshot is the stable read/audit aggregate for debugger and control-plane clients. It
combines runtime_status, fact-stream browsing, verify, and conflicts into one
structured payload with summary counts. Use it for polling or status panes; use the
individual tools when a client needs a narrower result or lower-cost refresh.
Tool definitions advertise outputSchema for every structuredContent shape. Tool results
keep human-readable content, and also return MCP 2025-11-25 structuredContent for
agents. initialize prefers 2025-11-25 and also accepts 2025-06-18 clients because
dent8’s v0 tool result shape is valid on both revisions. The structured payloads carry a
stable status (accepted, rejected, contested, ok, invalid, failed, or
integrity_issues; runtime/snapshot probes may also report degraded). Writes include an
accepted_events array with every committed event’s id/kind/hash, plus a current-state
receipt (receipt_kind: "current_state") when the subject still resolves to an explainable
fact. Refused firewall writes carry
rejection_reason; malformed calls carry error_reason with status: "invalid". For
older clients that ignore structuredContent, dent8 also includes a serialized JSON mirror
as a second text content block.
Every error payload — MCP tool errors and the CLI’s --output json alike — also carries a
stable kebab-case code naming the cause, classified from the typed firewall error
at the point the message is written, so an agent branches on the token instead of parsing
prose. Where status says what happened (rejected), code says why:
insufficient-authority, canonical-contradiction, terminal-fact,
laundered-authority, unbacked-supersession, below-authority-floor,
uniqueness-violation, ttl-ceiling-exceeded, authority-ceiling, scope-violation,
identity-rejected, unauthenticated-write, weaker-entrenchment, content-rejected,
write-conflict, commit-failed, and integrity/IO causes (corrupt-event,
replay-failed, canonicalization-failed, store-unavailable), with generic fallbacks
(rejected, invalid-argument, operation-failed, unknown-tool) when no finer cause is
known. The MCP outputSchema advertises the closed enum of codes this build can emit.
Recommended behavior:
- Treat writes as candidate events through the firewall.
- Call
snapshotfirst for a complete read/audit view, orruntime_statuswhen debugging just the live server/store wiring before trusting a long-running MCP server. - Carry evidence/provenance fields for assertions; signed identity may provide source and authority defaults, but explicit fields must still satisfy the same grant/ceiling checks.
- Make stale, contested, expired, or superseded facts visible to clients.
- Put the core usage workflow in MCP server instructions so Codex, Claude Code, Gemini CLI, Devin/Cascade, Cursor, Grok Build, Hecate, and other MCP-aware agent hosts know to inspect dent8 before relying on durable project facts.
- Keep tool output schemas synchronized with
structuredContent.
Client setup examples live under examples/mcp/:
Codex, Claude Code,
Gemini CLI, Devin/Cascade,
Cursor, Grok Build, and
Hecate. Framework examples live under
examples/langchain/ and
examples/vercel-ai-sdk/. These are integration profiles, not
separate memory semantics; every write still enters through the shared firewall path.
Transport status: v0 supports stdio plus a local Unix-socket daemon. dent8 mcp install
writes configs that launch the globally installed dent8 binary (command = "dent8" by
default, overrideable with --command) and, by default, pass ["mcp", "serve"]. Several
agents can share one belief base either by pointing separate stdio server subprocesses at the
same backend and registries, while keeping distinct grant/key env values for provenance, or by
connecting to one local daemon that requires the session-challenge handshake before writes.
dent8 mcp proxy is the stdio bridge for clients that cannot speak Unix sockets directly: it
authenticates to the daemon once, then forwards MCP frames over that connection. The installer
can write proxy mode with --use-daemon, or --daemon-socket PATH for
["mcp", "proxy", "--socket", PATH]. The daemon supports authenticated writes, but each daemon
process is still single-source: use separate stdio subprocesses or separate daemon instances
when per-agent provenance matters. A remote HTTP/streamable transport remains design-only
today.
Optional native-memory guard profiles live under
examples/agent-hooks/ and call dent8 hook native-memory-guard.
These hooks are not an alternate write path; they run dent8 verify and block direct edits
to provider-native memory/rules files that would bypass the fact-event firewall.
dent8 native scan --agent <profile> is the read-only audit counterpart: it inventories
known native files/rules, hashes them, flags dent8 receipt markers, and reports guard posture.
dent8 native reconcile --agent <profile> goes one step deeper for explicit
dent8://<kind>/<key>/<predicate> references: it resolves each through the same receipt
path as explain and fails on stale, contested, no-longer-believed, missing, or malformed
references. It still does not import prose or write native files.
The MCP server exposes the same read-only audits as native_scan and native_reconcile
with the same agent profiles and optional dir / root / time-travel arguments, so an
agent can inspect bypass-prone native memory before trusting it.
The adapter design is tracked in
agent-adapters.md.
MCP Resources
Section titled “MCP Resources”MCP resources provide context identified by URI. dent8 exposes one resource per fact
stream at dent8://{kind}/{key}/{predicate} (segments percent-encoded):
resources/listenumerates every stream in the log, with its freshness marked;resources/readreturns the stream’s integrity receipt (and, for a write-capable connection, records afact.retrievedaudit event by default — the same read-audit loop asdent8 context --record-retrieval);resources/subscribe/resources/unsubscriberegister fornotifications/resources/updatedpushes when a subscribed stream gains events. A write through the same connection notifies immediately; a write from any other process sharing the store is picked up within a short poll tick — so a long-running agent stops re-pollingexplainand reacts when a fact it depends on is superseded, contested, or retracted. Subscribing to a not-yet-asserted stream is allowed and notifies on its first write. Both the stdio server and the local daemon (throughdent8 mcp proxy, which pumps frames bidirectionally) deliver notifications.
Source: MCP resources specification
HTTP API — MCP-over-HTTP (built)
Section titled “HTTP API — MCP-over-HTTP (built)”The HTTP API is the MCP JSON-RPC surface carried over HTTP — the third transport of
dent8 mcp serve, after stdio and the local Unix-socket daemon, over the same
dispatch firewall path (ADR 0019). Rather than a
bespoke REST surface that would re-map every operation and re-derive every receipt (a second
copy of the machine contract, free to drift), the belief surface is the MCP method set, and
HTTP just carries it. The “routes” are MCP methods.
dent8 mcp serve --http --port 3369 # loopback + bearer token; writes with this identitycurl -s http://127.0.0.1:3369/ -H 'authorization: bearer <token>' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"assert","arguments":{"subject":"repo:x","predicate":"database", "value":"postgres","authority":"high","source":"source:owner"}}}'- Endpoint.
POST /(and/mcp) with a JSON-RPC message or batch; the response is the JSON-RPC result (204 No Contentfor a lone notification).GET /healthzis an unauthenticated liveness probe. The full belief surface —assert/supersede/retract/contradict/reinforce/expire/derive/explain/replay/list_facts/conflicts/snapshot/whatif/verify/native_*— is reachable as MCPtools/call, carrying the samestatus/ errorcode/structuredContentas stdio and the CLI’s--output json. - Trust boundary (local-first). Binds loopback only, validates the
Hostheader against localhost forms (anti-DNS-rebinding), and requires a bearer token on every non-health request (DENT8_HTTP_TOKEN, else generated per run and printed on start — the token substitutes for the daemon’sSO_PEERCREDcheck, which TCP cannot do). Writes are attested with the server’s own identity (DENT8_GRANT/DENT8_IDENTITY_KEY), exactly likedent8 mcp serveover stdio. - Deferred: a remote, multi-user service where each client proves its own source key (the daemon’s session challenge ported to HTTP, or client-signed write attestations) is a distinct decision, blocked until such a deployment exists. Until then the HTTP transport is loopback/trusted-network; front it with a reverse proxy (TLS) for anything else.
Desktop Debugger
Section titled “Desktop Debugger”The desktop app is accepted as a future product surface, but only as a debugger/control plane
over the existing integrity boundary (ADR 0020).
It should make the CLI/MCP/daemon state visible: connected agents, authority ceilings, grants,
recent accepted/rejected writes, conflicts, stale facts, snapshot health, explain/replay
timelines, native scan/reconcile findings, witness coverage, and doctor health.
The desktop app must not become a separate memory provider or private write path. Read/audit views should come first. Any future write action must call the same signed, authority-checked daemon/HTTP path used by other clients. A TypeScript web debugger should come before a native shell; Tauri is the preferred wrapper when a desktop package is justified.
SDKs should be thin wrappers over the HTTP API and shared JSON schemas.
Do not let SDK convenience helpers hide freshness, conflict, or authority metadata.