Concepts
The mental model behind Ergo.
One store, two behaviors
Everything Ergo remembers is a claim — a statement scoped to an
(org_id, project). But claims come in two flavors, and the difference is the
whole point.
| Kind | Behavior | Reason | Changed by |
|---|---|---|---|
fact | upsert freely | optional | overwrite / ingest |
decision · constraint · rejection · convention | append-only | required | supersede |
Facts are cheap, high-churn context — paths, versions, who-owns-what. They upsert without ceremony and skip the contradiction gate.
Decisions, constraints, rejections, and conventions are the durable choices
you don't want a future session to reverse by accident. They are append-only,
they must carry a reason, and the only way to change one is to supersede it —
which keeps the old version linked in history.
Why reasons are mandatory
A decision without a reason can't defend itself. When a later session asks "why
do we deploy only on green CI?", Ergo's why query returns the best reasoned
belief plus its rationale and full supersede history. A reason-less claim can
never win that query — so decisions require one at write time.
The contradiction guard
A guarded write (remember, learn, supersede) doesn't just append. It runs
the candidate claim through a pipeline before it's allowed to land:
- Normalize — an LLM normalizer parses the statement into a structured form
(subject, stance, scope, and an atomic
valuewhere one exists — a color, port, version, hostname, or number). - Structural — compares the normalized claim against active claims in the same scope: same subject, same-direction stance, overlapping scope, but a disagreeing atomic value flags a conflict.
- NLI — natural-language inference checks for entailment/contradiction that the structural pass can't see from values alone.
- Judge — decides the outcome: a HIGH-confidence contradiction blocks the write; softer signals surface as an advisory warning.
A blocked write returns HTTP 409 (the MCP tools surface this as a structured
conflict, not an error). That 409 is the product working — it's Ergo refusing
to let the agent quietly contradict itself.
The gate is deliberately selective. It runs on decisions/constraints, where a stale claim is costly. Bulk reference content goes through
ingest, which skips the gate entirely (see below).
Here's that same pipeline alongside the other four ways a claim moves through Ergo, so the shape of the whole system is in one place:
- Stored
- 0
- Warn
- 0
- 409
- 0
remember and supersede are the two gated lanes — both run
normalize → structural → NLI → judge, and both can be turned away with a
409. ingest is drawn passing underneath the four gate rings, because it
genuinely skips them — it's the fact fast-path described above. recall
and why are drawn arcing backwards, out of the store rather than into
it, because they're reads: nothing they do can ever 409. A blocked claim on
a gated lane travels only as far as the judge ring before reversing and
returning red, which is the 409 from the paragraph above, drawn as a path
rather than a status code. The five plates at the far end are the physical
store — claims, vec_claims, writes, conflict_events, and
projects — all in the one SQLite file described in
One SQLite file below. Drag to orbit, and use the lane
buttons or "force a contradiction" to see a 409 on demand.
Resolving a conflict: supersede vs. retract
When you hit a 409 — or when a decision simply changes — you have two distinct tools, and the difference matters:
supersede— "I changed my mind, and here's why." The decision genuinely changed. Ergo writes a new row, flips the old one tosuperseded, and links them so the why-chain survives. Use this to preserve history.retract— "this was wrong at birth." A typo, test junk, or a mis-scoped write that never should have existed. It flips toretracted(reason required) and leaves the active set, but stays visible inhistory. Retract runs no contradiction gate — it's pure removal.
Rule of thumb: if the world changed, supersede. If the claim was a mistake, retract.
Provenance
Beliefs formed from a source keep that source attached. learn takes a required
source and folds it into the reason, so a later why/recall can tell you not
just what is believed and why, but where it came from — a file and line, a doc,
a URL. This is the bridge between raw ingested reference (no gate) and a
contradiction-checked claim.
Audit trail
Every guarded write and every conflict it triggers is logged — not just the
current belief. If you need to answer who wrote what, and when for a
compliance or security review, /audit (or the ergo_audit tool) is a
self-serve, read-only trail of your own org's writes and conflict events —
see HTTP API → GET /audit.
On the hosted app this is also a browsable page — see The app →
Audit — with a project selector and paginated tables,
not just the raw API response.
Scope
Every read and write is scoped to an (org_id, project) pair. Claims in one
scope are never contradiction-checked against another — no cross-contamination
between repos or teams. The MCP adapter defaults the scope to
org_id="claude-code" and project = the git-repo basename of the working
directory, both overridable per call.
org_id is also the tenant — the isolation unit in a multi-tenant
deployment, where each tenant gets its own database file and its own token.
project is a namespace inside a tenant, not a security boundary. See
Multi-tenancy for the full model.
One SQLite file
The entire store — claims, reasons, history, and the sqlite-vec embedding
index — is a single SQLite file. One file, one embedding space, one backup. That
makes Ergo trivially air-gappable and portable: copy the file and you've copied
the memory. The embedding dimension is locked at the first write, so pick your
embedding provider before you start writing.