First live test of the sx-forge technology driving a real work session: - sx-fix-up.sh <forge-agent> <briefing.md>: reads the agent's briefing FROM the rose-ash/sx-review forge (agentic-sx branch), materialises a git worktree + branch (loops/sx-<slug>), and spins up a tmux+claude session briefed from the forge. Commits are LOCAL by default (no push). - sx-fix-down.sh [--clean]: stop the sx-fix session; --clean removes worktrees. - plans/agent-briefings/sx-gate-loop.md: W14 (test gate) briefing — the safe first payload (test-only, cannot regress the 5762p/274f baseline), scoped commit-no-push with hard guardrails. Verified live: launcher read the W14 briefing from the forge, created worktree /root/rose-ash-loops/sx-ws-w14 on loops/sx-ws-w14, booted claude, and the agent picked up the briefing. Watch: tmux a -t sx-fix. Note: MCP servers need /mcp auth in a fresh worktree (agent works via Bash meanwhile). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
116 lines
5.5 KiB
Bash
Executable File
116 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# sx-fix-up.sh — spin up ONE claude fix-loop in tmux, driven by an agentic-sx
|
|
# branch in the rose-ash/sx-review forge (git-sx / gitea-sx / agentic-sx).
|
|
#
|
|
# This tests the git→gitea→agentic→tmux wiring: the forge holds the agent
|
|
# branch + briefing; this launcher READS that briefing from the forge (proving
|
|
# the forge drives the session), then materialises a git worktree and a tmux
|
|
# window running claude on the corresponding real branch.
|
|
#
|
|
# Usage: ./scripts/sx-fix-up.sh <forge-agent> <briefing.md> [interval]
|
|
# forge-agent agentic-sx agent branch in the forge, e.g. ws-W14
|
|
# briefing.md file under plans/agent-briefings/ with the detailed work plan
|
|
# interval optional /loop interval (e.g. 15m); omit for self-paced
|
|
#
|
|
# Example: ./scripts/sx-fix-up.sh ws-W14 sx-gate-loop.md
|
|
#
|
|
# The real code branch is loops/sx-<slug> in worktree
|
|
# /root/rose-ash-loops/sx-<slug>. Commits are LOCAL by default — the briefing
|
|
# decides whether to push. Watch: tmux a -t sx-fix ; stop: ./scripts/sx-fix-down.sh
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
|
|
AGENT="${1:?usage: sx-fix-up.sh <forge-agent> <briefing.md> [interval]}"
|
|
BRIEFING_MD="${2:?briefing file under plans/agent-briefings/ required}"
|
|
INTERVAL="${3:-}"
|
|
SLUG="$(echo "$AGENT" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-' | sed 's/-*$//')"
|
|
SESSION="sx-fix"
|
|
WT="/root/rose-ash-loops/sx-${SLUG}"
|
|
BRANCH="loops/sx-${SLUG}"
|
|
BIN="hosts/ocaml/_build/default/bin/sx_server.exe"
|
|
BOOT_WAIT=20
|
|
|
|
[ -f "plans/agent-briefings/$BRIEFING_MD" ] || { echo "no such briefing: plans/agent-briefings/$BRIEFING_MD"; exit 1; }
|
|
|
|
# --- 1. read the briefing identity FROM the forge (the agentic-sx → launch link) ---
|
|
echo "Querying the forge for agent '$AGENT'..."
|
|
FORGE_OUT="$(
|
|
{
|
|
echo '(epoch 1)'
|
|
for f in spec/stdlib.sx lib/r7rs.sx lib/persist/event.sx lib/persist/backend.sx \
|
|
lib/persist/log.sx lib/persist/kv.sx lib/artdag/dag.sx \
|
|
lib/datalog/tokenizer.sx lib/datalog/parser.sx lib/datalog/unify.sx \
|
|
lib/datalog/db.sx lib/datalog/builtins.sx lib/datalog/aggregates.sx \
|
|
lib/datalog/strata.sx lib/datalog/eval.sx lib/datalog/api.sx lib/datalog/magic.sx \
|
|
lib/git/object.sx lib/git/ref.sx lib/git/dag.sx lib/git/worktree.sx \
|
|
lib/git/diff.sx lib/git/merge.sx lib/git/porcelain.sx \
|
|
lib/relations/schema.sx lib/relations/engine.sx lib/relations/api.sx \
|
|
lib/relations/explain.sx lib/relations/federation.sx lib/relations/tree.sx \
|
|
lib/agentic/schema.sx lib/agentic/branch.sx lib/gitea/repo.sx; do
|
|
echo "(load \"$f\")"
|
|
done
|
|
echo '(epoch 2)'
|
|
echo '(load "plans/sx-review/forge-build.sxsrc")'
|
|
echo '(epoch 3)'
|
|
echo "(eval \"(str (agentic/briefing-title (agentic/briefing-of fb-sp \\\"$AGENT\\\")) \\\" | \\\" (agentic/briefing-goal (agentic/briefing-of fb-sp \\\"$AGENT\\\")))\")"
|
|
} | timeout 300 "$BIN" 2>/dev/null | grep -A1 '(ok-len 3' | tail -1
|
|
)"
|
|
if [ -z "$FORGE_OUT" ]; then
|
|
echo "FAILED: could not read briefing for '$AGENT' from the forge." >&2
|
|
exit 1
|
|
fi
|
|
echo "Forge briefing: $FORGE_OUT"
|
|
|
|
# --- 2. materialise the worktree + branch off architecture ---
|
|
if [ -d "$WT/.git" ] || [ -f "$WT/.git" ]; then
|
|
echo "worktree exists: $WT"
|
|
else
|
|
if git show-ref --verify --quiet "refs/heads/$BRANCH"; then
|
|
git worktree add "$WT" "$BRANCH" >/dev/null
|
|
else
|
|
git worktree add -b "$BRANCH" "$WT" architecture >/dev/null
|
|
fi
|
|
echo "worktree created: $WT on $BRANCH"
|
|
fi
|
|
|
|
# permissions so the loop doesn't stall on prompts (mirrors sx-loops-up.sh)
|
|
mkdir -p "$WT/.claude"
|
|
cat > "$WT/.claude/settings.local.json" <<'SETTINGS'
|
|
{
|
|
"permissions": {
|
|
"allow": [
|
|
"mcp__sx-tree__sx_summarise","mcp__sx-tree__sx_read_tree","mcp__sx-tree__sx_read_subtree",
|
|
"mcp__sx-tree__sx_find_all","mcp__sx-tree__sx_find_across","mcp__sx-tree__sx_validate",
|
|
"mcp__sx-tree__sx_write_file","mcp__sx-tree__sx_eval","mcp__sx-tree__sx_harness_eval",
|
|
"mcp__sx-tree__sx_build","mcp__sx-tree__sx_test","mcp__sx-tree__sx_diff_branch",
|
|
"mcp__sx-tree__sx_changed","mcp__sx-tree__sx_comp_list","mcp__sx-tree__sx_comp_usage",
|
|
"Bash(node *)","Bash(python3 *)","Bash(bash *)","Bash(cp *)","Bash(git *)","Bash(timeout *)"
|
|
]
|
|
},
|
|
"enabledMcpjsonServers": ["sx-tree","rose-ash-services","hs-test"]
|
|
}
|
|
SETTINGS
|
|
|
|
# --- 3. tmux window + claude + /loop briefing ---
|
|
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
|
|
tmux new-session -d -s "$SESSION" -n "$SLUG" -c "$WT"
|
|
else
|
|
tmux new-window -t "$SESSION" -n "$SLUG" -c "$WT"
|
|
fi
|
|
tmux send-keys -t "$SESSION:$SLUG" "claude" C-m
|
|
echo "waiting ${BOOT_WAIT}s for claude to boot..."
|
|
sleep "$BOOT_WAIT"
|
|
|
|
PRE="/loop "; [ -n "$INTERVAL" ] && PRE="/loop $INTERVAL "
|
|
CMD="${PRE}Read plans/agent-briefings/$BRIEFING_MD (forge agent $AGENT: $FORGE_OUT) and do ONE iteration per fire: pick the first unchecked [ ], implement, test, commit LOCALLY (no push), tick the box, prepend one dated line to the Progress log, then stop. You are on branch $BRANCH in worktree $WT. Obey the briefing's hard guardrails — test-only, no semantics edits, no push."
|
|
tmux send-keys -t "$SESSION:$SLUG" "$CMD"
|
|
sleep 0.5
|
|
tmux send-keys -t "$SESSION:$SLUG" Enter
|
|
|
|
echo ""
|
|
echo "Launched fix-loop '$SLUG' (forge agent $AGENT) in tmux '$SESSION'."
|
|
echo " Attach: tmux a -t $SESSION"
|
|
echo " Watch: tmux capture-pane -t $SESSION:$SLUG -p | tail -40"
|
|
echo " Stop: tmux kill-window -t $SESSION:$SLUG (or ./scripts/sx-fix-down.sh)"
|
|
echo " Branch: $BRANCH Worktree: $WT (commits LOCAL — review before push)"
|