Final rebrand: rename remaining Rust source file to complete the gsd → forge transition. All parser references already use forge_parser after earlier commits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.3 KiB
4.3 KiB
Build From Spec
End-to-end workflow: take a product idea or specification, produce working software.
Prerequisites
sfCLI installed (npm install -g sf-run)- A directory for the project (can be empty)
- Git initialized in the directory
Process
Step 1: Prepare the project directory
PROJECT_DIR="/tmp/my-project-name"
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"
git init 2>/dev/null # SF needs a git repo
Step 2: Write the spec file
Write a spec file that describes what to build. More detail = better results.
cat > spec.md << 'SPEC'
# Product Name
## What
[Concrete description of what to build]
## Requirements
- [Specific, testable requirement 1]
- [Specific, testable requirement 2]
- [Specific, testable requirement 3]
## Technical Constraints
- [Language, framework, or platform requirements]
- [External services or APIs involved]
- [Performance or security requirements]
## Out of Scope
- [Things explicitly NOT included]
SPEC
Spec quality matters. Vague specs produce vague results. Include:
- What the user can DO when it's done (not what code to write)
- Technical constraints (language, framework, Node version)
- What's out of scope (prevents scope creep)
Step 3: Launch the build
Fire-and-forget (simplest — SF does everything):
cd "$PROJECT_DIR"
RESULT=$(sf headless --output-format json --timeout 0 --context spec.md new-milestone --auto 2>/dev/null)
EXIT=$?
--timeout 0 disables the timeout for long builds. --auto chains milestone creation into execution.
With budget limit:
# Use step-by-step mode with budget checks instead of auto
# See workflows/step-by-step.md
For CI or ecosystem runs (no user config):
RESULT=$(sf headless --bare --output-format json --timeout 0 --context spec.md new-milestone --auto 2>/dev/null)
EXIT=$?
Step 4: Handle the result
case $EXIT in
0)
# Success — verify deliverables
STATUS=$(echo "$RESULT" | jq -r '.status')
COST=$(echo "$RESULT" | jq -r '.cost.total')
COMMITS=$(echo "$RESULT" | jq -r '.commits | length')
echo "Build complete: $STATUS, cost: \$$COST, commits: $COMMITS"
# Inspect what was built
sf headless query | jq '.state.progress'
# Check the actual files
ls -la "$PROJECT_DIR"
;;
1)
# Error — inspect and decide
echo "Build failed"
echo "$RESULT" | jq '{status: .status, phase: .phase}'
# Check state for details
sf headless query | jq '.state'
;;
10)
# Blocked — needs intervention
echo "Build blocked — needs human input"
sf headless query | jq '{phase: .state.phase, blockers: .state.blockers}'
# Options: steer, supply answers, or escalate
# See workflows/monitor-and-poll.md for blocker handling
;;
11)
echo "Build was cancelled"
;;
esac
Step 5: Verify deliverables
After a successful build, verify the output:
cd "$PROJECT_DIR"
# Check project state
sf headless query | jq '{
phase: .state.phase,
progress: .state.progress,
cost: .cost.total
}'
# Check git log for what was built
git log --oneline
# Run the project's own tests if they exist
[ -f package.json ] && npm test 2>/dev/null
[ -f Makefile ] && make test 2>/dev/null
Complete Example
# 1. Setup
mkdir -p /tmp/todo-api && cd /tmp/todo-api && git init
# 2. Write spec
cat > spec.md << 'SPEC'
# Todo API
Build a REST API for managing todo items using Node.js and Express.
## Requirements
- GET /todos — list all todos
- POST /todos — create a todo (title, completed)
- PUT /todos/:id — update a todo
- DELETE /todos/:id — delete a todo
- Todos stored in-memory (no database)
- Input validation with descriptive error messages
- Health check endpoint at GET /health
## Technical Constraints
- Node.js with ESM modules
- Express framework
- No external database — in-memory array
- Port configurable via PORT env var (default 3000)
## Out of Scope
- Authentication
- Persistent storage
- Frontend
SPEC
# 3. Launch
RESULT=$(sf headless --output-format json --timeout 0 --context spec.md new-milestone --auto 2>/dev/null)
EXIT=$?
# 4. Report
if [ $EXIT -eq 0 ]; then
COST=$(echo "$RESULT" | jq -r '.cost.total')
echo "Build complete (\$$COST)"
echo "Files created:"
find . -not -path './.sf/*' -not -path './.git/*' -type f
else
echo "Build failed (exit $EXIT)"
echo "$RESULT" | jq .
fi