Skip to content

fix(harness): run the bash tool's command under bash - #78

Merged
sanchitrk merged 1 commit into
mainfrom
claude/linear-cod-152-f4883b
Oct 15, 2026
Merged

sanchitrk merged 1 commit into
mainfrom
claude/linear-cod-152-f4883b

Conversation

@sanchitrk

Copy link
Copy Markdown
Contributor

Problem

The bash tool ran the model's command under each backend's sh (host, Vercel, Daytona). /bin/sh is dash on Debian and Ubuntu, so bash syntax (arrays, [[ ]], {1..3}, here-strings, source) worked on a Mac and failed on Linux.

It was worse than a wrong shell: the command was pasted into the output wrapper, so under dash a bash-only construct broke the wrapper's own parse. The model got sh: 3: Syntax error pointing into our script, with no output file and no exit code.

Fix

tool/output.ts: the wrapper carries the command as a quoted string and picks the shell inside the sandbox:

c=<quoted command>
if command -v bash >/dev/null 2>&1; then s=bash; else s=sh; fi
run() ( if [ "$s" = bash ]; then bash -c "$c"; else eval "$c"; fi )
  • One place covers every backend; sandbox providers are untouched.
  • A syntax error stays the command's (exit 2); the wrapper always parses.
  • The fallback uses eval, which needs no PATH lookup. There's no exec, because just-bash carries on past it.
  • The shell rides on the wrapper's existing report line. A failure under sh ends with (ran under sh: bash is not on PATH in this sandbox), so the model can fix the command and re-run. Successful runs are unchanged.

Also updates the local sandbox doc and CHANGELOG.md.

Tests

  • tools.output.test.ts: bash-only syntax on host (streaming, re-encoded, buffered) and just-bash produces one artifact, __artifacts__/tools.bash.syntax.json. A syntax error stays BashFailed exit 2. A host without bash on PATH runs under sh and states it on failure, for both the streaming and buffered paths.
  • fixtures/bash.spec.ts: the same command on live Daytona and Vercel matches the same artifact (15/15 live bash tests pass).
  • With the host shell forced to /bin/dash, the old code fails the three host cases; the new code passes all 48.
  • One-off live runs (not committed) with gpt-6-luna (openai-codex and openai) and gemini-4-argon: every run answered correctly. Where sh is dash and bash is on PATH, the fix took 1 tool call instead of 2. Without bash, it took 2 calls instead of 2 to 4.

vp check and vp run typecheck are clean.

🤖 Generated with Claude Code

The command ran under each backend's `sh`, which is dash on Debian and
Ubuntu, so bash syntax failed there. It was also pasted into the output
wrapper, so a bash-only construct broke the wrapper's own parse.

The wrapper now carries the command as a quoted string and runs it with
`bash -c` when bash is on PATH, else `eval` under `sh`. The shell rides
on the wrapper's report, and a failure under `sh` says so to the model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sanchitrk
sanchitrk merged commit a80eddf into main Oct 15, 2026
2 checks passed
@sanchitrk
sanchitrk deleted the claude/linear-cod-152-f4883b branch October 15, 2026 06:48
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