cc-os/openspec/changes/archive/2026-06-05-add-memory-plugin/tasks.md

9.2 KiB

1. Plugin directory and config

  • 1.1 Create plugin directory structure: ~/.claude/plugins/memory/ with hooks/ and skills/ subdirectories
  • 1.2 Write ~/.claude/plugins/memory/config.yaml with configurable fields: vault path (~/Documents/SecondBrain), Graphify output dir, Ollama model (qwen25-coder-7b-16k), num_ctx (8192), stale threshold (7 days), and env vars (OLLAMA_FLASH_ATTENTION=1, GRAPHIFY_OLLAMA_NUM_CTX=8192, GRAPHIFY_OLLAMA_KEEP_ALIVE=5)
  • 1.3 Write a README.md for the plugin documenting: the reasoning_effort:"none" patch requirement, the pinned Graphify version (v0.8.31), the Modelfile-baked context approach (qwen25-coder-7b-16k), and how to verify the patch is present after any pip upgrade

2. SessionStart hook

  • 2.1 Write ~/.claude/plugins/memory/hooks/session-start.sh: read stdin JSON via jq (fields: .cwd, .source); source config; check ~/.cache/graphify/vault-rebuild.stamp mtime vs. threshold — if stale or absent AND no lock file at ~/.cache/graphify/vault-rebuild.lock, spawn nohup graphify extract <vault-path> --backend ollama --model <model> --force >> <logfile> 2>&1 & as a detached background process, write the lock file (background process removes it on completion), and continue immediately; do NOT wait for the rebuild (SessionStart blocks the session — it must return sub-second on the synchronous path). Log that a background rebuild was triggered.
  • 2.2 Extend session-start.sh: inject vault god-node summary — read from GRAPH_REPORT.md or equivalent at the configured output dir; assemble context string (compact "map of what's known" block, not raw graph.json)
  • 2.3 Extend session-start.sh: inject convention/* note summaries — attempt graphify query "convention" --budget 500; fall back to grep -rl "convention/" <vault-path> | xargs grep -h "^summary:" if graph query returns empty; omit section silently if no convention notes found
  • 2.4 Extend session-start.sh: inject episodic journal pointer — compute today's journal path (<vault-path>/journal/YYYY-MM-DD.md) and add as a one-line pointer; inject project graph path (<project-root>/graphify-out/graph.json) if that file exists (read .cwd from stdin JSON as working directory base; use git rev-parse --show-toplevel from there or $CLAUDE_PROJECT_DIR convention)
  • 2.5 Emit all injected content to stdout as {"additionalContext": "<assembled-text>"} JSON and exit 0 — this is the confirmed Claude Code mechanism for hook-to-model context injection (Claude Code hooks documentation)
  • 2.6 Test session-start.sh standalone (not via Claude Code harness): supply mock stdin JSON (echo '{"cwd":"/tmp","source":"startup"}' | ./session-start.sh); run with a clean stamp, a stale stamp (confirm background spawn, no block), a lock file already present (confirm no duplicate spawn), and a missing vault — confirm each path behaves as specified in memory-plugin-hooks/spec.md

3. PostToolUse hook

  • 3.1 Write ~/.claude/plugins/memory/hooks/post-tool-use-write.sh: source config; read stdin JSON via jq — extract FILE_PATH=$(jq -r '.tool_input.file_path') and TOOL_NAME=$(jq -r '.tool_name'); guard clause — skip if $FILE_PATH does not match <vault-path>/**/*.md; if it matches, run graphify update --file "$FILE_PATH"; log error but do NOT block on non-zero exit (exit 0 always); also append $FILE_PATH to per-session temp log (see task 4.2)

    Deviation (2026-06-05): graphify update --file does not exist in Graphify v0.8.31. The correct incremental update for markdown/doc files is graphify extract <vault-path> --update --backend ollama --model <model> which uses SHA-256 content hashing to skip unchanged files. Running this synchronously in PostToolUse would block on Ollama. Adopted approach: PostToolUse deletes ~/.cache/graphify/vault-rebuild.stamp (invalidates freshness). Next SessionStart detects the missing stamp and spawns graphify extract --update as a detached background process, refreshing only changed files. Graph freshness is deferred by at most one session start, not immediate.

  • 3.2 Test post-tool-use-write.sh standalone: supply mock stdin JSON (echo '{"tool_name":"Write","tool_input":{"file_path":"<vault-path>/test.md"}}' | ./post-tool-use-write.sh); test with a vault .md path (confirm graphify update fires), a non-vault path (confirm nothing fires), and a path where graphify returns non-zero (confirm error is logged, script exits 0)

