Files
erp/fleet/harness/bin/vibe-builder.sh
T
arcodangeandClaude Fable 5 f2a60817e2 feat(fleet): multi-runtime harness — verifier tests + capped builder shell
The harness layer (builder sessions, cold verifiers, evidence flow) gets a
committable home, per the PRD model-fleet § harness portability and erp#63:

- fleet/harness/verifier/: the two canonical verifier tests (locate-test,
  cold-reader backlog audit) with pinned inputs, verbatim prompts, ground
  truth and pass rules — judged context-free, never self-graded.
- fleet/harness/bin/run-verifier.sh: runs a test against any OpenAI-style
  local endpoint (Ornith/MLX) or vibe -p (Mistral); emits sha256-pinned
  JSON transcripts.
- fleet/harness/bin/vibe-builder.sh: the bounded shell for scoped builders
  and recurring tasks — refuses the trunk (linked-worktree guard), hard
  --max-turns/--max-price caps, full JSON journal per run.
- fleet/README.md layout + AGENTS.md Fleet section updated in the same
  change (same-change freshness rule).

Part of erp#63 (harness portability spike, D2).

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VRShc4QhLLU73FLHx9vskh
2026-07-18 18:52:53 +02:00

70 lines
2.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Scoped builder bench / recurring-task shell: run `vibe -p` inside a linked
# worktree with hard caps and a JSON journal. Refuses to run in the trunk.
# See fleet/harness/README.md (builder bench protocol, safety bounds).
set -euo pipefail
usage() {
cat >&2 <<'EOF'
usage: vibe-builder.sh <worktree-dir> <prompt-file> [--max-turns N] [--max-price DOLLARS] [--out DIR]
Runs: vibe -p "$(cat prompt-file)" --auto-approve --max-turns N --max-price D --output json
inside <worktree-dir>, which MUST be a linked git worktree (never the trunk).
Journal: <out>/builder-<worktree-name>-<ts>.json (+ .meta.json with wall-clock and exit code).
Defaults: --max-turns 60, --max-price 3, --out $TMPDIR/harness-runs.
EOF
exit 2
}
WORKTREE="${1:-}"; PROMPT_FILE="${2:-}"
[ -d "$WORKTREE" ] && [ -f "${PROMPT_FILE:-}" ] || usage
shift 2
MAX_TURNS=60 MAX_PRICE=3 OUT_DIR="${TMPDIR:-/tmp}/harness-runs"
while [ $# -gt 0 ]; do
case "$1" in
--max-turns) MAX_TURNS="$2"; shift ;;
--max-price) MAX_PRICE="$2"; shift ;;
--out) OUT_DIR="$2"; shift ;;
*) usage ;;
esac
shift
done
# Structural guard: a linked worktree has .git as a FILE (gitdir pointer);
# the trunk has .git as a directory. Same never-the-trunk guarantee as dol-write.sh.
if [ ! -f "$WORKTREE/.git" ]; then
echo "REFUSED: $WORKTREE is not a linked git worktree (trunk is reserved for the user)" >&2
exit 1
fi
mkdir -p "$OUT_DIR"
TS="$(date +%Y%m%dT%H%M%S)"
NAME="$(basename "$WORKTREE")"
JOURNAL="$OUT_DIR/builder-$NAME-$TS.json"
META="$OUT_DIR/builder-$NAME-$TS.meta.json"
START="$(date +%s)"
set +e
(cd "$WORKTREE" && vibe -p "$(cat "$PROMPT_FILE")" --auto-approve \
--max-turns "$MAX_TURNS" --max-price "$MAX_PRICE" --output json) > "$JOURNAL" 2>"$JOURNAL.stderr"
EXIT_CODE=$?
set -e
WALL=$(( $(date +%s) - START ))
PROMPT_SHA="$(shasum -a 256 "$PROMPT_FILE" | cut -d' ' -f1)"
cat > "$META" <<EOF
{
"worktree": "$WORKTREE",
"prompt_file": "$PROMPT_FILE",
"prompt_sha256": "$PROMPT_SHA",
"max_turns": $MAX_TURNS,
"max_price": $MAX_PRICE,
"timestamp": "$TS",
"wall_clock_s": $WALL,
"exit_code": $EXIT_CODE,
"journal": "$JOURNAL"
}
EOF
echo "$META"
exit "$EXIT_CODE"