The mneme 0.10.0 CLI adds decision-index migrate, which moves project memory onto the persisted, versioned Decision Index. decision-mcp and the decision proposals|show|accept|reject group read and write that index. MCP can retrieve and propose; only the separate human authority commands can accept or reject. Acceptance does not activate deterministic protection.
CLI reference

The mneme command-line interface

Reference for the OSS mneme CLI: manage and audit the decision corpus, operate the local MCP server, review decision proposals, enforce generated content, export to editor surfaces, and run the governance benchmark.

Install

Python 3.11+. MIT-licensed. No vector store, no ML runtime.

$ pipx install "mneme-hq==0.10.0"
# Include the optional MCP runtime:
$ pipx install "mneme-hq[mcp]==0.10.0"

Installs the mneme entry point on your PATH. Scaffold a new corpus with mneme init; every other subcommand requires --memory pointing at a project_memory.json file. An example corpus ships at examples/project_memory.json.

From source (contributors): git clone https://github.com/MnemeHQ/mneme && cd mneme && pip install -e .

init

Scaffold an empty project memory corpus.

mneme initWrite

Creates the memory file (including its parent directory) containing a valid, empty decision corpus — deliberately zero seeded decisions, because every recorded decision is enforceable and sample content would create phantom rules. Exits non-zero without writing if the target file already exists, unless --force is supplied. On 0.10.0 the new file already holds an authoritative decision_index section, so it needs no migration.

$ mneme init
Created .mneme/project_memory.json
Flags
FlagRequiredDescription
--pathnoOutput path. Defaults to .mneme/project_memory.json.
--forcenoOverwrite an existing file at --path.

decision-index migrate

Move project memory written by 0.9.x onto the persisted Decision Index. New in 0.10.0.

mneme decision-index migrateWrite

Adds an authoritative decision_index section to project_memory.json. The index holds each decision, its immutable versions, and its rule bindings; the existing decisions[] array becomes a compatibility snapshot derived from it. The command changes only that one file. The MCP server, mneme decision accept, and mneme adr import --apply need migrated memory and exit 2 without it. mneme check, test_query, list_decisions, and the adr import preview work with either.

$ mneme decision-index migrate --memory .mneme/project_memory.json
Decision Index migration preview: .mneme/project_memory.json
  Native decisions:                2
  Active after migration:          2
  Non-active leaving Layer 1:      1
    ADR-000 (superseded)
  Legacy items becoming decisions: 1
    rule-001
  Migrated rule bindings:          0
  ...
Preview only; nothing was written. Re-run with --apply to write exactly this migration.

$ mneme decision-index migrate --memory .mneme/project_memory.json --apply
Migrated .mneme/project_memory.json: decision_index is now authoritative.
Flags
FlagRequiredDescription
--memorynoPath to project_memory.json. Defaults to .mneme/project_memory.json.
--applynoWrite exactly the previewed migration. Without it the command only previews. There is no --dry-run flag, and no force or repair mode.
  • Lossless or it refuses. If any decision can’t be represented in the index, it prints ERROR: migration refused: …, exits 2, and writes 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, source.type: "eventcatalog"), can’t be represented, so migration refuses. Because adr import --apply also needs migrated memory, keep such a decision this way: write it as an ADR file, remove its row from decisions[], migrate, then import the ADR.
  • Safe to re-run. On migrated memory it prints Already migrated: decision_index is authoritative and valid; nothing to do. and leaves the file byte-identical.
  • No lost updates. --apply refuses if the file changed after it was read.
  • Superseded decisions stop being enforced. Decisions marked superseded, deprecated, or inactive move out of decisions[] but stay in the index with their lifecycle. Before migration, mneme check still loaded such a row; after it, only active decisions are retrieved and enforced. The preview lists them under “Non-active leaving Layer 1”.

Upgrade every writer before you apply. Migrated memory must not be written by 0.9.2 or earlier. An older add_decision or adr import, for example in a CI image or a teammate’s install, succeeds without an error, and the next 0.10.0 mneme check, test_query, list_decisions, or audit on the file then fails with DecisionIndexPersistenceError; decision-mcp and add_decision exit 2. decision-index migrate won’t repair the file. To recover, restore it from version control and redo the change with 0.10.0. Move CI jobs, hooks, and every install to 0.10.0 first.

