# Verifying the auto-memory flow

Augment now *enforces* the memory loop through host lifecycle hooks rather than
relying on the agent to remember to call the MCP tools:

| Event              | Hook command                       | Effect |
| ------------------ | ---------------------------------- | ------ |
| `SessionStart`     | `augment hook session-start`       | Warms the daemon and registers the project. |
| `UserPromptSubmit` | `augment hook user-prompt-submit`  | Recalls relevant memory and injects it as `additionalContext` **before** the model sees the prompt. |
| `PreToolUse`       | `augment hook pre-tool-use`        | Recalls **additional** memory keyed to the matched tool action (the edited file / the Bash command) and injects it as `additionalContext`. Matcher-scoped to `Edit\|Write\|Bash` to bound the hot path; injection-only (never blocks, gates, or rewrites a tool call). Uses a raised relevance floor (`min_score` 0.45 — above the 0.4 search default, calibrated on the real model because tool queries are command/path-shaped, not prose) and injects each distinct query at most once per session. |
| `Stop`             | `augment hook stop`                | Blocks the turn **once** with a directive to upsert a memory, then allows the stop (loop-guarded per turn). |

`PreToolUse` fires before **every matched** tool call, so it is the only hook with a tool-name
`matcher` (the others fire once per prompt/turn). Two host nuances: on Claude the injected text
rides alongside the *tool result* on the next model request (it supplements, rather than precedes,
the action); on Codex builds older than ~0.124.0 `PreToolUse` `additionalContext` is rejected and
silently dropped (the tool still runs). It is purely additive — `UserPromptSubmit` remains the
guaranteed memory path on both hosts.

