diff options
| author | Craig Jennings <c@cjennings.net> | 2026-08-05 18:22:37 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-08-05 18:22:37 -0500 |
| commit | 588fbf6b3adca048afbf57ef616cc3558310fff2 (patch) | |
| tree | c84802dc698c6db4031adff3092050edbe7621ee /claude-rules | |
| parent | cf9910d51715b1bb040dd808501fd5cf490fc30d (diff) | |
| download | rulesets-588fbf6b3adca048afbf57ef616cc3558310fff2.tar.gz rulesets-588fbf6b3adca048afbf57ef616cc3558310fff2.zip | |
feat(rules): quiet output, and a dispatch gate for where output lands
Tool output isn't free. It lands in the Emacs buffer I'm working in, so eleven hourly sentry cycles on 2026-08-05 filled my workspace with lines confirming nothing had changed.
Two rules, each in the file that already owns the concern. interaction.md gets quiet output: a check returning the expected result prints nothing, and only deviations plus one summary line reach the terminal. It already governs styling, and volume is the larger cost.
subagents.md gets a third dispatch justification beside cost and isolation. A repeated scheduled pass is dispatched for where its output lands, not for how hard the work is. The size gates don't apply, since a recurring check battery is always a known target in under ten calls.
Verification gates are exempt, and that exemption is load-bearing. An exit code can lie, so a check that is evidence for a completion claim still gets read in full.
sentry.org's pass runner now runs the walk in a background subagent, and says where the thread boundary falls.
Diffstat (limited to 'claude-rules')
| -rw-r--r-- | claude-rules/interaction.md | 26 | ||||
| -rw-r--r-- | claude-rules/subagents.md | 57 |
2 files changed, 77 insertions, 6 deletions
diff --git a/claude-rules/interaction.md b/claude-rules/interaction.md index b5798bd..746f5c9 100644 --- a/claude-rules/interaction.md +++ b/claude-rules/interaction.md @@ -97,6 +97,32 @@ In conversational output to the user, do not use Markdown bold (`**...**`) or in This governs **chat output**, not the Markdown source of rule files, specs, or docs the user reads in an editor — those keep normal Markdown formatting. The constraint is the terminal rendering of the live conversation. +## Quiet Output: A Check That Passes Says Nothing + +A check that returns the expected result prints nothing. Only deviations print, plus at most one summary line. + +**Why:** tool output isn't free. Craig runs Claude Code inside Emacs EAT, so every Bash stdout lands in the buffer he's working in, where the command's output and his work compete for one screen. The reverse-video rule above governs the styling of what reaches his terminal. This governs the volume, which is the larger cost. + +**The failure it closes** is reading "keep output minimal" as a rule about prose, and treating tool output as exempt because it isn't prose. Work ran eleven hourly sentry cycles on 2026-08-05, each about ten Bash calls printing in full. Nearly every line confirmed nothing had changed: roam current, staleness unchanged, lint at its known counts, tree clean. Craig's instruction that day was "I want you to switch to the quiet form ALWAYS." + +**How to apply:** + +- Let the exit code carry the pass, but capture the output rather than discarding it, so the failure branch can show what went wrong: + + out=$(cmd 2>&1) || { echo "DEVIATION: <what>"; echo "$out"; } + + Don't write `cmd >/dev/null 2>&1 || echo "DEVIATION: ..."`. That throws the diagnostic away down the one branch that needs it, leaving only the placeholder you typed. +- Grep for problems rather than for confirmation. Piping a report through `grep DEVIATION` beats printing the report. +- Compare against the known-good value and print only a mismatch (a count, a SHA, a status string). +- One closing summary line is fine ("checks done", "3 of 11 passes had findings"). A per-item roll call confirming each success is not. +- When you genuinely need a command's output, filter it to the anomalies first. + +Quiet isn't silent. A deviation, a finding, and anything Craig asked to see all print in full. Suppressing those is the opposite failure and a worse one. The rule removes confirmations, never signal. + +**Verification gates are exempt, and the exemption is load-bearing.** [`verification.md`](verification.md) requires reading a check's whole output before claiming it passed, because an exit code can lie. A suite that silently skipped every test exits 0. A linter can exit 0 holding warnings. A gate running against a hand-maintained file list exits 0 without ever seeing your new file. So when the command is the evidence for a completion claim (the pre-commit test run, the linter, the type checker, a bug's reproduction steps), read the real output and say what it said. Quiet form governs routine checks that only confirm the expected state. It never buys a cheaper way to claim something passed. Where the two rules meet, `verification.md` wins. + +This is about the main thread's output, because that's what reaches his terminal. A background subagent writes to a file instead, which is why a repeated multi-step pass gets dispatched rather than run inline. See the Output-Destination Override in [`subagents.md`](subagents.md). + ## Showing Craig Visuals Craig runs Claude Code inside Emacs EAT (through tmux). EAT renders SendUserFile and inline terminal images as an `[image] path.png` text line — the visual itself never appears. In one session ~20 renders went out that way and Craig approved UI he had never seen (takuzu, 2026-07-11). Never rely on SendUserFile or inline image display to show a visual. SendUserFile stays fine for *delivering* a file; it just doesn't display one. diff --git a/claude-rules/subagents.md b/claude-rules/subagents.md index e52d906..b36abba 100644 --- a/claude-rules/subagents.md +++ b/claude-rules/subagents.md @@ -10,7 +10,10 @@ deliberately, not reflexively. ## Pre-Dispatch Checks Run these two checks before any spawn. Both can send the work back to the -main thread without the spawn ever happening. +main thread without the spawn ever happening. The two overrides below +(Isolation, Output Destination) point the other way, at dispatch, and each +lifts the Cost gate. Neither touches Availability: no override can conjure a +spawn mechanism that isn't there. ### Availability @@ -36,7 +39,39 @@ at dispatch time. Every size-based rule in this file — the cost gate here, "Don't Subagent At All", the trivial-work anti-pattern — is subject to the isolation override -below. +and the output-destination gate below. + +## Output-Destination Override: When the Terminal Is the Cost + +The cost gate above weighs the handoff against the work. The isolation +override below fires when the main thread is disqualified from judging. This +third justification is neither. The work is trivial, the main thread is +perfectly capable of it, and dispatching is still correct, because a background +subagent's output goes to a file while the main thread's goes to Craig's +terminal. Background is the operative word. A foreground dispatch puts the +output right back where it started. + +It fires for a **repeated multi-step pass on a schedule**: a recurring battery +of checks, a monitor loop's per-cycle body, any prompt that walks the same list +every N minutes. Ten Bash calls once is fine inline. Ten Bash calls every hour +for eleven hours is a hundred and ten blocks of output in the buffer he's +working in, which is what happened on 2026-08-05. + +Dispatch those, and let the quiet-output rule in `interaction.md` govern what +the main thread then says about the result: deviations, plus one line per cycle. +The justification is where the output lands, not how hard the work is. So the +size gates in this file don't apply, the same way they don't apply under the +isolation override. In particular, "the target is already known and the work +fits in under ~10 tool calls" is exactly the shape of a recurring check battery, +so that gate would otherwise refuse every case this one exists to catch. + +The inverse keeps this from becoming a licence to dispatch everything. Work that +produces little output, or output Craig actually wants to watch, gains nothing +from the handoff and still pays the contract cost. A one-off check stays inline +and prints quietly. + +Craig's directive, 2026-08-05: quiet form always, and hand a repeated pass to a +subagent. ## Isolation Override — When Size Doesn't Gate @@ -123,8 +158,13 @@ to the user to adjudicate, not back to the author's own judgment. ### Don't Subagent At All -Unless the Isolation Override applies — these are efficiency rules, and they -lapse when the main thread's own context is what makes its answer untrustworthy. +Unless one of the two overrides applies. These are efficiency rules, and they +lapse under the Isolation Override (the main thread's own context is what makes +its answer untrustworthy) and under the Output-Destination Override (the pass +repeats on a schedule, so its output floods Craig's terminal). The first bullet +below is the one the second override most often lifts. A recurring check battery +is always a known target in under ~10 calls, and that's not a reason to run it +inline. - **The target is already known** and the work fits in under ~10 tool calls. - **Single-function logic** — one Read + one Edit is faster than briefing @@ -202,8 +242,10 @@ fix), then dispatch the fix with a specific contract. - **Retrying a failed subagent task in the orchestrator** — pollutes context. Dispatch a fix agent instead. - **Subagenting trivial work** — one Read + one Edit doesn't need an - agent; spawn overhead exceeds benefit. Except under the Isolation - Override, where a one-line diff still gets its own reviewer. + agent; spawn overhead exceeds benefit. Except under either override: the + Isolation Override, where a one-line diff still gets its own reviewer, and + the Output-Destination Override, where a trivial pass that repeats hourly + gets dispatched for where its output lands. - **Reviewing your own change inline** — the mirror-image failure, and the more expensive one. Skipping a dispatch to save overhead on a small diff costs a review that could only have come from outside your context. @@ -219,3 +261,6 @@ fix), then dispatch the fix with a specific contract. see `verification.md`. - Testing discipline applies to subagent-produced tests too — see `testing.md`. +- What the main thread prints once a pass is dispatched: see the + quiet-output rule in `interaction.md`. It's the other half of the + Output-Destination Override above. |
