## 1. Capture current behavior (golden fixtures) - [x] 1.1 For each of the 4 bash hooks (`session_start.sh`, `session_context.sh`, `post_tool_use_write.sh`, `session_end.sh`), write a golden fixture: known stdin JSON → snapshot of side effects (journal append content, rebuild-stamp invalidation, touched-paths temp file contents, parsed config env vars) - [x] 1.2 Store fixtures under `cc-os/plugins/memory/tests/fixtures/` with one subdirectory per hook - [x] 1.3 Confirm each fixture can be run against the current bash hook and produces the expected snapshot output ## 2. Move plugin source into cc-os (no behavior change) - [x] 2.1 Copy `~/.claude/plugins/memory/` verbatim into `cc-os/plugins/memory/` under git (bash hooks, config.yaml, skills — exactly as-is) - [x] 2.2 Commit to git; confirm `git status` shows only the new `plugins/memory/` tree, no diffs to existing files - [x] 2.3 Do NOT yet repoint the marketplace or change any hook behavior — this establishes the seam only ## 3. Port to Python deep module - [x] 3.1 Implement `config.py`: `load_config() -> Config` frozen dataclass; handles YAML parse, path expansion, defaults, missing file — replaces all 3 inline parsers - [x] 3.2 Implement `hook_io.py`: `read_input() -> HookInput` dataclass (session_id, cwd, file_path, reason); replaces all 4 inline stdin parsers and the `python3`-vs-`jq` inconsistency - [x] 3.3 Implement `session_state.py`: `record_touch(session_id, path)` / `read_touches(session_id) -> list[str]`; encapsulates the `/tmp/claude-vault-touched-$SESSION_ID` temp-file contract (file still exists by necessity — separate process invocations; the win is an explicit named contract) - [x] 3.4 Implement thin hook entry points: `hooks/session_start.py`, `hooks/session_context.py`, `hooks/post_tool_use_write.py`, `hooks/session_end.py` (vault journal only) - [x] 3.5 Implement `hooks/memsearch_sync.py` as a separate SessionEnd hook entry (split from session-end); preserve exact ADR-015 sync behavior (auto-commit+push to `forgejo.swansoncloud.com/jared/memsearch`) - [x] 3.6 Wrap every `main()` in try/except: uncaught exceptions log to stderr and exit 0 (fail-open invariant) ## 4. Verify parity against golden fixtures - [x] 4.1 Run each Python hook entry point against the golden fixtures from task 1; assert output is identical to the bash snapshots - [x] 4.2 Fix any divergences; do NOT proceed to cleanup or cutover until all fixtures pass - [x] 4.3 Only after fixture parity is confirmed: clean up any dead code, simplify, refactor ## 5. Cut over marketplace to cc-os source (LAST functional task) - [x] 5.1 Verify the exact mechanism to repoint the `local-plugins` marketplace (source-path change vs symlink vs re-registration) — do not assume; confirm against current Claude Code plugin system behavior - [x] 5.2 Repoint `local-plugins` marketplace entry for `memory` to `cc-os/plugins/memory/` - [x] 5.3 Update `~/.claude/settings.json` hook entries to invoke the Python scripts - [x] 5.4 Start a new Claude Code session; confirm memory plugin loads from cc-os path and all hooks fire correctly ## 6. Documentation and ADR - [x] 6.1 Add ADR-016 to `docs/memory-system/03-architecture-decisions.md` recording the three decisions: source location, module shape (deep functions vs OO hierarchy), and memsearch-sync split (relocation not reversal of ADR-015) - [x] 6.2 Update `CLAUDE.md` Implemented Components section: plugin source pointer changed to `cc-os/plugins/memory/`; update hook language from bash to Python - [x] 6.3 Mark this change done in `docs/memory-system/04-build-plan.md` and update build plan status