4. SessionEnd hook

  • 4.1 Write ~/.claude/plugins/memory/hooks/session-end.sh: read stdin JSON via jq — extract SESSION_ID=$(jq -r '.session_id') and REASON=$(jq -r '.reason'); source config; compute today's journal path; if file does not exist, create it with minimal frontmatter (summary:, scope/global, type/log); append a timestamped entry with: current project (from $CLAUDE_PROJECT_DIR or git rev-parse --show-toplevel), vault notes touched this session (read from temp log at /tmp/claude-vault-touched-$SESSION_ID — see task 4.2), UTC timestamp. Note: SessionEnd has no decision control (exit code ignored); use for cleanup/logging only.
  • 4.2 Extend post-tool-use-write.sh to append successfully-updated vault note paths to a per-session temp file /tmp/claude-vault-touched-$SESSION_ID where SESSION_ID is read from stdin JSON via jq -r '.session_id'; session-end.sh reads this same file using its own stdin session_id. (Confirmed available: session_id is a field on stdin JSON for both PostToolUse and SessionEnd — Claude Code hooks documentation.)
  • 4.3 Test session-end.sh standalone: supply mock stdin JSON (echo '{"session_id":"test-123","reason":"exit"}' | ./session-end.sh); run with notes in the temp file at /tmp/claude-vault-touched-test-123 (confirm journal entry created with paths), run with no temp file (confirm minimal entry is still appended), run twice in one day (confirm append-only, no overwrite)

5. Skills authoring

  • 5.1 Write ~/.claude/plugins/memory/skills/memory-query.md: cover all patterns from memory-plugin-skills/spec.md — god-node-first discipline, graphify query/path/explain with --budget/--dfs/--graph, cross-client lookups, explicit call-out that tag-based graph traversal is unverified (ADR-014), episodic questions → memsearch
  • 5.2 Write ~/.claude/plugins/memory/skills/memory-write.md: cover all rules from the spec — evergreen vs. ephemeral test, required frontmatter contract (summary written now, scope/, at least one facet tag), vault-not-repo rule, note that PostToolUse hook fires automatically on vault writes
  • 5.3 Write ~/.claude/plugins/memory/skills/memory-reorganize.md: cover the spec — plan-mode-only rule, three triggers (duplicate, recurrence-promotion, oversized note), consolidation procedure, --force rebuild requirement after reorganization, ghost-node explanation
  • 5.4 Register the three skills in the plugin manifest (or ~/.claude/settings.json) so they are available as on-demand skills in Claude Code sessions
    • Note (2026-06-05): Skills in ~/.claude/plugins/memory/skills/ require a marketplace entry to be auto-discovered via enabledPlugins. The .claude-plugin/plugin.json manifest is in place; a marketplace registration in ~/.claude/settings.json extraKnownMarketplaces pointing to ~/.claude/plugins/ is needed to complete skill auto-loading. Hooks fire independently of this.

6. Hook registration

  • 6.1 Register session-start.sh as a SessionStart hook in ~/.claude/settings.json
  • 6.2 Register post-tool-use-write.sh as a PostToolUse hook for Write and Edit tool calls in ~/.claude/settings.json
  • 6.3 Register session-end.sh as a SessionEnd hook in ~/.claude/settings.json

7. End-to-end validation against fixture set (ADR-013)

  • 7.1 Start a Claude Code session in the fixture project — confirm SessionStart injects god-node list, at least one convention summary (if present), journal pointer, and project graph path
  • 7.2 Write a test vault note during the session — confirm PostToolUse fires graphify update --file (verify from hook log or graph.json mtime)

    Clarification (2026-06-05): PostToolUse fires stamp invalidation (deletes ~/.cache/graphify/vault-rebuild.stamp), triggering deferred incremental update on next SessionStart, per deviation note in task 3.1.

  • 7.3 End the session — confirm SessionEnd appended a journal entry to <vault-path>/journal/YYYY-MM-DD.md with the note paths touched
  • 7.4 Trigger a stale rebuild: backdate the stamp file (or delete it) and restart the session — confirm SessionStart returns immediately (no freeze), background rebuild process spawns (check process list / logfile), lock file appears then clears, stamp is updated when rebuild completes; start a second concurrent session during rebuild and confirm the lock prevents a duplicate spawn
  • 7.5 Test the convention-injection fallback: temporarily remove the vault graph and restart the session — confirm the grep fallback surfaces convention summaries (or the section is cleanly omitted if none exist)
  • 7.6 Run each of the three skills (/memory-query, /memory-write, /memory-reorganize) in a session and confirm the guidance loads and is coherent with the fixture set context