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
70 lines
2.1 KiB
Bash
Executable File
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"
|