# File anchoring and the Stop hook

> How mmw-agent ties facts to local files, notices when they change at search time, and reminds Claude Code to save the outcome of a turn.

Facts in memory often come from a file: a contract, a note, a config. If the file is corrected later and the memory record is not, the agent keeps confidently repeating the old version. The MMW server cannot see your files, so the local agent, **mmw-agent 0.1.4** and later, does this check.

On this page:

1. how to anchor a fact to a file without computing anything by hand;
2. how search notices that the file changed;
3. how the Stop hook keeps Claude Code from finishing without saving the outcome.

## Anchoring on remember

Put the file path in `source_id`, and that's it. The agent computes the file's SHA-256 and sends it as `source_hash`:

```text
Remember in MMW: the operator is a private individual. Source: site-audit/NOTIFICATION.md
```

```json title="what is sent to the server"
{
  "content": "the operator is a private individual",
  "source_id": "site-audit/NOTIFICATION.md",
  "source_hash": "sha256:5f1c…"
}
```

- Paths are resolved **against source roots**: by default, the folder the client started the agent in (for Claude Code, the project folder). Set your own roots with `MMW_SOURCE_ROOTS` (several paths separated by `:` on Linux and macOS, `;` on Windows).
- Files outside the roots are never read or hashed. An absolute path works too if it is inside a root.
- IDs that do not look like a path (`session:…`, `https://…`, `owner-note`) are left alone.
- If `source_hash` is already set, the agent does not change it.
- **File contents never leave your computer**; only the hash is sent.

## The check on search

On every search the agent re-hashes the source files of the records found and adds a `local_source` field:

| `local_source` | Meaning | `status` |
| --- | --- | --- |
| `unchanged` | the file is the same as when saved | unchanged |
| `changed` | the file changed after saving | `stale` |
| `missing` | the file no longer exists | `stale` |

`conflict` is the louder status and is never replaced with `stale`. Records without a source file are left as they are.

The check only works through mmw-agent on the computer that has the files. In claude.ai, ChatGPT and other clients without the agent, `local_source` does not appear. To make a change visible there too, save the corrected fact again under the same `fact_key`: the new version ranks first and the old one gets `superseded_by`. More in [Conflicts and summaries](/memory/conflicts-and-summaries/).

## Stop hook for Claude Code

`mmw-agent hook-stop` is a hook for the Stop event. When Claude Code is about to end a turn, the hook checks whether files in the git working tree changed during this session **after the last `remember` call**. If they did, the turn does not end: Claude gets the list of files and a request to save the decisions and facts, with the path as `source_id`, reusing the earlier `fact_key` for corrections.

1. Open `~/.claude/settings.json` (all projects) or `.claude/settings.json` in a project.

2. Add the hook:

   ```json
   {
     "hooks": {
       "Stop": [
         {
           "hooks": [
             {
               "type": "command",
               "command": "uvx --from https://app.mmwhub.tech/downloads/mmw-agent/mmw_agent-0.1.4-py3-none-any.whl mmw-agent hook-stop"
             }
           ]
         }
       ]
     }
   }
   ```

3. Restart Claude Code.

How the hook behaves:

- **It blocks at most once in a row.** If Claude decides there is nothing to save, the second Stop goes through (`stop_hook_active`), so it never loops.
- **Only this session counts.** Files changed before the session started or before the last `remember` are ignored.
- **Outside a git repository it does nothing.**
- **It sends nothing.** The check is local: git and the Claude Code session transcript.
- To switch it off for a while, set `MMW_STOP_HOOK=off`.

## What it does not do

- It does not watch files in the background: a change is noticed on search or at the end of a turn, not when the file is saved.
- It does not fix records by itself: the hook asks the agent to save a new version; the decision stays with the agent and the person.
- It does not check facts saved without `source_id`. Always give the source when a fact comes from a file.

## What's next