The same `hooks/hooks.json` ships in both the Claude Code and Codex plugins
(Codex copied Claude's event names + stdin/stdout contract), so one set of
handlers serves both hosts.

This doc is the test process. Run the layers top-to-bottom; each is cheaper and
more isolated than the one below it.

## 1. Automated (no network, no host) — `npm test`

```sh
npm test
```

Covers:
- `test/hooks.test.ts` — the stdin→stdout contract of every hook event
  (UserPromptSubmit envelope, PreToolUse tool-query derivation + injection-only
  envelope + 0.45 floor + per-session dedupe, Stop block-once loop guard,
  fail-open paths).
- `test/recall.test.ts` — recall degrades to `""` on any failure (a hook must
  never break the agent).
- `test/cli.test.ts` — the `recall` and `hook` CLI commands.
- `test/install.test.ts` — the installer writes `hooks/hooks.json` for both hosts.
- `test/integration/memory-flow.test.ts` — a planted memory flows
  upsert → index → `recall()` → UserPromptSubmit **and** PreToolUse envelopes, against a **real**
  `AugmentService` (real store + sqlite index), using the deterministic hash
  embedder. Proves the wiring end-to-end without a model download.

## 2. CLI smoke (real daemon + real embeddings, one machine)

Build first, then drive the real daemon by hand. Use a throwaway memory root so
you don't pollute your real memories:

```sh
npm run build
export AUGMENT_MEMORY_ROOT="$(mktemp -d)"      # PowerShell: $env:AUGMENT_MEMORY_ROOT = (New-Item -ItemType Directory -Path $env:TEMP\augver -Force).FullName

# Plant a memory (project_id 1 after the first init), then recall it.
node ./dist/bin/augment.js recall "the deploy pipeline"      # prints recalled text (empty until something is stored)

# Exercise the hook handlers exactly as a host would (JSON on stdin):
echo '{"user_input":"fix the deploy pipeline","cwd":"."}' | node ./dist/bin/augment.js hook user-prompt-submit
#   -> {"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"## Augment memory ..."}}  (or nothing if no match)

# PreToolUse keys the query off the tool action (Bash -> command, Edit/Write -> file_path):
echo '{"tool_name":"Bash","tool_input":{"command":"deploy the pipeline"},"cwd":"."}' | node ./dist/bin/augment.js hook pre-tool-use
#   -> {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"## Augment memory ..."}}  (or nothing if no match)
echo '{"tool_name":"Read","tool_input":{"file_path":"x"}}' | node ./dist/bin/augment.js hook pre-tool-use
#   -> (empty)  Read isn't in the installed matcher; even if invoked it derives a query but stays injection-only

echo '{"session_id":"s","prompt_id":"p"}' | node ./dist/bin/augment.js hook stop
#   -> {"decision":"block","reason":"Before ending this turn, record durable memory ..."}
echo '{"session_id":"s","prompt_id":"p"}' | node ./dist/bin/augment.js hook stop
#   -> (empty)  second stop for the same turn is allowed — proves the loop guard
```

The first `recall`/`hook user-prompt-submit` call auto-starts the daemon and, on
a cold machine, downloads the bge-small model — so the very first run is slow.
This is real-model retrieval; ranking quality (not just wiring) is what you're
eyeballing here.

Two footnotes on the examples: they omit `session_id`, which deliberately skips
the PreToolUse once-per-session dedupe — include one to demo it. And the Stop
loop-guard marker persists in the OS tmpdir, so re-running the stop example
later with the same `session_id`/`prompt_id` yields empty on the *first* call
too — use fresh ids per run.

For a binding version of the ranking-quality check, `npm run test:model` runs
the pinned real-bge abstention/recall tripwires
(`test/real-model-abstention.model.ts`) — what this layer can otherwise only
eyeball.

## 3. Real project (host-level hook firing)

1. Install into a repo (or user scope):
   ```sh
   npm exec --yes --package @fingerskier/augment -- augment install all --scope repo --memory-root "<your shared memory root>"
   ```
2. Confirm the plugin is actually installed/enabled — hooks only fire when the
   plugin is active:
   - **Claude Code:** `/plugin` → `augment` listed and enabled. The installer
     best-effort-registers it via the `claude` CLI; if that was skipped, run the
     printed `/plugin marketplace add … && /plugin install …` commands.
   - **Codex:** plugin-shipped hooks need a **one-time trust** — run `/hooks` and
     approve the augment hooks. (Managed/enterprise distribution can pre-trust;
     a plain plugin install cannot.)
3. Observe the loop on a real task:
   - **Inject:** start a session and give a task that matches something in your
     memory. The recalled block ("## Augment memory (recalled for this task)")
     should appear in the model's context — confirm it influenced the answer.
   - **Capture:** finish the task. The Stop hook should prompt the agent to
     `upsert` a WORK/ARCH/ISSUE/TODO/SPEC/INFO memory; confirm a new file appears under
     your memory root and that `augment recall` surfaces it next time.

## Known caveats (logged, not blockers)

- **Hook startup cost (resolved).** Hooks now invoke the install-time-provisioned
  runtime directly (`node <prefix>/node_modules/@fingerskier/augment/dist/bin/augment.js
  hook <event>`, tens of milliseconds) — the old `npm exec --yes` form paid a
  multi-second npm bootstrap per event. Residual caveat: provisioning is
  best-effort. If npm was missing at install time the installer prints a manual
  `npm install --prefix <prefix> @fingerskier/augment` command and hooks fail
  open (silent no-ops) until it is run. MCP uses the same provisioned tree via
  direct `node …/augment-mcp.js` (no `npm exec` chain) after install.
- **Claude hook activation depends on plugin install.** The MCP server is also
  direct-registered (so the tools always exist), but the hooks live in the plugin;
  if the plugin isn't installed, the loop degrades to the CLAUDE.md prose guidance.
- **Retrieval floor calibration (resolved).** The `(cos+1)/2` mis-normalization
  is fixed by an empirically-anchored cosine rescale (`SEMANTIC_COSINE_BASELINE`
  0.33), and abstention is now proven on the real model by `npm run test:model`.
  Remaining retrieval-quality follow-ups (ordinary-upsert credential warnings
  and HF revision pinning) are tracked in
  `.council/memory/retrieval-quality-roadmap.md` and
  [ROADMAP.md](../ROADMAP.md).
