Context guard: size whole-file reads before they happen (0.15.0) - #28
Merged
Conversation
readIntent() sizes Read (offset/limit-aware) and cat/head/tail/less/more/bat;
piped, redirected, byte-ranged and followed reads pass. govern.mjs measures
the files (lines + bytes) and sends tool_context to the gateway, or hands it
to the local engine. Policy block contextGuard { maxLines, mode: off|shadow|
enforce, action, guidance }: shadow records estTokens on the audit line,
enforce denies (or asks) with a steer that names the sanctioned path per
harness. No block → no behavior change.
Ported Spotify shunt's 34 hook evals and closed its known bypasses (offset 0
/ limit 0 pass, head -100 blocks) by sizing the effective read.
Tracks gatewaystack-connect#1072.
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.
Spotify's shunt plugin blocks Read/cat over 350 lines with a PreToolUse hook (their lesson: CLAUDE.md is advice, hooks are law). This is the ACP version: one parser, measured, shadow-first, every harness the installer serves.
What
readIntent()in decide.mjs (pure): sizesRead(offset/limit-aware) andcat/head/tail/less/more/bat. Pipes, redirects, byte ranges,tail -fare targeted and pass.head -n Ncounts as N lines.tool_context: { read, files }on/govern/tool-use; local mode hands it todecide().contextGuard: { maxLines, mode: off|shadow|enforce, action: deny|ask, guidance }. Shadow → allow, audit line carriescontextGuard.estTokens. Enforce → deny/ask, reason names the sanctioned path (offset/limit or grep;sed -nfor Codex; subagent).Tests
49 new (test/context-guard.test.mjs): Spotify's 17 Read + 17 Bash evals ported, plus the bypasses they document as known gaps (offset 0 / limit 0 now sized,
head -100now passes,head -n 5passes on purpose). Layer 2 spawns the real hook against real files. Full suite 162/162.Sandbox: install.sh --local in a throwaway HOME, then a 1,200-line Read → denied with the steer;
head -n 20→ silent allow; audit.jsonl carries the ledger.Order
Merge this first: install.sh fetches govern.mjs from this repo's main. Gateway side: gatewaystack-connect PR (same branch name). Tracks gatewaystack-connect#1072.