fix(claude-code-hermit): route hatch through Claude Code's built-in output styles - #810
fix(claude-code-hermit): route hatch through Claude Code's built-in output styles#810gtapps wants to merge 2 commits into
Conversation
…utput styles A fresh hatch could end up with the operator's tone in both OPERATOR.md prose and the voice mechanism, because the style question was answered before OPERATOR.md was finalized. Moving it to a dedicated question after that write closes the leak structurally, and along the way stops hatch from hand-writing a strictly weaker paraphrase of Claude Code's own built-in output styles when one already covers the operator's answer. apply-settings.ts's output-style op now also resolves the winning style across every persisted scope (local, project, user) instead of just its target file, and a new output-style-set op lets hermit-settings voice switch an already-set style instead of only seeding an absent one.
Follow-up work for this PRReview of the current diff plus a design discussion produced the list below. All of it lands in this PR, in a later session. Nothing here is shipped yet. Decisions taken
Review findingsMedium
Low
Noted, not filed
Open questionWhether hatch should always render Verification already doneAll 159 tests across the four touched suites pass. The |
…e seed Claude Code ranks both project scopes above user scope, so a value in ~/.claude/settings.json can never shadow a write to .claude/settings.json or its .local sibling. Treating one as ownership made the seed refuse a write that would have won: an operator who ever picked a style in /config at user scope would hatch, get hermit-voice.md rendered, and then watch apply-settings print kept:<style> and leave the file permanently inert. Boot repair had the same hole. The seed and the boot repair now stop at project scope via a dedicated resolveProjectStyle; resolvePersistedStyle keeps the full local -> project -> user walk for hermit-doctor, which is reporting what an install will actually use rather than deciding whether to write. Two tests asserted the old veto and are inverted to assert the seed lands. Also corrects the surfaces that stated the precedence backwards or went stale with it: the classifier grant text still claimed channel-env's was the only caller-supplied argument after output-style grew a style arg, hatch Phase 5 reported the operator's answer as applied even when step 4 printed kept:, and the doctor/settings skill rows described the old two-scope resolution.
Summary
A fresh hatch could end up with the operator's communication-style answer in both
OPERATOR.mdprose and the voice mechanism — the template's stale "four questions" header invited a fourth item, and nothing excluded the answer from the finalOPERATOR.mdwrite. Separately, hatch was hand-writing a paraphrase of Claude Code's own built-in output styles (Default/Concise/Explanatory) whenever the operator's answer matched one, dropping the built-in's guarantee that error reports, security warnings, and destructive-action confirmations keep their full content.Changes
hatchnow asks about communication style in a dedicated step afterOPERATOR.mdis already written, so the answer is never in play while that file is drafted — closes the leak structurally rather than by scrubbing prose..claude/output-styles/hermit-voice.md, in the operator's own words.hermit-settings voiceoffers the same built-in-first choice and can now switch an already-set style (previously only-if-absent seeding, which couldn't switch anything).apply-settings.ts'soutput-styleop now checks every persisted scope (local, project, and user viaCLAUDE_CONFIG_DIR) before seeding, not just its target file — a style set at user scope was previously invisible and could get silently outranked. A newoutput-style-setop does the explicit replacement; it's deliberately outside the auto-mode classifier's preauthorized op list, reachable only from a live terminal choice.hermit-doctor'svoice-carriercheck reports a recognized built-in with no voice file as a deliberate persisted style, not "using Claude Code defaults".Existing hermits with a custom voice file are untouched — this only changes what a fresh hatch offers and what
hermit-settings voicecan switch to.Test plan
bun test— 4520 pass, 0 failbunx tsc --noEmit— cleanConcise/Explanatory/Learning/Proactive, anddefaultlowercase for Default) verified against the installed CLI's own binary (claude --version2.1.243), not just docs — the docs never state the persisted value for Default