Skip to content

fix(brains): re-inject the core prompt after Claude Code compaction [BRNS-MCPWEB-022] - #24

Merged
olegshmuelov merged 1 commit into
mainfrom
fix/mcpweb-022-compact-hook
Aug 9, 2026
Merged

fix(brains): re-inject the core prompt after Claude Code compaction [BRNS-MCPWEB-022]#24
olegshmuelov merged 1 commit into
mainfrom
fix/mcpweb-022-compact-hook

Conversation

@olegshmuelov

Copy link
Copy Markdown
Contributor

Claude Code fires SessionStart with source=compact after auto and manual compaction, but the Claude hook map matched only startup|resume|clear — so a compacted session never re-received core.md, and the brains rules survived only as whatever the compaction summary kept. SessionStart is the core prompt's only delivery path. The Codex map has carried compact since it was introduced; the asymmetry was drift, not intent.

What changed

  • plugins/brains/hooks/claude-hooks.json — the SessionStart matcher gains compact, matching the Codex map.
  • tests/plugin-contract/run.ts — the pinned CLAUDE_HOOK_EVENTS matcher moves in lockstep (two-edit change by design; the JSON-only edit fails the suite at the matcher pin — verified).
  • Both plugin manifests 2.8.0 → 2.8.1 (patch, per the delivery guard's convention).

Verification

  • All three suites green (plugin-contract, inbox-v2 32/32, tool-error 14/14); generated-artifact-guard OK.
  • Live A/B on real compacted sessions: a control tree (matcher reverted, proven one-line-different) gets zero post-boundary re-injection; this tree delivers exactly one core.md + operator-layer block after each of two consecutive compactions — re-injection happens and does not accumulate. The resume-fired duplicate is dropped by the CLI's own SessionStart dedupe.
  • Matcher and compact-firing semantics confirmed identical by inspection on 2.1.220 (CI's pin) and 2.1.226.

Blast radius: no new command or payload — the existing SessionStart hook just runs on one more documented source value. Second-run side effects on compaction (device re-report, pending-prompt re-surface, drift nudge) are pre-existing Codex-client behavior, unchanged here.

Ticket: BRNS-MCPWEB-022

Claude Code fires SessionStart with source=compact after auto and manual
compaction, but the Claude hook map matched only startup, resume and clear, so
a compacted session never re-received core.md — it survived as whatever the
compaction summary happened to keep. SessionStart is the core prompt's only
delivery path, and the Codex map has carried compact all along.

The contract test pins this matcher verbatim, so the constant moves with the
JSON.

@nir-ssvlabs nir-ssvlabs left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Four one-line edits, but two of them are the kind that only look right — I checked both against the tree rather than the description.

The delivery ladder is clean, which is the thing this repo's guard exists for. main is at 2.8.0, and this goes to 2.8.1 on both manifests — strictly forward, aligned, patch-shaped for a fix(…). Worth noting the ordering hazard I raised on #23 resolved correctly on its own: #22 (2.7.1) merged at 09:57, #23 (2.8.0) at 10:34, so neither became a downgrade and this bump sits cleanly on top.

The asymmetry claim is accurate, not a rationalisation. CODEX_HOOK_EVENTS.SessionStart was already pinned to startup|resume|clear|compact, and hooks.json carries the same matcher — so Claude was genuinely the drifted side, and this restores parity rather than inventing a new behaviour. The lockstep JSON + pin edit is the right shape: the matcher is pinned whole, so the JSON-only edit really does fail at the pin.

The blast-radius claim holds for the client that's actually changing. This is where I'd expect a fix like this to hide something: compact is a new trigger for Claude, so brains-start.sh now runs at a moment it never did. The description frames the second-run side effects (device re-report, pending-prompt re-surface, drift nudge) as pre-existing Codex-client behaviour — I checked whether any of them live in the shared script, and they don't. It is 50 lines with zero network calls: cat core.md, then optionally cat the operator USER.md. So on the Claude path the entire effect of this change is re-emitting two files' text — no request, no state mutation, nothing to double-fire. That is what makes the live A/B result ("one block per compaction, no accumulation") the expected outcome rather than a lucky one.

Nothing else to raise. The A/B against a proven one-line-different control tree is the right way to evidence a hook-firing change — inspection alone can't tell you whether the CLI actually fires compact for that matcher.

Merge: ✅ ready — BLOCKED is only the missing approval (REVIEW_REQUIRED, 0 unresolved threads, all suites + generated-artifact-guard green); this clears it.

@olegshmuelov
olegshmuelov merged commit ae36d65 into main Aug 9, 2026
4 checks passed
@olegshmuelov
olegshmuelov deleted the fix/mcpweb-022-compact-hook branch August 9, 2026 11:58
@nir-ssvlabs

Copy link
Copy Markdown

Correcting my review above — one claim in it is wrong, and it's the blast-radius one.

I wrote that brains-start.sh is "50 lines with zero network calls" and that the whole effect of adding compact was "re-emitting two files' text — no request, no state mutation, nothing to double-fire."

Not right. Line 48 delegates:

[ -x "$LIB" ] && "$LIB" startup "$SESSION"   # LIB=hooks/lib/brains-inbox.sh

brains-inbox.sh carries four curl calls and hits devices, inbox/claude and ack. I grepped this file for curl, got zero, and stopped at the file boundary instead of following the delegation.

So compact does run the device report + inbox pull + ack on every compaction — not just two cats. That doesn't change the verdict (it's the same set already running on startup|resume|clear, and your A/B showed no accumulation), but the risk I signed off on was larger than I described, and anyone reading my review for the blast radius should have the accurate version. Found it while reviewing #25, whose description states these three effects correctly.

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.

2 participants