Skip to main content

The item lifecycle

A briefing item is not a static row — it moves through a lifecycle: it is born in a session, carried while open, and eventually closed, revived, or removed. Three commands drive the transitions, and all three share one contract: nothing is ever guessed on your behalf.

The never-guess contract

resolve and forget accept either an exact item id (o-3f8a2c) or a free-text query — but the query must match exactly one item. An ambiguous match is refused with the candidates listed; you pick one by id. Both commands take --dry-run, which runs the same match and prints what would happen without writing anything — look before the write.

One caveat the contract cannot cover: a confident match on the wrong item is not ambiguous, so the refusal never fires. That is what --dry-run is for.

daimon resolve — close a loop

daimon resolve "retry policy for the payments webhook" --dry-run
daimon resolve o-3f8a2c --note "shipped exponential backoff in #212"

Resolving records an append-only event; from then on, briefings withhold the item instead of carrying it stale. The item is not deleted — its history stays searchable, and the event trail shows when and why it closed. --status accepts a free-form lifecycle status; any status starting with reopen revives the item.

daimon reverify — assert it's still true

daimon reverify o-3f8a2c --evidence "checked the release page"

Reverify is the answer to the staleness warning: a carried item aged past the threshold, you checked the world, and it still holds. The event resets the item's last-verified stamp, so the warning clock restarts. Reverify takes exact ids only — re-asserting a claim is deliberate, so there is no fuzzy match to mis-fire.

Reverify is also the reject half of a supersession candidate (below).

daimon forget — remove, provably

daimon forget o-3f8a2c --reason "contains client name"
daimon forget "wrong belief about retry nonce" --dry-run

Resolve closes an item but keeps its content in history. Forget is for the cases where the content itself must go — a name that should never have been captured, a project detail, a wrong belief that keeps carrying. Capture-time redaction is the first line of defense; forget is the second, for judgment calls no redaction pattern can know about.

What happens on forget:

  • The item is removed from the live checkpoint, which is rewritten through the normal store path — redaction re-runs and, with receipts on, the receipt re-mints over the post-removal bytes (see receipts).
  • An append-only tombstone event records forgotten:<12-char content hash> — the hash, never the text. Removal means the content leaves the audit trail too; the trail can still prove that something was removed, when, and why (--reason, redacted like any note).
  • The recall index deletes the item's rows across all historical checkpoint copies in your local index — including your local copies of team mirrors — so recall cannot resurrect it. (Propagating tombstones into teammates' own mirrors is a deliberate follow-up, not in v1.)
  • The serializer's chunk cache is purged wholesale. That cache keeps pre-redaction extraction output for a few days so an interrupted capture never re-pays its LLM calls — and because its entries are keyed by chunk text, not searchable by contained value, selective removal is impossible. Forget clears all of it (the cost: chunks younger than the rotation window, chunk_cache_days, default 3 days, get re-extracted next time). Entries are also age-reaped at that window independently of forget. The purge is never fatal — removal of the belief state always completes — and the command reports honestly whether the purge succeeded.
  • Briefing withhold, carry suppression, and daimon stats all inherit the tombstone through the same event stream.

Deletion-durability compliance

The claim "a forgotten memory stays forgotten" is not asserted — it is committed as an executable compliance test that runs on every commit (source). It runs a forgotten value through every path that could quietly resurrect it and proves it stays gone at each one, while a never-forgotten twin stays retrievable so no check can pass vacuously:

#StepResult
1Write a distinctive fact through the serializerretrievable
2forget it — briefing, carry, recallremoved
3Re-feed the original source transcript and re-serializenot resurrected
4Recall index rebuildabsent
5A subsequent carryabsent
6Team dual-write mirrorabsent from the remote copy
7Rendered brief stringabsent
8Recall SQLite rowsabsent
9Signed receiptbinds the post-deletion bytes
10Audit trailrecords the deletion, holds none of its text
11Serializer chunk cache (pre-redaction)purged wholesale on forget

Result: 11 / 11 steps compliant. The tests are deterministic and use zero model quota — a canned extractor and a stubbed signer stand in for the LLM and the vitni CLI — so this is a compliance check that runs on every commit, not a benchmark. Step 3 is the one that matters most: re-ingesting the raw material a deleted item came from is how systems quietly bring it back, and the value-keyed tombstone drops it at the write boundary regardless of what the extractor re-produces.

One bound worth stating exactly: the chunk cache is pre-redaction by necessity (quote verification needs the raw text), so before this step joined the protocol a forgotten value's bytes could sit in the cache until the age reaper fired. Now forget purges the local chunk cache in the same command, and the chunk_cache_days reaper (default 3 days) remains the independent upper bound for anything written after a forget. The claim is scoped to this machine: the cache never syncs anywhere.

daimon handoff — the baton

Checkpoints are reconstructive: extracted from the transcript, ranked, budget-trimmed, competing for slots. The moment of deliberate handoff — "next session: do THIS first, watch out for THAT" — has different semantics: intentional, small, imperative, and it must never lose rank to ambient noise.

daimon handoff "Ship the release first. Beware: the cache key rotated."
daimon handoff --clear

The baton leads the next briefing, above every section:

HANDOFF (left deliberately by previous session, 2026-08-03T03:43:58Z):
→ Ship the release first. Beware: the cache key rotated.

It is stored as an event, never as a cognitive item — so it cannot enter ranking, dedup, or carry scoring, and it cannot resolve anything. One baton per project; a new one supersedes the old (the event trail keeps history). It stays active until the session that read it ends and serializes — a crashed session never consumes it. Capped small on purpose: a baton is "do X, beware Y", not a second checkpoint.

Decisions carry their because

A decision without its reasoning invites the next session to re-litigate it. When the transcript states the why, capture keeps one short clause of it:

- [✓ verbatim] soft-clip over hard clamp — because the clamp erased ordering in tied groups

The honesty bar matches everything else: stated reasoning only, never invented — a decision whose why was never said arrives without one.

The redaction boundary, stated exactly

"A quoted secret never reaches disk" is easily heard as "secrets never leave the machine". Those are different claims, and only the first is made:

  • Redaction is a disk boundary. It runs where bytes are persisted or displayed from disk — checkpoint writes, the team dual-write, event notes, and the status lines read back from crash/error logs.
  • It is not a network boundary. The serialize call ships the raw session transcript to whatever LLM backend you configured — a local backend sees everything, and so does a hosted one. Pick the backend with that in mind.
  • It catches secret shapes, not sensitive meaning. The pattern list is deliberately narrow (see team sharing for the exact inventory): filesystem paths, usernames, hostnames, and emails are not secret shapes, and a stored quote is arbitrary transcript bytes that syncs verbatim to a team remote. forget is the tool for content the patterns cannot know about.
  • The one bounded exception on disk is the pre-redaction chunk cache described above: local-only, mode 0600, age-reaped, purged wholesale by forget.

Supersession candidates

When a newer session contradicts a carried item, the briefing presents a supersession candidate: both sides, with the confirm/reject commands inline. You verify which side is true in the world, then answer with exactly those commands:

  • Confirmdaimon resolve <id>: the old item is genuinely superseded; future briefings withhold it.
  • Rejectdaimon reverify <id>: the contradiction was apparent, not real; the item stands, freshly verified.

The design principle across the whole lifecycle: daimon flags, you decide. Contradiction, staleness, and removal are all surfaced with evidence and resolved by an explicit human (or explicitly-instructed agent) action — never by a silent merge.