list_decisions

Print every decision in the memory file.

mneme list_decisionsRead

Lists every decision in the corpus with id, summary, scope, and constraints. On migrated memory it lists active decisions only. Read-only.

$ mneme list_decisions --memory examples/project_memory.json
Flags
FlagRequiredDescription
--memoryyesPath to project_memory.json.

add_decision

Append a new decision to the corpus.

mneme add_decisionWrite

Writes a new decision directly to the JSON file. The Pipeline runtime is never mutated — this is a file operation only. Fails with exit code 2 if the id already exists. On migrated memory it creates the first version of a decision only: an identical retry writes nothing and exits 0, and the same id with different content exits 2. To change a decision, edit its ADR and run adr import --update-existing.

$ mneme add_decision --memory examples/project_memory.json \
    --id mneme_042 \
    --decision "Use JSON storage" \
    --scope storage \
    --constraint "no postgres" \
    --anti-pattern "sqlalchemy"
Flags
FlagRequiredDescription
--memoryyesPath to project_memory.json.
--idyesStable id for the decision (e.g. mneme_042).
--decisionyesShort statement of the decision.
--rationalenoOptional free-text explanation.
--scopeno, repeatableOne or more scope tags. Pass --scope multiple times.
--constraintno, repeatableOne or more constraints the decision implies.
--anti-patternno, repeatableOne or more patterns to flag against.

test_query

Run a query through the retriever and show scores plus the injected context.

mneme test_queryRead

Useful for debugging which decisions are surfaced for a given task description before you wire enforcement into a workflow. Prints every decision ranked by score, plus the top-N context packet that would actually be injected.

$ mneme test_query --memory examples/project_memory.json \
    --query "should I add postgres?"
Flags
FlagRequiredDescription
--memoryyesPath to project_memory.json.
--queryyesThe task description / prompt context to retrieve against.
--topnoHow many top decisions to show in the injected packet. Defaults to the package default.

check

Enforce decisions against an input file. The command at the center of the governance loop.

mneme checkEnforce

Reads an input file (a prompt, a generated diff, a draft), retrieves the relevant decisions for --query, and runs the enforcer. Prints any violations and exits with a code that reflects the verdict.

$ mneme check --memory examples/project_memory.json \
    --input draft.md \
    --query "working on storage layer" \
    --mode strict
Flags
FlagRequiredDescription
--memoryyesPath to project_memory.json.
--inputyesPath to the file to check. A filepath, not inline text — write generated content or a diff to a file first.
--queryyesProvides retrieval context for relevance-scored decisions. Retrieval does not bound corpus-wide typed literal enforcement — those rules apply regardless of query relevance.
--target-pathnoArtifact path used for typed-rule path applicability when --input contains materialized or introduced content from another file (e.g. a hook checking staged edit content against the real target path).
--topnoSize of the retrieval-gated tier: bounds how many decisions have their multi-term rules applied. Unambiguous literal rules are enforced across the whole corpus regardless (ADR-017).
--modenostrict (default) or warn. See exit codes.
--jsonnoEmit a machine-readable verdict payload (schema: mneme.check/v1, includes evaluation_complete, per-rule applicability, and freshness) as the only stdout content. Exit codes unchanged.
--adr-dirnoDirectory of ADR markdown files checked for freshness drift. Warn-only diagnostics that never affect the exit code; defaults to docs/adr, skipped silently when absent.

Mode semantics. strict exits non-zero on any violation, making it suitable as a merge gate. warn exits zero for every verdict (an INCOMPLETE evaluation still exits 2), useful while a team is still shaping its decision corpus and does not want a noisy corpus to block work.

Which decisions are checked. On memory migrated to the Decision Index, only active decisions are retrieved and enforced. Superseded, deprecated, and inactive decisions stay in the index but never produce a verdict. Memory without a decision_index section keeps the pre-0.10.0 loading path. The flags and exit codes are the same either way.

