Skip to content

perf(prompt): let throwaway scripts be authored inline in Bash#753

Merged
ericleepi314 merged 1 commit into
mainfrom
perf/scope-write-preference-to-deliverables
Jul 26, 2026
Merged

perf(prompt): let throwaway scripts be authored inline in Bash#753
ericleepi314 merged 1 commit into
mainfrom
perf/scope-write-preference-to-deliverables

Conversation

@ericleepi314

Copy link
Copy Markdown
Collaborator

Iteration 4 on the trajectory gap against the latest Claude Code, measured with eval/harbor/compare_trajectories.py on seven terminal-bench 2.1 tasks at the same model (claude-opus-5), effort (xhigh) and timeout multiplier.

The change: the "To create files use Write instead of cat with heredoc or echo" sub-bullet now adds that a throwaway script you run once and discard is part of the command rather than a deliverable, and may instead be authored inline in the same Bash call that runs it. The Write preference is untouched for deliverables — that's what keeps real edits reviewable as diffs. "Reserve using the Bash exclusively for system commands" three lines below loses "exclusively", which cannot coexist with the carve-out.

Result

Against the prior clean state (iter2), on the six tasks both runs completed:

task iter2 iter4 Claude Code Δ
regex-log 15 7 7 −8
distribution-search 10 6 3 −4
cancel-async-tasks 9 6 4 −3
sparql-university 12 12 6 0
fix-code-vulnerability 10 12 8 +2
circuit-fibsqrt 8 17 11 +9
mean 10.67 10.00 6.50

Gap +4.17 → +3.50 (16% closed). 3 improved, 2 regressed, 1 unchanged. regex-log matches Claude Code exactly; circuit-fibsqrt is most of the remaining drag and is iteration 5's target.

Reward: 7/7 at 1.0, none killed. iter2 had one trial killed at its timeout; the withdrawn iter3 had one outright FAIL.

The behavior metrics moved further than the mean:

metric iter2 iter4 Claude Code
tool mix Bash / Write 70.2 / 19.1 78.8 / 11.8 79.7 / 11.9
heredoc-authored 12.1% 20.9% 23.4%
exact-repeat rate 5.3% 2.4% 0.0%
Bash stmts median/mean 3.0 / 4.4 4.0 / 5.2 3.0 / 5.5

Tool mix is now within a point of Claude Code's on every entry.

What is NOT claimed

The mechanism I originally wrote down was wrong, and review caught it. I'd claimed clawcodex was effectively barred from authoring scratch files in Bash, citing a 2.7% heredoc rate. That figure came from the withdrawn iter3 build and counted heredoc syntax only. Counting any Bash call that authors file content (heredoc or printf/echo/tee redirect), clawcodex was already near parity beforehand: iter0 27.7%, iter2 24.2%, Claude Code 27.7%. Claude Code also uses Write for probe scripts — 294 of its 327 Write/Edit calls target non-/tmp paths.

So the improvement is measured, but it is not explained by "the prompt forbade something Claude Code does." Most likely the carve-out removes hesitation at the margin rather than unlocking a blocked behavior. Recording that honestly matters more than a tidy story: iterations 2 and 3 both had tidy stories and delivered nothing and harm respectively.

Known cost, accepted deliberately

In acceptEdits mode Write is auto-accepted while any Bash redirect prompts, so taking this option trades a saved step for an approval prompt there. Verified: check_accept_edits_bash (src/permissions/bash_mode_validation.py:304) gates on _has_shell_redirection, not on the redirect target — cat is in ACCEPT_EDITS_READ_ONLY_COMMANDS whose branch requires not redirection_anywhere — so cat > /app/x <<PY, cat > /tmp/x <<PY, cat > ./x <<PY and printf 'x' > /app/x all return False and prompt. Location therefore makes no permission difference and none is specified. Hence "may", not an instruction. No approval is bypassed — this adds prompts, never skips them.

Tests

8840 passed, 3 skipped, 0 failures.

