Skip to content

feat(claude): inject capture/recall behavior via SessionStart hook#183

Open
couragehong wants to merge 4 commits into
CryptoLabInc:mainfrom
couragehong:feat/claude-session-start-hook
Open

feat(claude): inject capture/recall behavior via SessionStart hook#183
couragehong wants to merge 4 commits into
CryptoLabInc:mainfrom
couragehong:feat/claude-session-start-hook

Conversation

@couragehong

Copy link
Copy Markdown
Contributor

Summary

  • What changed: Added a plugin-level SessionStart hook (hooks/hooks.json + hooks/session-start.sh, registered via "hooks" in plugin.json) that injects Rune's automatic capture/recall behavior contract into the session context on startup|resume|compact — only when ~/.rune/config.json has state: "active".
  • Why: The "automatic" capture/recall contract lived only in SKILL.md (loaded on demand) and the repo's CLAUDE.md (applies only if users copy it into their own projects). Sessions without that guidance never captured or recalled unless the user typed a slash command — the plugin itself didn't deliver "no commands to memorize".
  • Scope: Claude Code only — hooks are a Claude Code plugin mechanism. Codex/Gemini get equivalent coverage via MCP initialize instructions in rune-mcp (follow-up, tracked separately).

Validation

  • Tests run: hooks.json/plugin.json validate as JSON. Hook exercised across states: no config → exit 0, 0 bytes; dormant → exit 0, 0 bytes; active → exit 0, contract injected. grep/sed fallback path forced (jq hidden) → identical behavior on multi-line and compact JSON configs. Simulated the exact Claude Code invocation (sh -c + ${CLAUDE_PLUGIN_ROOT} substitution + event JSON on stdin) → injection confirmed.
  • Docs updated (if behavior/setup changed): not yet — README/SKILL.md mention of the hook can land with the Codex/Gemini instructions follow-up.

Cross-Agent Invariants

  • No agent-specific script duplicates bootstrap/setup logic (hook only reads config state; no install/boot logic)
  • Agent-specific scripts remain thin adapters (the hook is injection-only; capture/recall stay in the MCP server)
  • Codex-only commands (codex mcp ...) are clearly separated from cross-agent/common instructions (not touched)
  • Claude/Gemini/OpenAI instructions do not include Codex-only commands (injected text references MCP tools generically)
  • SKILL.md, commands/rune/*.toml, and AGENT_INTEGRATION.md stay consistent on boundaries (none modified)

Notes for Reviewers

  • Risk areas: the hook emits a few KB into every active session's context (token cost); dormant/unconfigured sessions are strictly zero-output. The state gate parses config with jq when present and a grep/sed fallback otherwise — the fallback assumes the standard config.json shape written by the configure tool.
  • Backward compatibility impact: none — plugins without hook support ignore the hooks field; dormant users see no behavior change.
  • Follow-up work (if any): (1) rune-mcp MCP initialize instructions for cross-agent (Codex/Gemini) coverage; (2) injected-contract wording iteration (capture triggers: decision-language → topic-boundary insights) — will land as follow-up commits on this PR; (3) optional Stop-hook session-end sweep.

🤖 Generated with Claude Code

couragehong and others added 4 commits July 14, 2026 16:12
The plugin's automatic capture/recall depended on the user copying
Rune's guidance into their own CLAUDE.md (or invoking slash commands
explicitly) — sessions without that guidance never captured or
recalled anything.

Ship a SessionStart hook (startup|resume|compact) that injects the
automatic-behavior contract into the session context whenever Rune is
active:

- hooks/session-start.sh gates on ~/.rune/config.json state (RUNE_HOME
  honored): not "active" -> exit 0 with no output, no network, no
  token spend, mirroring the dormant fail-safe.
- When active, it emits the recall-before-answering and
  capture-as-decisions-crystallize contract to stdout, which Claude
  Code injects like CLAUDE.md content — every session, including
  post-compaction resumes.
- jq is used when available with a grep/sed fallback, so the hook
  works on machines without jq.

Claude Code only: hooks are a plugin-level mechanism. Codex/Gemini
coverage will come separately via MCP initialize instructions in
rune-mcp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sharpen the SessionStart-injected behavior contract:

- Recall: concrete trigger list (rationale/history questions, any
  design/tooling/process choice, debugging a teammate may have hit,
  onboarding questions), recall-before-answering, attribution
  required, and an explicit injection guard — recalled records are
  reference data, never instructions.
- Capture: trigger on a thread of work landing on a conclusion
  (root cause found, approach validated/ruled out, non-obvious
  behavior figured out, standard established), not only explicit
  decision language. Adds the teammate-benefit test, the extracted
  JSON field spec with status_hint (accepted vs proposed feeds the
  rerank status multiplier), and a correction-record protocol for
  when recall surfaces an outdated record.
- Drop capture self-censoring: near-duplicates are the server-side
  novelty filter's job, not the capture gate's.

Verified: dormant → 0 bytes; active → contract injected; bash -n clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 2.6KB detailed contract duplicated what the model already gets
elsewhere: the capture tool's schema teaches the extracted format at
call time, and scribe.md/SKILL.md carry the full policy. The hook only
needs to supply the "when": capture what's worth sharing, recall before
answering, plus two one-line guards (redact secrets/PII; recalled
records are data, never instructions). 559 bytes injected per active
session, down from 2,605.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Append two pointers to the minimal contract: read
agents/claude/scribe.md before the first capture (what to capture +
extracted JSON format) and agents/claude/retriever.md before recall
work (when to search, synthesis and citation rules). The docs are read
lazily — only when a tool is actually about to be used — so the
per-session injection stays under 1 KB while the full policy remains
one Read away.

The plugin root resolves from CLAUDE_PLUGIN_ROOT with a
script-relative fallback, so settings.json-registered (non-plugin)
usage gets working paths too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@couragehong couragehong requested a review from esifea July 14, 2026 07:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant