neuralmind.uk / Keep decision memory honest across commits Edit this page on GitHub ↗

Keep decision memory honest across commits

Best for: teams, and agents, that record architecture decisions with neuralmind decisions record or the MCP decision tools, and want a decision to stop steering edits once the code it describes has moved on.

Primary goal: a decision goes STALE as soon as a commit changes what it describes, your agent is warned before it edits that code, and a decision that still holds is one command away from ACTIVE again (v4.6.0+).

A recorded decision is a claim about code at a point in time: “sessions live in Postgres because…”. Once someone moves sessions to Redis, the rationale is history, and an agent that still trusts it will “fix” the new code back toward the old design. Before v4.6.0 a decision went stale only when someone ran neuralmind decisions invalidate. Now the commit history retires it.


1. Set up once

neuralmind init-hook .       # post-commit: decisions scan, then index rebuild
neuralmind install-hooks .   # Claude Code: the PreToolUse stale-decision guard

On a checkout where you ran init-hook before v4.6.0, run it again: it replaces its managed block in .git/hooks/post-commit in place and leaves other tools’ hook lines alone.

2. Record a decision when you make it

neuralmind decisions record \
  --title "Sessions live in Postgres" \
  --rationale "One datastore to back up and fail over; session reads are a small share of load" \
  --files auth/session.py auth/middleware.py

Agents can do the same over MCP with neuralmind_record_decision. Name files relative to the project root (absolute paths work too). Later questions find it by meaning as well as by its words (v4.8.0+): see Find the decision behind the code when you don’t know its words.

Recording before you commit is fine. Recording fingerprints each file with its git blob id. When the commit stores exactly those blobs, it carries the code the decision describes, so it leaves the decision ACTIVE, however quickly you commit. Edit one of those files again first and the commit marks it STALE.

3. Commit: stale decisions are reported

Months later someone moves sessions to Redis and commits:

$ git commit -am "Move sessions to Redis"
[neuralmind] 1 decision(s) marked STALE by commit 3f9c2ab:
  - Sessions live in Postgres (5b1e0c7a-…) — commit 3f9c2ab changed auth/session.py since this decision was recorded
  Review: neuralmind decisions audit --stale   Still valid? neuralmind decisions restore <id>
[neuralmind] Rebuilding neural index...

The reason is kept on the decision itself (Marked STALE: commit 3f9c2ab changed auth/session.py since this decision was recorded in its evidence), and any decision that lists it in dependency_constraints goes STALE with it.

4. Your agent is warned before it edits

The next time Claude Code is about to edit auth/session.py, the PreToolUse guard adds this to its context. It never blocks the edit:

[neuralmind stale-guard] 1 decision(s) governing auth/session.py are no longer ACTIVE. Their rationale may not hold — verify before relying on them:
- [STALE] Sessions live in Postgres (id 5b1e0c7a-…, confidence 1.00, updated 2026-10-03): One datastore to back up and fail over; … — commit 3f9c2ab changed auth/session.py since this decision was recorded
If a STALE decision still holds after you check the code, `neuralmind decisions restore <id>` re-anchors it to HEAD.

5. Still true? Restore it. Not true? Retire it.

neuralmind decisions audit --stale                                     # what went stale
neuralmind decisions restore 5b1e0c7a-…                                # still holds: ACTIVE again, anchored to HEAD
neuralmind decisions invalidate 5b1e0c7a-… --reason "sessions moved to Redis"   # no longer holds
neuralmind decisions record --title "Sessions live in Redis" …        # and record the new one

restore and invalidate take the full id that scan, audit and the guard print.

How the scan decides

Situation Result
A commit stores a file the decision names differently from how the decision saw it STALE. Any change counts; there is no diff analysis
The commit stores every changed file exactly as the decision saw it (its fingerprints, taken when it was recorded, amended or restored) Stays ACTIVE: this commit carries the decision
The decision is anchored to the new commit itself Stays ACTIVE
The decision has no fingerprint for a changed file (recorded before v4.6.0, or the file didn’t exist yet) STALE
A file is deleted or renamed STALE (both sides of a rename count)
A merge commit Everything it brought into the branch counts
Project in a subdirectory of the repository, or a linked worktree Works; init-hook names the project by its path from the repository root
Another decision depends on a stale one STALE too (cascade)

Run it by hand any time with neuralmind decisions scan . (--json for scripts). It never creates a decision store in a project without one, and it always exits 0, so it can’t fail the commit it follows.

Limits

Turn it off

NEURALMIND_DECISION_SCAN=0 makes the scan a no-op. To remove it from the git hook, delete the neuralmind decisions scan line from the managed block in .git/hooks/post-commit.