Repository navigation
Align hooks with Claude Code's documented output contract (#15) - #33
Open
1aifanatic wants to merge 1 commit into
Open
1aifanatic wants to merge 1 commit into
1aifanatic wants to merge 1 commit into
Conversation
PostToolUse now emits replacements as hookSpecificOutput.updatedToolOutput in the tool's own shape (Bash stdout with stderr/interrupted kept, Read file.content with metadata kept) instead of a top-level tool_response that Claude Code ignores. Bash and Read results now actually reach the filter and compression path. Savings are booked only after a replacement is emitted. UserPromptSubmit cannot replace the prompt, so it now emits only the intent hint as hookSpecificOutput.additionalContext and no longer calls compress or books prompt-compression savings that never reached the model. Adds subprocess contract tests for the built hooks (temporary HOME, stub Scaledown API) and updates README/setup/AGENTS.md claims. Refs scaledown-team#15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Closes #15
Problem
PostToolUseprinted a top-level{tool_response: ...}, which isn't part of Claude Code's hook contract, so every replacement was ignored.extractTextdidn't recognise Claude Code's real Bash ({stdout, stderr, interrupted, isImage, noOutputExpected}) or Read ({type:"text", file:{content, ...}}) result shapes. Those results never reached the filter or compression path.UserPromptSubmitprinted{prompt: ...}, which this event can't do: it can only add context. The intent hint was dropped, and "prompt compression" called the API and booked savings for text the model never received.Changes
hooks/post-tool-use.tsextractText/replaceTexthandle Bashstdoutand Readfile.content. The rest of the shape (stderr, interrupted, isImage, file metadata) is preserved. Image output is never rewritten. The existingoutput/content/textfallbacks are kept for other tools.postToolUseOutput()emits{"hookSpecificOutput":{"hookEventName":"PostToolUse","updatedToolOutput":<same shape>}}.processToolResponse().main()books savings and requests only after a replacement has been written. No-op and API-failure paths print{}and book nothing.hooks/user-prompt-submit.ts{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"[DietCode intent: …]"}}.SCALEDOWN_COMPRESS_THRESHOLD/SCALEDOWN_NIAH_DISABLEconfig fields stay inConfig, but the hook no longer reads them.Docs: README "What it does", "How it works", the feature matrix (the "Auto compression (large prompts)" row is removed), the env var table, "How compression works" (rewritten), the
dietcode setupsummary andagents-md/AGENTS.md. This also removes the unqualified "50–70% before the prompt reaches the model" claim (related to #19).Tests
hooks/post-tool-use.test.ts: the mock-only "compression logic" tests are replaced with realprocessToolResponsetests. They cover realistic Bash, Read and MCP-style inputs, check that output is replaced rather than appended, keep stderr and status, and cover the small-output no-op, API failure and the disabled toggle.hooks/user-prompt-submit.test.ts: the mock-only tests are replaced with output-shape tests.hooks/hook-contract.test.tsruns the builtdist/hooks/*.jsover stdin/stdout, as Claude Code does. It uses a temporaryHOME, so it never touches the real~/.scaledown, and a local stub Scaledown API. It asserts the exact JSON contract, which endpoints get called, and thatstats.jsononly changes when a replacement is emitted. It's added tonpm run test:unit; CI already builds first, and the suite skips ifdist/is missing.npx tsc --noEmitis clean, and the 73 tests across the hook and niah suites pass.Live verification (the request actually sent to the model)
I ran
claude -pon Claude Code 2.1.310 with--settingsregistering the built hooks, a stub Scaledown API, and a prompt asking the model to runls -l <dir>and echo the tool result verbatim, plus any[DietCode intenttext in its context:origin/mainls -l(permissions, owners, dates); intent hint: NONE;totalSaved: 0sub/ … alpha.txt 3B … Summary: 3 files, 1 dirs(the filtered output replaced the original);[DietCode intent: search (82%)]Not covered / follow-ups
hook-integration.test.ts(theclaude -psmoke tests that needANTHROPIC_API_KEY) is unchanged. The live check above could become a CI assertion there if maintainers want to spend API budget on it.🤖 Generated with Claude Code