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
Answer Injection
Pre-supply answers and secrets to eliminate interactive prompts during headless execution.
Usage
sf headless --answers answers.json auto
sf headless --answers answers.json new-milestone --context spec.md --auto
The --answers flag takes a path to a JSON file containing pre-supplied answers and secrets.
Answer File Schema
{
"questions": {
"question_id": "selected_option_label",
"multi_select_question": ["option_a", "option_b"]
},
"secrets": {
"API_KEY": "sk-...",
"DATABASE_URL": "postgres://..."
},
"defaults": {
"strategy": "first_option"
}
}
Fields
| Field | Type | Description |
|---|---|---|
questions |
Record<string, string | string[]> |
Map question ID → answer. String for single-select, string array for multi-select. |
secrets |
Record<string, string> |
Map env var name → value. Injected into child process environment variables. |
defaults.strategy |
"first_option" | "cancel" |
Fallback for unmatched questions. Default: "first_option". |
How Secrets Work
Secrets are injected as environment variables into the SF child process:
- The orchestrator passes the answer file via
--answers - SF reads the file and sets secret values as env vars in the child process
- When
secure_env_collectruns inside the agent, it finds the keys already inprocess.env - The tool skips the interactive prompt and reports the keys as "already configured"
Secrets are never logged or included in event streams.
How Question Matching Works
Two-phase correlation:
- Observe — SF monitors
tool_execution_startevents forask_user_questionsto extract question metadata (ID, options, allowMultiple) - Match — Subsequent
extension_ui_requestevents are correlated to the metadata and responded to with the pre-supplied answer
Handles out-of-order events (extension_ui_request can arrive before tool_execution_start) via a deferred processing queue with 500ms timeout.
Coexistence with --supervised
Both --answers and --supervised can be active simultaneously. Priority order:
- Answer injector tries first
- If no answer found, supervised mode forwards to the orchestrator
- If no orchestrator response within
--response-timeout, the auto-responder kicks in
Without Answer Injection
Headless mode has built-in auto-responders for all prompt types:
| Prompt Type | Default Behavior |
|---|---|
| Select | Picks first option |
| Confirm | Auto-confirms |
| Input | Empty string |
| Editor | Returns prefill or empty |
Answer injection overrides these defaults with specific answers when precision matters.
Diagnostics
The injector tracks statistics printed in the session summary:
| Stat | Description |
|---|---|
questionsAnswered |
Questions resolved from the answer file |
questionsDefaulted |
Questions handled by the default strategy |
secretsProvided |
Number of secrets injected |
Unused question IDs and secret keys are warned about at exit.
Example: Orchestrator with Answers
# Create answer file
cat > answers.json << 'EOF'
{
"questions": {
"test_framework": "vitest",
"package_manager": "pnpm"
},
"secrets": {
"OPENAI_API_KEY": "sk-...",
"DATABASE_URL": "postgres://localhost:5432/mydb"
},
"defaults": {
"strategy": "first_option"
}
}
EOF
# Run with pre-supplied answers
sf headless --answers answers.json --output-format json auto 2>/dev/null
# Parse result
RESULT=$(sf headless --answers answers.json --output-format json next 2>/dev/null)
echo "$RESULT" | jq '{status: .status, cost: .cost.total}'