The Decision Index is Mneme’s authoritative record of decisions. Since mneme-hq 0.10.0 it lives in the decision_index section of project_memory.json: every decision, each immutable version of it, and the typed rules bound to those versions. Only active decisions are enforced or used by check and test_query; non-active ones are kept, and MCP reads return them labelled. It records what each version said and, where known, where it came from, not who approved it.
Reference · mneme-hq 0.10.0

Decision Index: versions, lifecycle, and migration.

What the persisted Decision Index stores, how a decision changes over time without losing its history, how supersession and rule protections carry across those changes, and how an existing 0.9.x project moves onto it.

What it stores

The index is a section of the project memory file, with schema mneme.decision-index/v1 and three lists:

ListOne entry perKey fields
decisionsDecisiondecision_id, lifecycle_status, active_version_id, and relationships such as supersedes.
versionsImmutable version of a decisionversion_id, content_digest, the statement, rationale, scope, constraints, and anti-patterns, source_evidence (for an ADR: the file locator and its sha256), and supersedes_version_id pointing at the version it replaced.
rulesTyped rule bound to a versionrule_id, decision_version_id, rule_type, the rule’s value and applicability, and how the binding was made.

The older top-level decisions[] array is still written, as a compatibility snapshot of the active decisions derived from the index. Mneme checks that the two agree when it loads the file. Nothing should edit the snapshot by hand.

Every surface reads the same file. mneme check, test_query, and the hook read the active decisions; the MCP server reads the whole index, reloading it for every canonical read; mneme decision accept, adr import, and add_decision write it.

Versions and identity

A version is never edited. When an ADR changes and you re-import it with mneme adr import --apply --update-existing, Mneme writes a new version whose supersedes_version_id names the previous one, moves the decision’s active_version_id to it, and keeps the earlier version in the list. Re-importing identical content reuses the existing version instead of adding a copy.

IdentifierDerived from
content_digestsha256 of the decision’s content: statement, rationale, scope, constraints, and anti-patterns. Identical content gives an identical digest.
version_iddver- plus a hash of the decision id, the content digest, the source occurrence, and the predecessor version. It identifies one occurrence in the decision’s history, so identical text from a different source, or after a different predecessor, gets a different id.
rule_id<decision_id>:<TYPE>:<32 hex>, a hash of the rule’s value and applicability. It doesn’t depend on the rule’s position, so a rule that carries over to a new version keeps its id and is bound to the new version.

add_decision only creates the first version of a decision. On migrated memory it refuses the same id with different content (exit 2); change a decision through its ADR instead.

Lifecycle

Each decision has one lifecycle_status: active, superseded, deprecated, or inactive.

  • Only active decisions are enforced or retrieved by the CLI. mneme check, test_query, the coding-agent hooks, list_decisions, conflict detection, benchmarks, and mneme audit see active decisions only.
  • Non-active decisions are kept, not deleted. They stay in the index with their versions, and the MCP read tools (decision.get, decision.search, decision.applicable_to, decision.trace) still return them, labelled with their lifecycle_status, so an agent can see what a decision replaced.
  • Migration changes what is enforced. Before migration, a row in decisions[] marked superseded was still loaded by mneme check. After migration it is not. The migration preview lists these decisions under “Non-active leaving Layer 1”, so you can review them first.

Supersession

Supersession comes from your ADRs. An ADR with supersedes: [ADR-101] in its frontmatter records a supersedes relationship on its decision, and ADR-101, marked status: superseded, is stored with lifecycle_status: superseded. Its rules stay in the index, bound to its version, and are not enforced.

$ mneme adr import docs/adr --memory .mneme/project_memory.json --dry-run
Active set (1 ADRs):
  [ADR-102] status=active
      rule: FORBID_LITERAL mongodb

Non-active ADRs (1):
  [ADR-101] status=superseded (superseded_by ADR-102)

Precedence between two accepted decisions is a separate question from supersession. In 0.10.0, when two accepted ADRs share a scope, the higher priority wins, then the newer date. The other is stored with lifecycle_status: inactive and not enforced. The import doesn’t report it; mneme check with an ADR directory warns SILENT_PRECEDENCE_ELIMINATION. Give each ADR its own scope. See precedence semantics.

Protections across edits

Each rule binding records how it was made. A rule derived from the ADR text follows the ADR: edit the rule out of the ADR, re-import, and the new version no longer carries it. A rule installed by mneme protect activate is a protection binding, and every rule binding that decision-index migrate carries over from 0.9.x memory is marked legacy_unknown, because its origin can’t be known. An ADR edit can’t silently drop either kind, so after migrating 0.9.x memory, changing or removing any rule in an ADR needs an explicit choice:

$ mneme adr import docs/adr --memory .mneme/project_memory.json --apply --update-existing
ERROR: ADR import refused while evolving 'ADR-301': decision 'ADR-301': version evolution would drop protection/legacy_unknown bindings ['ADR-301:FORBID_LITERAL:faca47fbc3a3d2125eaa532ec1037c38']; pass --preserve-protection or --release-protection for each (ADR-030 §9a)

Choose for each named rule: --preserve-protection RULE_ID carries it into the new version after revalidating it, and --release-protection RULE_ID lets it go. To retry an earlier --update-existing apply, --expected-predecessor ADR-ID=VERSION_ID pins the version that was current when it ran. Flags in full: adr import.

Migration from 0.9.x

Projects created with mneme init or mneme setup on 0.10.0 start with an index. Memory written by 0.9.x moves over with one explicit command. It previews by default and writes only with --apply:

mneme decision-index migrate --memory .mneme/project_memory.json
mneme decision-index migrate --memory .mneme/project_memory.json --apply
  • It is lossless or it refuses, writing nothing. Decisions added with add_decision or imported from ADR files migrate. A decision whose source is a free-text note, or points at something other than an ADR file (such as an EventCatalog import), has no representation in the index, so memory that contains one stays unmigrated. To keep such a decision, write it as an ADR file, remove its row from decisions[], migrate, then import the ADR.
  • Re-running it on migrated memory changes nothing.
  • --apply refuses if the file changed after the preview read it.
  • Until you migrate, mneme check, test_query, and list_decisions keep working on the pre-0.10.0 path. The MCP server, mneme decision accept, and mneme adr import --apply need the index and exit 2 without it.

Full output and exit codes: decision-index migrate.

Version compatibility

Upgrade every writer before you migrate. Once memory is migrated, a 0.9.2 or earlier process that writes it, such as add_decision in an old CI image or a teammate’s install, succeeds without an error. The next 0.10.0 mneme check, test_query, list_decisions, or audit on the file then fails with DecisionIndexPersistenceError, because the decisions[] snapshot no longer matches the index, and the MCP server refuses to start. Move CI jobs, hooks, and every install to 0.10.0 first.

If it happens, decision-index migrate won’t repair the file. Restore it from version control and redo the change with 0.10.0.

No 0.10.0 command migrates memory implicitly. Only mneme decision-index migrate --apply does.

What it does not record

The index is a version history of decisions, not an approval record. It stores what each version said, its date, where it came from (for an ADR, the file and its content hash; for an accepted proposal, the proposal; versions added with add_decision record no source), and which version it replaced. It does not store who approved a decision: mneme decision accept has no identity input, and neither the version nor the proposal records the person who ran it. If you need an auditable record of who approved each change, keep it where identities are verified, such as pull request reviews on the ADR files.