Two same-named test_connection_error_re_raises tests are deselected — tests/test_stream_watchdog.py (known) and tests/test_agent_loop_compat_model_error.py::TestModelErrorPropagation (found this session). The latter hangs inside src/tasks/eviction.py:205 _sweeper_loop, passes in isolation, and is byte-identical on main, so it is a pre-existing background-sweeper test-interaction flake, not a regression. Located by dumping the stack with SIGABRT after --timeout-method=thread failed to interrupt it.

🤖 Generated with Claude Code

Iteration 4 on the trajectory gap against the latest Claude Code, measured
with eval/harbor/compare_trajectories.py on seven terminal-bench 2.1 tasks
at the same model (claude-opus-5), effort (xhigh) and timeout multiplier.

The change: the "To create files use Write instead of cat with heredoc or
echo" sub-bullet now adds that a throwaway script you run once and discard
is part of the command rather than a deliverable, and MAY instead be
authored inline in the same Bash call that runs it. The Write preference is
untouched for deliverables -- that is what keeps real edits reviewable as
diffs. "Reserve using the Bash EXCLUSIVELY for system commands" three
lines below loses "exclusively", which cannot coexist with the carve-out.

Result: behavior converged, step count improved modestly
--------------------------------------------------------------------
Against the prior clean state (iter2), on the six tasks both runs
completed:

    mean steps       10.67 -> 10.00   (Claude Code 6.50)
    gap vs CC        +4.17 -> +3.50   (16% of the gap closed)
    per task         3 improved, 2 regressed, 1 unchanged

    regex-log            15 -> 7   (Claude Code 7 -- exact match)
    distribution-search  10 -> 6
    cancel-async-tasks    9 -> 6
    sparql-university    12 -> 12
    fix-code-vulnerability 10 -> 12
    circuit-fibsqrt       8 -> 17  <-- most of the remaining drag

Reward: 7/7 at 1.0, none killed. iter2 had one trial killed at its
timeout; the withdrawn iter3 had one outright FAIL.

The behavior metrics moved further than the mean:

    tool mix Bash/Write   70.2/19.1 -> 78.8/11.8   (CC 79.7/11.9)
    heredoc-authored           12.1% -> 20.9%      (CC 23.4%)
    exact-repeat rate           5.3% ->  2.4%      (CC 0.0%)
    Bash stmts median/mean   3.0/4.4 -> 4.0/5.2    (CC 3.0/5.5)

Tool mix is now within a point of Claude Code's on every entry.

What is NOT claimed
--------------------------------------------------------------------
The mechanism I originally wrote down was wrong, and review caught it.
I had claimed clawcodex was effectively barred from authoring scratch
files in Bash, citing a 2.7% heredoc rate. That figure came from the
WITHDRAWN iter3 build and, worse, counted heredoc syntax only. Counting
any Bash call that authors file content (heredoc or printf/echo/tee
redirect), clawcodex was already near parity before this change: iter0
27.7%, iter2 24.2%, Claude Code 27.7%. Claude Code also uses Write for
probe scripts -- 294 of its 327 Write/Edit calls target non-/tmp paths.

So the improvement above is measured, but it is not explained by "the
prompt forbade something Claude Code does". Most likely the carve-out
removes hesitation at the margin rather than unlocking a blocked
behavior. Recording that honestly matters more than a tidy story:
iterations 2 and 3 both had tidy stories and delivered nothing and harm
respectively.

Known cost, accepted deliberately
--------------------------------------------------------------------
In acceptEdits mode Write is auto-accepted while any Bash redirect
prompts, so taking this option trades a saved step for an approval prompt
there. Verified: check_accept_edits_bash
(src/permissions/bash_mode_validation.py:304) gates on
_has_shell_redirection, NOT on the redirect target -- `cat` is in
ACCEPT_EDITS_READ_ONLY_COMMANDS whose branch requires
`not redirection_anywhere` -- so `cat > /app/x <<PY`, `cat > /tmp/x <<PY`,
`cat > ./x <<PY` and `printf 'x' > /app/x` all return False and prompt.
Location therefore makes no permission difference and none is specified.
Hence "may", not an instruction: the model keeps Write when a prompt would
cost more than the step saves. No approval is bypassed -- this adds
prompts, never skips them.
@ericleepi314
ericleepi314 merged commit 7ee841b into main Jul 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant