Run GSD commands as subprocesses via gsd headless. No SDK, no RPC — just shell exec, exit codes, and JSON on stdout.
bash
# Install GSD globally
npm install -g gsd-pi
# Verify installation
gsd --version
# Create a milestone from a spec and execute it
gsd headless --output-format json new-milestone --context spec.md --auto
bash
gsd headless [flags] [command] [args...]
Default command is auto (run all queued units).
FlagDescription--output-format <fmt>Output format: text (default), json (structured result at exit), stream-json (JSONL events)--jsonAlias for --output-format stream-json — JSONL event stream to stdout--bareMinimal context: skip CLAUDE.md, AGENTS.md, user settings, user skills. Use for CI/ecosystem runs.--resume <id>Resume a prior headless session by its session ID--timeout NOverall timeout in ms (default: 300000)--model IDOverride LLM model--supervisedForward interactive UI requests to orchestrator via stdout/stdin--response-timeout NTimeout (ms) for orchestrator response in supervised mode (default: 30000)--answers <path>Pre-supply answers and secrets from JSON file--events <types>Filter JSONL output to specific event types (comma-separated, implies --json)--verboseShow tool calls in progress output
CodeMeaningConstant0Success — unit/milestone completedEXIT_SUCCESS``1Error or timeoutEXIT_ERROR``10Blocked — needs human interventionEXIT_BLOCKED``11Cancelled by user or orchestratorEXIT_CANCELLED
These codes are stable and suitable for CI pipelines and orchestrator logic.
FormatBehaviortextHuman-readable progress on stderr. Default.jsonCollect events silently. Emit a single HeadlessJsonResult JSON object to stdout at exit.stream-jsonStream JSONL events to stdout in real time (same as --json).
Use --output-format json when you need a structured result for decision-making. See references/json-result.md for the full field reference.
bash
gsd headless --output-format json new-milestone --context spec.md --auto
Reads a spec file, bootstraps .gsd/, creates the milestone, then chains into auto-mode executing all phases (discuss → research → plan → execute → summarize → complete). The JSON result is emitted on stdout at exit.
Extra flags for new-milestone:
--context <path> — path to spec/PRD file (use - for stdin)--context-text <text> — inline specification text--auto — start auto-mode after milestone creation--verbose — show tool calls in progress outputbash
# From stdin
cat spec.md | gsd headless --output-format json new-milestone --context - --auto
# Inline text
gsd headless new-milestone --context-text "Build a REST API for user management" --auto
bash
gsd headless --output-format json auto
Loop through all pending units until milestone complete or blocked.
bash
gsd headless --output-format json next
Execute exactly one unit (task/slice/milestone step), then exit. This is the recommended pattern for orchestrators that need control between steps.
bash
gsd headless query
Returns a single JSON object with the full project snapshot — no LLM session, instant (~50ms). This is the recommended way for orchestrators to inspect state.
json
{
"state": {
"phase": "executing",
"activeMilestone": { "id": "M001", "title": "..." },
"activeSlice": { "id": "S01", "title": "..." },
"progress": { "completed": 3, "total": 7 },
"registry": [...]
},
"next": { "action": "dispatch", "unitType": "execute-task", "unitId": "M001/S01/T01" },
"cost": { "workers": [{ "milestoneId": "M001", "cost": 1.50 }], "total": 1.50 }
}
bash
gsd headless dispatch research|plan|execute|complete|reassess|uat|replan
Force-route to a specific phase, bypassing normal state-machine routing.
bash
gsd headless --resume <session-id> auto
Resume a prior headless session. The session ID is available in the HeadlessJsonResult.sessionId field from a previous --output-format json run.
When using --output-format json, the process emits a single HeadlessJsonResult on stdout at exit. Parse it for decision-making:
bash
RESULT=$(gsd headless --output-format json next 2>/dev/null)
EXIT=$?
STATUS=$(echo "$RESULT" | jq -r '.status')
COST=$(echo "$RESULT" | jq -r '.cost.total')
PHASE=$(echo "$RESULT" | jq -r '.phase')
NEXT=$(echo "$RESULT" | jq -r '.nextAction')
SESSION_ID=$(echo "$RESULT" | jq -r '.sessionId')
echo "Status: $STATUS, Cost: \$${COST}, Phase: $PHASE, Next: $NEXT"
See references/json-result.md for the full field reference.
Exit code 10 means the execution hit a blocker requiring human intervention:
bash
gsd headless --output-format json next 2>/dev/null
EXIT=$?
if [ $EXIT -eq 10 ]; then
# Inspect the blocker
BLOCKER=$(gsd headless query | jq '.state.phase')
echo "Blocked: $BLOCKER"
# Option 1: Use --supervised mode to handle interactively
gsd headless --supervised auto
# Option 2: Pre-supply answers to resolve the blocker
gsd headless --answers blocker-answers.json auto
# Option 3: Steer the plan to work around it
gsd headless steer "Skip the blocked dependency, use mock instead"
fi
bash
MAX_BUDGET=10.00
RESULT=$(gsd headless --output-format json next 2>/dev/null)
COST=$(echo "$RESULT" | jq -r '.cost.total')
# Check cumulative cost via query (includes all workers)
TOTAL_COST=$(gsd headless query | jq -r '.cost.total')
if (( $(echo "$TOTAL_COST > $MAX_BUDGET" | bc -l) )); then
echo "Budget exceeded: \$$TOTAL_COST > \$$MAX_BUDGET"
gsd headless stop
exit 1
fi
The recommended pattern for full control. Run one unit at a time, inspect state between steps:
bash
while true; do
RESULT=$(gsd headless --output-format json next 2>/dev/null)
EXIT=$?
STATUS=$(echo "$RESULT" | jq -r '.status')
COST=$(echo "$RESULT" | jq -r '.cost.total')
echo "Exit: $EXIT, Status: $STATUS, Cost: \$$COST"
# Handle terminal states
[ $EXIT -eq 0 ] || break
# Check if milestone is complete
PHASE=$(gsd headless query | jq -r '.state.phase')
[ "$PHASE" = "complete" ] && echo "Milestone complete" && break
# Budget check
TOTAL=$(gsd headless query | jq -r '.cost.total')
if (( $(echo "$TOTAL > 20.00" | bc -l) )); then
echo "Budget limit reached"
break
fi
done
Lightweight pattern using only the instant query command:
bash
PHASE=$(gsd headless query | jq -r '.state.phase')
NEXT_ACTION=$(gsd headless query | jq -r '.next.action')
case "$PHASE" in
complete) echo "Done" ;;
blocked) echo "Needs intervention — exit code 10" ;;
*) [ "$NEXT_ACTION" = "dispatch" ] && gsd headless next ;;
esac
Use --bare to skip user-specific configuration for deterministic CI runs:
bash
gsd headless --bare --output-format json auto 2>/dev/null
This skips CLAUDE.md, AGENTS.md, user settings, and user skills. Bundled GSD extensions and .gsd/ state are still loaded (they're required for GSD to function).
Use --json (or --output-format stream-json) for real-time events:
bash
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
Use --events to receive only specific event types:
bash
# Only phase-relevant events
gsd headless --events agent_end,extension_ui_request auto 2>/dev/null
# Only tool execution events
gsd headless --events tool_execution_start,tool_execution_end auto
Available event 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.
Pre-supply answers and secrets for fully autonomous headless runs:
bash
gsd headless --answers answers.json auto
Answer file schema:
json
{
"questions": { "question_id": "selected_option" },
"secrets": { "API_KEY": "sk-..." },
"defaults": { "strategy": "first_option" }
}
"first_option" (default) or "cancel" for unmatched questionsSee references/answer-injection.md for the full mechanism.
All state lives in .gsd/ as markdown files (version-controllable):
text
.gsd/
PROJECT.md
REQUIREMENTS.md
DECISIONS.md
KNOWLEDGE.md
STATE.md
milestones/
M001/
M001-CONTEXT.md # Requirements, scope, decisions
M001-ROADMAP.md # Slices with tasks, dependencies, checkboxes
M001-SUMMARY.md # Completion summary
slices/
S01/
S01-PLAN.md # Task list
S01-SUMMARY.md # Slice summary
tasks/
T01-PLAN.md # Individual task spec
T01-SUMMARY.md # Task completion summary
State is derived from files on disk — checkboxes in ROADMAP.md and PLAN.md are the source of truth for completion.
See references/commands.md for the complete reference.
CommandPurposeautoRun all queued units (default)nextRun one unitqueryInstant JSON snapshot — state, next dispatch, costs (no LLM)new-milestoneCreate milestone from specdispatch <phase>Force specific phasestop / pauseControl auto-modesteer <desc>Hard-steer plan mid-executionskip / undoUnit controlqueueQueue/reorder milestoneshistoryView execution historydoctorHealth check + auto-fix