- You write the spec (what to build)
- You launch the build (
gsd headless ... new-milestone --context spec.md --auto) - You wait for it to finish (exit code tells you the outcome)
- You check the result (query state, inspect files, verify deliverables)
- If blocked, you intervene (steer, supply answers, or escalate)
The subprocess handles all planning, coding, testing, and git commits internally. You never write application code yourself — GSD does that.
Build something from scratch:
Read workflows/build-from-spec.md — write spec, init directory, launch, monitor, verify.
Check on a running or completed build:
Read workflows/monitor-and-poll.md — query state, interpret phases, handle blockers.
Execute with fine-grained control:
Read workflows/step-by-step.md — run one unit at a time with decision points.
Understand the JSON output:
Read references/json-result.md — field reference for HeadlessJsonResult.
Pre-supply answers or secrets:
Read references/answer-injection.md — answer file schema and injection mechanism.
Look up a specific command:
Read references/commands.md — full command reference with flags and examples.
Launch a full build (spec to working code):
mkdir -p /tmp/my-project && cd /tmp/my-project && git init
cat > spec.md << 'EOF'
# Your Product Spec Here
Build a ...
EOF
gsd headless --output-format json --context spec.md new-milestone --auto 2>/dev/null
Check project state (instant, free):
cd /path/to/project
gsd headless query | jq '{phase: .state.phase, progress: .state.progress, cost: .cost.total}'
Resume work on an existing project:
cd /path/to/project
gsd headless --output-format json auto 2>/dev/null
Run one step at a time:
RESULT=$(gsd headless --output-format json next 2>/dev/null)
echo "$RESULT" | jq '{status: .status, phase: .phase, cost: .cost.total}'
State is derived from files on disk — checkboxes in ROADMAP.md and PLAN.md are the source of truth for completion. You never need to edit these files. GSD manages them. But you can read them to understand progress.
gsd headless --answers answers.json --output-format json auto 2>/dev/null
{
"questions": { "question_id": "selected_option" },
"secrets": { "API_KEY": "sk-..." },
"defaults": { "strategy": "first_option" }
}
- questions — question ID to answer (string for single-select, string[] for multi-select)
- secrets — env var to value, injected into child process environment
- defaults.strategy —
"first_option"(default) or"cancel"for unmatched questions
See references/answer-injection.md for the full mechanism.
gsd headless --json auto 2>/dev/null | while read -r line; do
TYPE=$(echo "$line" | jq -r '.type')
case "$TYPE" in
tool_execution_start) echo "Tool: $(echo "$line" | jq -r '.toolName')" ;;
extension_ui_request) echo "GSD: $(echo "$line" | jq -r '.message // .title // empty')" ;;
agent_end) echo "Session ended" ;;
esac
done
Filter to specific events: --events agent_end,execution_complete,extension_ui_request
Available types: agent_start, agent_end, tool_execution_start, tool_execution_end,
tool_execution_update, extension_ui_request, message_start, message_end,
message_update, turn_start, turn_end, cost_update, execution_complete.
See references/commands.md for the complete reference.