Updates channel prefixes, log messages, comments, and configuration values across daemon, mcp-server, and related packages to complete the rebrand from gsd to sf-run naming. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.6 KiB
3.6 KiB
Step-by-Step Execution
Run SF one unit at a time with decision points between steps. Use this when you need control over execution — budget enforcement, progress reporting, conditional logic, or the ability to steer mid-build.
When to use this vs auto
| Approach | Use when |
|---|---|
auto |
You trust the build, just want the result |
next loop |
You need budget checks, progress updates, or intervention points |
Core Loop
cd /path/to/project
MAX_BUDGET=20.00
TOTAL_COST=0
while true; do
# Run one unit
RESULT=$(sf headless --output-format json next 2>/dev/null)
EXIT=$?
# Parse result
STATUS=$(echo "$RESULT" | jq -r '.status')
STEP_COST=$(echo "$RESULT" | jq -r '.cost.total')
PHASE=$(echo "$RESULT" | jq -r '.phase // empty')
SESSION_ID=$(echo "$RESULT" | jq -r '.sessionId // empty')
# Handle exit codes
case $EXIT in
0) ;; # success — continue
1)
echo "Step failed: $STATUS"
break
;;
10)
echo "Blocked — needs intervention"
sf headless query | jq '.state'
break
;;
11)
echo "Cancelled"
break
;;
esac
# Check if milestone complete
CURRENT_PHASE=$(sf headless query | jq -r '.state.phase')
if [ "$CURRENT_PHASE" = "complete" ]; then
TOTAL_COST=$(sf headless query | jq -r '.cost.total')
echo "Milestone complete. Total cost: \$$TOTAL_COST"
break
fi
# Budget check
TOTAL_COST=$(sf headless query | jq -r '.cost.total')
OVER=$(echo "$TOTAL_COST > $MAX_BUDGET" | bc -l)
if [ "$OVER" = "1" ]; then
echo "Budget limit (\$$MAX_BUDGET) exceeded at \$$TOTAL_COST"
sf headless stop
break
fi
# Progress report
PROGRESS=$(sf headless query | jq -r '"\(.state.progress.tasks.done)/\(.state.progress.tasks.total) tasks"')
echo "Step done ($STATUS). Phase: $CURRENT_PHASE, Progress: $PROGRESS, Cost: \$$TOTAL_COST"
done
Step-by-Step with Spec Creation
Complete flow from idea to working code with full control:
# 1. Setup
PROJECT_DIR="/tmp/my-project"
mkdir -p "$PROJECT_DIR" && cd "$PROJECT_DIR" && git init 2>/dev/null
# 2. Write spec
cat > spec.md << 'SPEC'
[Your spec here]
SPEC
# 3. Create the milestone (planning only, no execution)
RESULT=$(sf headless --output-format json --context spec.md new-milestone 2>/dev/null)
EXIT=$?
if [ $EXIT -ne 0 ]; then
echo "Milestone creation failed"
echo "$RESULT" | jq .
exit 1
fi
echo "Milestone created. Starting execution..."
# 4. Execute step-by-step
STEP=0
while true; do
STEP=$((STEP + 1))
RESULT=$(sf headless --output-format json next 2>/dev/null)
EXIT=$?
[ $EXIT -ne 0 ] && break
PHASE=$(sf headless query | jq -r '.state.phase')
COST=$(sf headless query | jq -r '.cost.total')
echo "Step $STEP complete. Phase: $PHASE, Cost: \$$COST"
[ "$PHASE" = "complete" ] && break
done
echo "Build finished in $STEP steps"
Intervention Patterns
Steer mid-execution
If you detect the build going in the wrong direction:
# Check what's happening
sf headless query | jq '{phase: .state.phase, task: .state.activeTask}'
# Redirect
sf headless steer "Use SQLite instead of PostgreSQL for storage"
# Continue
sf headless --output-format json next 2>/dev/null
Skip a stuck unit
sf headless skip
sf headless --output-format json next 2>/dev/null
Undo last completed unit
sf headless undo --force
sf headless --output-format json next 2>/dev/null
Force a specific phase
sf headless dispatch replan # Re-plan the current slice
sf headless dispatch execute # Skip to execution
sf headless dispatch uat # Jump to user acceptance testing