Completeness and path diagnostics. A verdict is only trusted when the payload's evaluation_complete flag is true; an incomplete evaluation exits 2 and prints Result: INCOMPLETE rather than a verdict. Path-scoped typed rules also emit per-rule applicability lines (PATH APPLIED [decision_id] … or PATH EXCLUDED [decision_id] …) showing how the target path resolved against the rule's selectors — an unresolvable path prints ERROR PATH_APPLICABILITY_UNKNOWN and the result is INCOMPLETE, never a silent pass. With --json, the same traces appear in the payload's applicability array.

audit

Run the Architecture Protection Audit over project memory.

mneme auditAudit

Classifies every active decision in the corpus — Protected, Mneme-ready, Requires modelling, or Guidance — and reports the protection summary and per-decision detail. This is the classification surface mneme protect consumes; the tiers are frozen P1.2 semantics that activation never reinterprets.

$ mneme audit --memory .mneme/project_memory.json --repo-root .
Flags
FlagRequiredDescription
--memoryyesPath to project_memory.json.
--repo-rootnoRepository root scanned for external enforcement evidence (.github/workflows, .gitlab-ci.yml). Verified CI evidence upgrades a literalizable decision to protected; a bare token mention is candidate evidence and exits 1 as a warning.
--jsonnoWrite the mneme.audit/v1 JSON report to FILE.

setup

Initialize Mneme project state in setup mode.

mneme setupSetup

Creates project state in setup mode: context and non-blocking checks only — never enforcement. Enabling protection is always a separate, explicit decision (mneme protect activate). Optionally records an opaque Architecture Audit setup reference, taken verbatim and resolved by Audit pairing. Run it inside a git repository; outside one it exits 2. Memory it creates is already migrated to the Decision Index.

$ mneme setup --memory .mneme/project_memory.json
Flags
FlagRequiredDescription
--memorynoPath to project_memory.json. Defaults to <repo-root>/.mneme/project_memory.json.
--audit-refnoOpaque Architecture Audit setup reference, recorded verbatim for Audit pairing.

protect

Per-decision protection activation: list candidates, inspect status, validate, activate.

mneme protect listRead

Lists decisions that are active, currently unprotected, and canonically Mneme-ready. Already-Protected, Requires-modelling, Guidance, and superseded decisions are never candidates, and no model decides eligibility — the audit's frozen classification decides it.

$ mneme protect list --memory .mneme/project_memory.json
mneme protect statusRead

Shows one decision's canonical tier, guardrail, evidence, and whether the activation rule is installed — all derived from the repository, never stored.

$ mneme protect status <decision-id> --memory .mneme/project_memory.json
mneme protect validateValidate

Deterministically validates a decision's proposed protection against the existing enforcement engine — without writing anything and without enabling protection. Four checks: prohibited input detected as a typed FAIL; permitted input not blocked; path applicability respected (canonical policy sources exempt); unrelated paths unaffected.

$ mneme protect validate <decision-id> --memory .mneme/project_memory.json
mneme protect activateActivate

Activation is an explicit user action — the only command that installs enforcement. It appends the typed FORBID_LITERAL rule to that one decision's record in project memory (idempotent; refuses on any unsafe or unsupported state), then re-loads from disk and re-runs the canonical assessment. Only an independently observed Protected tier is reported as verified.

$ mneme protect activate <decision-id> --memory .mneme/project_memory.json
Shared flags — all protect subcommands
Argument / flagRequiredDescription
decision_idyes (positional, except list)Decision id, e.g. config-format or mneme_042.
--memoryyesPath to project_memory.json.
--repo-rootnoRepository root for the same external CI-evidence scan mneme audit performs; omitted means no CI-evidence scan.

Validation is not activation, and activation is not verified protection. A VALID result changes nothing in the repository; after activation the decision only counts as Protected when a fresh canonical assessment observes real enforcement evidence. Full semantics, result distinctions, and boundaries: Protection activation.

Availability. Shipped in the Mneme core at MnemeHQ/mneme@91d71be7 and part of the released mneme-hq package on PyPI since mneme-hq==0.7.0. Install with pipx install "mneme-hq==0.10.0".

decision-mcp

Serve the frozen six-tool Decision Index surface over local stdio.

