singularity-forge/sf-orchestrator/workflows/step-by-step.md

157 lines
3.6 KiB
Markdown

# 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
```bash
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
# One query — extract phase, cost, and progress together
STATE=$(sf headless query)
CURRENT_PHASE=$(echo "$STATE" | jq -r '.state.phase')
TOTAL_COST=$(echo "$STATE" | jq -r '.cost.total')
PROGRESS=$(echo "$STATE" | jq -r '"\(.state.progress.tasks.done)/\(.state.progress.tasks.total) tasks"')
if [ "$CURRENT_PHASE" = "complete" ]; then
echo "Milestone complete. Total cost: \$$TOTAL_COST"
break
fi
# Budget check
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
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:
```bash
# 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
STATE=$(sf headless query)
PHASE=$(echo "$STATE" | jq -r '.state.phase')
COST=$(echo "$STATE" | 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:
```bash
# 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
```bash
sf headless skip
sf headless --output-format json next 2>/dev/null
```
### Undo last completed unit
```bash
sf headless undo --force
sf headless --output-format json next 2>/dev/null
```
### Force a specific phase
```bash
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
```