Repository navigation
Filter sidecar Haiku flows so session title generation stops leaking into the transcript - #25
Merged
Conversation
Juliusolsson05
force-pushed
the
fix/claude-title-haiku-sidecar-leak
branch
from
April 27, 2026 07:53
7179472 to
72d9fb8
Compare
Bumps the claude-code-headless submodule to pick up the
sidecar-flow filter added in
claude-code-headless@a91e4a9, then opts the proxy adapter into
filtering by passing a `getSessionModel` callback.
The callback returns a constant non-Haiku model id by default
(`'claude-opus-4-7'`) because cc-shell does not yet parse the
user's primary model from Claude Code's screen header. The exact
string doesn't matter; the adapter only uses it for the
`/haiku/i` pattern test, never as an authoritative model id.
Users running Haiku as their primary model can override via the
`CC_SHELL_PRIMARY_MODEL` env var (set it to a Haiku model id to
disable filtering).
Without this wiring the headless-side filter is inert and the
production bug — Claude Code title-generation calls leaking as
phantom `{"title": "..."}` ghost entries at the bottom of the
transcript — would still reproduce.
Follow-up TODO carried in the comment: replace the constant
default with screen-header parsing so the env-var escape hatch
becomes redundant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Juliusolsson05
force-pushed
the
fix/claude-title-haiku-sidecar-leak
branch
from
April 27, 2026 12:34
72d9fb8 to
bc5bbc7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Claude Code v2.1.x makes a small auxiliary
/v1/messagescall at session start to generate a 3-7 word session title viaqueryHaiku()(vendorutils/sessionTitle.ts). The proxy adapter currently treats it as a normal assistant turn —turn_started+text_delta+block_completedall fire on the SemanticChannel — and the renderer mints a ghost entry for the JSON-shaped output. Because Claude Code never writes auxiliary calls to the JSONL rollout, that ghost is never superseded, orphans after its 3 s TTL, and gets rendered as a phantom{"title": "..."}message at the bottom of the transcript.The smoking gun, decoded straight from a captured proxy log:
— a Haiku sidecar inside an Opus session, exactly matching
generateSessionTitle()in the vendor source.The actual fix lives in
claude-code-headless(submodule SHA bumped from7984e29→35bb19c, branchfix/sidecar-haiku-leak, PR Juliusolsson05/claude-code-headless#3). The adapter now demotes a flow to the existing'secondary'attribution state atmessage_startwhen the flow's model matches/haiku/iAND a caller-suppliedgetSessionModel()returns a model that does not. The rule reads "filter Haiku flows on non-Haiku sessions" — catches every known auxiliary Haiku call (title gen, compaction summaries, hook agents, teleport title-and-branch) without false-positiving Haiku-as-primary users.This PR's cc-shell side is the wiring: pass-through of the new
getSessionModelandsidecarModelPatternoptions throughClaudeCodeHeadlessOptions.proxy, and inclaudeSession.tsan opt-in that returns a non-Haiku constant by default with aCC_SHELL_PRIMARY_MODELenv-var escape hatch for users running Haiku as their primary model.Dependency
This PR's submodule pointer references
35bb19con the headless repo. That commit lives onfix/sidecar-haiku-leakand is being reviewed in Juliusolsson05/claude-code-headless#3. The headless PR should land first so the submodule SHA is reachable onmainwhen this PR merges (otherwise the submodule pointer dangles on a feature branch).What's NOT in this PR
getSessionModel()returns the constant'claude-opus-4-7'because the model only matters for the/haiku/ipattern test, never as an authoritative model id. A TODO inclaudeSession.tsmarks where to drop in a real parser later..gitignorechange as a separate commit. The.worktrees/ignore rule is the second commit in the diff (9fa530b); it's small infra for the development workflow that produced this fix. Happy to split if you'd rather it be a standalone PR.Test plan
npx tsx packages/claude-code-headless/src/testing/verify-sidecar-haiku.ts— 13/13 cases greenturn_started, notext_delta, noblock_completed,flow_ignoredpublished)getSessionModelcallback → filter is inert (preserves pre-fix behaviour)tsc --noEmitforclaudeSession.ts,ClaudeProxyAdapter.ts,ClaudeCodeHeadless.ts, and the new test — cleannpm run devagainst this branch on a fresh Opus/Sonnet session, confirm the{"title": "..."}ghost no longer appears at the bottom of the transcriptCC_SHELL_PRIMARY_MODEL=claude-haiku-4-5-20251001set, confirm Haiku conversation turns still render🤖 Generated with Claude Code