Integration · Corpus import 4 min read · May 2026

# Import Existing ADRs

Your ADRs are already written. This makes them enforceable. Add a `## Constraints` section, run one command to preview, one to apply — and the decisions are live in the enforcement pipeline.

By Theo Valmis · Published May 2026

## The problem this solves

Most teams have ADRs. They sit in `docs/adr/`, written in good faith, referenced in onboarding, and then quietly ignored by every AI coding agent that touches the codebase. The agent has no access to them, no enforcement against them, and no way to know when code it generates violates a decision the team already made.

`mneme adr import` closes that gap without requiring you to rewrite your ADRs or adopt a new format. Add a single section to flag machine-readable constraints, run the import, and those decisions enter the same enforcement pipeline as any other Mneme rule. Mneme catches the violation before it lands in review.

## Step 1: add a Constraints section

ADR files need YAML frontmatter and an optional `## Constraints` section. The rest of the body is free-form markdown and is preserved as rationale.

    ---
    id: ADR-005
    title: Brand vs Package Namespace Enforcement
    status: accepted
    priority: foundational
    date: "2026-05-04"
    scope: code
    ---

    The package namespace is `mneme`. The brand name is "Mneme HQ".
    These must never be conflated in code-bearing surfaces.

    ## Constraints

    - FORBID_DEPENDENCY: MnemeHQ
    - FORBID_PATH: site/use-cases/**/Mneme HQ*

YAML frontmatter is required. Nygard-style `**Status:** Accepted` headers are not parsed. Adding a 6-line frontmatter block per file is a one-time, scriptable conversion.

Three directive kinds are supported:

Directive | What it does | Enforced by `mneme check`?
--- | --- | ---
FORBID_DEPENDENCY: X | Stored as `"no X"` in decision constraints | Yes — triggers WARN
FORBID_PATH: glob | Stored for visibility and audit | No (path enforcement is a follow-on)
REQUIRE_PATH: glob | Stored for visibility and audit | No (path enforcement is a follow-on)

Unknown directive kinds raise a parse error rather than being silently dropped — a typo should not defeat governance.

## Step 2: preview the import

The default mode is dry-run. Nothing is written.

    mneme adr import docs/adr --memory .mneme/project_memory.json

Output shows the active decision set and each parsed constraint:

    ADR import preview
    ============================================================

    Active set (4 ADRs):
      [ADR-001] status=active
          (no ## Constraints directives)
      [ADR-005] status=active
          constraint: no MnemeHQ
          constraint: FORBID_PATH site/use-cases/**/Mneme HQ*

ADRs with status `proposed`, `deprecated`, or `superseded` are excluded from the active set. Explicit supersession via the `supersedes` frontmatter field is handled silently. Active-active contradictions (two accepted ADRs sharing the same scope, priority, and date) surface as diagnostics and block the apply step until resolved.

## Step 3: apply the import

    mneme adr import docs/adr --memory .mneme/project_memory.json --apply

The import writes atomically: the updated memory is serialized to a sibling temp file, then swapped in with `os.replace()`. A failed write leaves the original file intact. No backup files are created — the original is always recoverable from git history.

On success, the command reports what was written:

    Wrote 4 decisions to .mneme/project_memory.json

## Step 4: verify enforcement

Once imported, decisions enter the existing `MemoryStore → DecisionRetriever → check_prompt` pipeline without any changes to those components.

    mneme check \
      --memory .mneme/project_memory.json \
      --input agent-output.py \
      --query "Python package imports code namespace" \
      --mode warn

If `agent-output.py` contains `from MnemeHQ.memory_store import MemoryStore`:

    WARN  [ADR-005] constraint "no MnemeHQ" -- trigger: mnemehq
          Brand vs Package Namespace Enforcement

    Result: WARN

The correct import path passes cleanly:

    Result: PASS

## Conflict handling

Same-id collision. If an incoming ADR id already exists in the target memory file's `decisions[]` array, the import refuses. Pass `--update-existing` to overwrite the existing entry in place.

Active-active contradiction. If two accepted ADRs share the same scope, priority, and date, the compiler cannot pick a winner deterministically. The import surfaces this as a diagnostic and refuses `--apply` unless `--approve-conflicts` is also passed. The fix is to edit the contradicting ADRs: mark one superseded, give one a higher priority, or give one a newer date.

## Dogfooding

Mneme HQ enforces its own ADRs this way. The `docs/adr/` directory in the public repo contains the team's architectural decisions, and `ADR-005` (namespace enforcement) is imported into the project's live memory. When an AI-assisted task generates code using the wrong package namespace, Mneme catches it before it lands in review.

The runnable demo is at `mneme-project-memory/examples/demo-adr-import.py` in the repo. It imports the ADR corpus, applies it to a fresh memory file, and shows the WARN and PASS verdicts end-to-end.

## Related reading

- governing Claude Code workflows with the PreToolUse hook
- architectural governance in GitHub Actions
- governance violation reference