#!/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 [--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 , which MUST be a linked git worktree (never the trunk). Journal: /builder--.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" <