mneme decision-mcpMCP server

Starts the local server. It reads canonical decisions from the Decision Index in --memory and stores proposals in --proposals. It exits with code 2 if the memory file is missing or not yet migrated; run decision-index migrate first. The server exposes proposal and read tools only; no MCP authority operation exists.

$ mneme decision-mcp
$ mneme decision-mcp --proposals .mneme/decision_proposals.json \
    --memory .mneme/project_memory.json --adr-dir docs/adr
Flags
FlagRequiredDescription
--proposalsnoProposal-store JSON path. Defaults to .mneme/decision_proposals.json; an explicit empty string selects an in-memory store.
--memorynoProject memory holding the authoritative decision_index section. Defaults to .mneme/project_memory.json. All canonical reads come from it.
--adr-dirnoADR directory validated before startup. Validation only: the server never reads decisions from it. No default. Invalid or ambiguous input prevents startup.

Requires mneme-hq[mcp]. Full tool, storage, error, and authority reference: MCP server.

decision

Inspect proposals and exercise explicit human accept/reject authority.

mneme decision proposals | show | accept | rejectAuthority workflow
$ mneme decision proposals
$ mneme decision show <proposal-id>
$ mneme decision accept <proposal-id> --memory .mneme/project_memory.json
$ mneme decision reject <proposal-id>

proposals and show are read-only. accept writes a canonical decision version into the Decision Index, which needs migrated memory; it does not run Audit or activate protection. reject makes no project-memory change. All four default to .mneme/decision_proposals.json; accept also accepts --decision-id.

Full lifecycle, provenance, flags, exit codes, and what changed in 0.10.0: Decision proposals.

cursor generate

Export retrieved decisions to a Cursor .mdc rules file.

mneme cursor generateExport

Generates a Cursor-compatible rules file scoped to the supplied query. Writes the corpus into a format the Cursor agent reads directly, so the same decisions are surfaced to the IDE agent as to the rest of the toolchain. See the Cursor integration page for end-to-end setup.

$ mneme cursor generate --memory examples/project_memory.json \
    --query "working on storage layer" \
    --output .cursor/rules/mneme.mdc
Flags
FlagRequiredDescription
--memoryyesPath to project_memory.json.
--queryyesContext query for retrieval.
--outputnoOutput path. Defaults to .cursor/rules/mneme.mdc.
--topnoHow many top decisions to include.

benchmark

Run the governance benchmark suite and report violation-detection results.

mneme benchmarkMeasure

Runs every scenario in the supplied directory against the decision corpus and prints a terminal report. Optional --json and --markdown flags emit machine- and human-readable reports for CI artifacts. Scenario categories map onto the governance violation hierarchy; the benchmark methodology is documented at /benchmark/.

$ mneme benchmark examples/benchmarks/ \
    --memory examples/project_memory.json \
    --json reports/bench.json \
    --markdown reports/bench.md
Flags
FlagRequiredDescription
benchmarks_diryes (positional)Directory containing benchmark scenario subdirectories.
--memoryyesPath to project_memory.json.
--jsonnoWrite a JSON report to FILE.
--markdownnoWrite a Markdown report to FILE.

adr import

Compile a directory of ADRs into the decision corpus.

mneme adr importWrite

Parses every ADR markdown file in a directory (YAML frontmatter required), validates the corpus, resolves precedence, and writes compiled decisions into the target memory. Runs as a preview by default; nothing is written until --apply. Full walkthrough: ADR import guide. Step by step: Turn an ADR into an enforceable decision.

$ mneme adr import docs/adr \
    --memory .mneme/project_memory.json \
    --dry-run
$ mneme adr import docs/adr \
    --memory .mneme/project_memory.json \
    --apply
Arguments & flags
FlagRequiredDescription
adr_diryes (positional)Directory containing ADR markdown files.
--memoryyesPath to the target project_memory.json.
--dry-runnoPrint the preview without writing (default).
--applynoWrite imported decisions to --memory.
--update-existingnoFor an ADR whose id already exists, create a new immutable version, or reuse the identical one. Earlier versions are kept, never overwritten.
--preserve-protection RULE_IDno, repeatableCarry a protection binding (installed by mneme protect activate) or a binding carried over by migration (legacy_unknown) into the new version when the edited ADR no longer derives it, after deterministic revalidation. Requires --apply --update-existing.
--release-protection RULE_IDno, repeatableExplicitly release a protection or legacy_unknown binding: drop it if the edited ADR no longer derives it, or downgrade it to an ordinary version binding if it does. Requires --apply --update-existing.
--expected-predecessor ADR-ID=VERSION_IDno, repeatableRetry an earlier --update-existing apply by pinning the version_id that was current when it ran (shown as “current predecessor” in the preview). Reuses that exact version if it exists, creates it if the pinned version is still current, and otherwise fails as stale. Requires --apply --update-existing.
--approve-conflictsnoProceed with apply even if active-active contradictions exist.

Protected rules can’t be dropped silently. If an edited ADR would drop a rule binding installed by mneme protect activate, or any binding carried over by decision-index migrate (authority legacy_unknown), --update-existing exits 2 instead of removing it; choose --preserve-protection or --release-protection for each rule it names. After migrating 0.9.x memory, that includes any rule you change or remove in an ADR. Rules first derived from an ADR on 0.10.0 follow the ADR. adr import --apply needs migrated memory; the preview doesn’t. On migrated memory, rule ids take the form <decision_id>:<TYPE>:<32 hex>, derived from the rule’s value and applicability rather than its position. A superseded ADR is recorded in the Decision Index with its lifecycle but is not enforced.

Exit codes

Designed for CI gating. The codes are stable across releases.

mneme check · by mode
Verdictstrict (default)warnMeaning
PASS00No violations.
WARN10Constraint matched. In strict mode the verdict stays WARN but the process exits non-zero; warn mode exits zero.
FAIL20Typed rule or anti-pattern hit. In strict mode this is a hard fail.
INCOMPLETE22Evaluation could not complete (evaluation_complete: false). Never reported as PASS — machine consumers should fail open on their own terms.
mneme benchmark
CodeMeaning
0All scenarios passed.
1At least one scenario failed, or a benign scenario was blocked (FALSE_POSITIVE).
2Supplied benchmarks_dir is not a directory.
mneme add_decision
CodeMeaning
0Decision appended, or, on migrated memory, an identical decision already exists and nothing was written.
2A decision with the supplied --id already exists (on migrated memory: with different content).
mneme decision-index migrate
CodeMeaning
0Preview printed, migration applied, or memory already migrated.
2Migration refused (not lossless, invalid memory or an invalid existing index, or the file changed after it was read), or the memory file doesn’t exist. Nothing was written.
mneme protect
CodeMeaning
0Success or desired state (including already_protected).
1Actionable failure: not eligible, validation failed, or verification failed.
2Usage error: missing file, unknown decision id, or refused unsafe record.

CI usage

The check command is designed to live as a pre-merge governance gate. The simplest viable wiring:

For a workflow that skips binary files and keeps the JSON verdicts, follow the how-to guide fail a pull request that breaks an ADR.

GitHub Actions — PR diff gate

Run mneme check against the PR diff in strict mode. Exit code 1 (WARN) or 2 (FAIL) blocks the merge.

name: governance
on: [pull_request]
jobs:
  governance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.11' }
      - run: python -m pip install "mneme-hq==0.10.0"
      - name: Render PR diff
        run: git diff origin/${{ github.base_ref }}...HEAD > pr.diff
      - name: Governance check
        run: |
          mneme check \
            --memory .mneme/project_memory.json \
            --input pr.diff \
            --query "${{ github.event.pull_request.title }}" \
            --mode strict

Full example wired into a working repo: /integrations/github-actions/.

Pre-commit — local warn-mode

Run in warn mode locally so the developer sees friction without blocking the commit. Pair with strict-mode CI for the actual gate.

# .git/hooks/pre-commit — --input expects a filepath, so write the diff first
$ git diff --cached > /tmp/mneme-staged.diff
$ mneme check \
    --memory .mneme/project_memory.json \
    --input /tmp/mneme-staged.diff \
    --query "$(git log -1 --pretty=%B)" \
    --mode warn