Every write Engram makes to your memory store passes through a three-tier safety model. The tier determines whether a fact is written automatically, requires a review step, or demands an explicit human confirmation. This model ensures that routine preferences flow into memory without friction while sensitive or conflicting information never slips in unreviewed.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/xantorres/engram/llms.txt
Use this file to discover all available pages before exploring further.
The three tiers
| Tier | Name | Trigger | How to write |
|---|---|---|---|
| 1 | Auto-append | Fact kind is in AUTO_KINDS and no conflict detected | Written automatically when autopromote=true and --apply is passed |
| 2 | Registry update | Metadata-level registry change | Written automatically when autopromote=true and --apply is passed |
| 3 | Curated / confirmed | Fact kind is in CURATED_KINDS, or a conflict is detected | Requires engram queue review with --confirm |
Even tier-1 and tier-2 facts are not written by default. The bridge is in dry-run mode unless both
bridge.autopromote = true (in config or via ENGRAM_AUTOPROMOTE) and the --apply flag are present.Kind classification
Engram classifies every memory fact by its kind. The kind determines which tier the fact enters.Auto kinds (tier 1)
Facts with these kinds are candidates for automatic promotion. They are considered low-sensitivity and routine:Examples of auto-kind facts
Examples of auto-kind facts
preference— “Always use single quotes in Python”tooling— “This project uses pnpm, not npm”project— “The API lives in src/api/”infra— “Staging is deployed on Fly.io in the fra region”
Curated kinds (tier 3)
Facts with these kinds are always routed to the review queue and require--confirm:
Examples of curated-kind facts
Examples of curated-kind facts
identity— usernames, email addresses, SSH key fingerprintsfiscal— billing accounts, pricing tiers, cost budgetspeople— names, roles, contact details of individualsconstraint— hard rules the agent must never violatelocation— physical addresses, geographic regions with personal significancehealth— medical context, accessibility needs
Conflict escalation
When the bridge classifies a new fact, it runs deduplication against already-promoted facts (dedup.compare). If the incoming fact conflicts with an existing one — that is, both make incompatible claims about the same subject — the new fact is always escalated to tier 3, regardless of its kind.
preference facts is treated with the same caution as an identity fact. You always decide which version of a conflicting truth wins.
Conflict escalation is a one-way ratchet — escalated facts never fall back to tier 1 or tier 2 automatically. You must explicitly approve or reject them via the review queue.
Bridge behavior: plan vs. apply
The bridge has two distinct phases:promote.plan() — classify without writing
promote.plan() — classify without writing
promote.plan() reads the pending queue, runs deduplication, classifies each fact by tier, and returns the promotion plan as output. Nothing is written to the store. This is what runs when you call engram sync without --apply.promote.apply() — write tier-1 and tier-2 facts
promote.apply() — write tier-1 and tier-2 facts
promote.apply() executes the plan produced by promote.plan(). It writes tier-1 and tier-2 facts to the store only if autopromote=True. Tier-3 facts remain in the queue regardless.autopromote is false, promote.apply() behaves identically to promote.plan() — the plan is shown and nothing is written.The --confirm gate (tier 3)
Tier-3 facts — curated kinds and conflict-escalated facts — live in the review queue until a human explicitly acts on them. Approving a tier-3 fact calls review.approve(), which refuses to execute without confirm=True.
Tier-1 write flow (end-to-end example)
The following shows the full lifecycle for a low-sensitivitytooling fact:
Tier-3 write flow (end-to-end example)
Dry-run default
The bridge does not write anything unless you explicitly enable it. This table summarises all combinations:autopromote | --apply flag | Result |
|---|---|---|
false | absent | Dry run — plan printed, nothing written |
false | present | Dry run — autopromote=false blocks writes |
true | absent | Dry run — --apply not passed |
true | present | Tier-1 and tier-2 facts written |
sync --apply regardless of the autopromote setting.
Undo tokens and atomic writes
Every write operation — whether triggered bypromote.apply() or review.approve() — follows the same atomic pattern:
- Snapshot the current content of the target file into a temporary location.
- Write the new content atomically (write to temp, then rename).
- Emit an undo token that references the snapshot.
- Append an audit entry to
audit.jsonl.
The forget command
review.forget() marks a promoted fact as rejected rather than approved. It does not delete the underlying store file entry immediately but records the rejection decision and prevents the fact from appearing in recall output.
What forget does:
- Marks the fact as
promoted → rejectedin the registry. - Emits an undo token so the rejection itself can be reversed.
- Appends an audit entry with
endpoint="fact/forget".
Audit trail (audit.jsonl)
Every write — approval, promotion, rejection, or forget — appends a JSON line to audit.jsonl in the store root. The file is append-only and is never modified by Engram after an entry is written.
Example audit.jsonl entries: