Tool API keys are stored globally in `~/.gsd/agent/auth.json` and apply to all projects automatically. Set them once with `/gsd config` — no need to configure per-project `.env` files.
```bash
/gsd config
```
This opens an interactive wizard showing which keys are configured and which are missing. Select a tool to enter its key.
### Supported keys
| Tool | Environment Variable | Purpose | Get a key |
1.`/gsd config` saves keys to `~/.gsd/agent/auth.json`
2. On every session start, `loadToolApiKeys()` reads the file and sets environment variables
3. Keys apply to all projects — no per-project setup required
4. Environment variables (`export BRAVE_API_KEY=...`) take precedence over saved keys
5. Anthropic models don't need Brave/Tavily — they have built-in web search
## MCP Servers
GSD can connect to external MCP servers configured in project files. This is useful for local tools, internal APIs, self-hosted services, or integrations that aren't built in as native GSD extensions.
### Config file locations
GSD reads MCP client configuration from these project-local paths:
-`.mcp.json`
-`.gsd/mcp.json`
If both files exist, server names are merged and the first definition found wins. Use:
-`.mcp.json` for repo-shared MCP configuration you may want to commit
-`.gsd/mcp.json` for local-only MCP configuration you do **not** want to share
### Supported transports
| Transport | Config shape | Use when |
|-----------|--------------|----------|
| `stdio` | `command` + optional `args`, `env`, `cwd` | Launching a local MCP server process |
| `http` | `url` | Connecting to an already-running MCP server over HTTP |
### Example: stdio server
```json
{
"mcpServers": {
"my-server": {
"type": "stdio",
"command": "/absolute/path/to/python3",
"args": ["/absolute/path/to/server.py"],
"env": {
"API_URL": "http://localhost:8000"
}
}
}
}
```
### Example: HTTP server
```json
{
"mcpServers": {
"my-http-server": {
"url": "http://localhost:8080/mcp"
}
}
}
```
### Verifying a server
After adding config, verify it from a GSD session:
- GSD and `gsd-mcp-server` both hydrate supported tool keys saved in `~/.gsd/agent/auth.json`, so MCP configs can safely reference them through `${ENV_VAR}` placeholders without committing raw credentials.
- If a server is team-shared and safe to commit, `.mcp.json` is usually the better home.
- If a server depends on machine-local paths, personal services, or local-only secrets, prefer `.gsd/mcp.json`.
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `GSD_HOME` | `~/.gsd` | Global GSD directory. All paths derive from this unless individually overridden. Affects preferences, skills, sessions, and per-project state. (v2.39) |
| `GSD_PROJECT_ID` | (auto-hash) | Override the automatic project identity hash. Per-project state goes to `$GSD_HOME/projects/<GSD_PROJECT_ID>/` instead of the computed hash. Useful for CI/CD or sharing state across clones of the same repo. (v2.39) |
| `GSD_STATE_DIR` | `$GSD_HOME` | Per-project state root. Controls where `projects/<repo-hash>/` directories are created. Takes precedence over `GSD_HOME` for project state. |
| `GSD_CODING_AGENT_DIR` | `$GSD_HOME/agent` | Agent directory containing managed resources, extensions, and auth. Takes precedence over `GSD_HOME` for agent paths. |
-`execution_simple` — used for tasks classified as "simple" by the [complexity router](./token-optimization.md#complexity-based-task-routing)
-`subagent` — model for delegated subagent tasks (scout, researcher, worker)
- Provider targeting: use `provider/model` format (e.g., `bedrock/claude-sonnet-4-6`) or the `provider` field in object format
- Omit a key to use whatever model is currently active
### Custom Model Definitions (`models.json`)
Define custom models and providers in `~/.gsd/agent/models.json`. This lets you add models not included in the default registry — useful for self-hosted endpoints (Ollama, vLLM, LM Studio), fine-tuned models, proxies, or new provider releases.
GSD resolves models.json with fallback logic:
1.`~/.gsd/agent/models.json` — primary (GSD)
2.`~/.pi/agent/models.json` — fallback (Pi)
3. If neither exists, creates `~/.gsd/agent/models.json`
**Quick example for local models (Ollama):**
```json
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{ "id": "llama3.1:8b" },
{ "id": "qwen2.5-coder:7b" }
]
}
}
}
```
The file reloads each time you open `/model` — no restart needed.
For full documentation including provider configuration, model overrides, OpenAI compatibility settings, and advanced examples, see the [Custom Models Guide](./custom-models.md).
**With fallbacks:**
```yaml
models:
planning:
model: claude-opus-4-6
fallbacks:
- openrouter/z-ai/glm-5
- openrouter/moonshotai/kimi-k2.5
provider: bedrock # optional: target a specific provider
```
When a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list.
### Community Provider Extensions
For providers not built into GSD, community extensions can add full provider support with proper model definitions, thinking format configuration, and interactive API key setup.
Community extensions are recommended over the built-in `alibaba-coding-plan` provider for DashScope models — they use the correct OpenAI-compatible endpoint and include per-model compatibility flags for thinking mode.
### `token_profile`
Coordinates model selection, phase skipping, and context compression. See [Token Optimization](./token-optimization.md).
| `balanced` | Default behavior — all phases run, standard model selection |
| `quality` | All phases run, prefers higher-quality models |
### `phases`
Fine-grained control over which phases run in auto mode:
```yaml
phases:
skip_research: false # skip milestone-level research
skip_reassess: false # skip roadmap reassessment after each slice
skip_slice_research: true # skip per-slice research
reassess_after_slice: true # enable roadmap reassessment after each slice (required for reassessment)
require_slice_discussion: false # pause auto-mode before each slice for discussion
```
These are usually set automatically by `token_profile`, but can be overridden explicitly.
> **Note:** Roadmap reassessment requires `reassess_after_slice: true` to be set explicitly. Without it, reassessment is skipped regardless of `skip_reassess`.
### `skill_discovery`
Controls how GSD finds and applies skills during auto mode.
| Value | Behavior |
|-------|----------|
| `auto` | Skills found and applied automatically |
| `suggest` | Skills identified during research but not auto-installed (default) |
| `off` | Skill discovery disabled |
### `auto_supervisor`
Timeout thresholds for auto mode supervision:
```yaml
auto_supervisor:
model: claude-sonnet-4-6 # optional: model for supervisor (defaults to active model)
soft_timeout_minutes: 20 # warn LLM to wrap up
idle_timeout_minutes: 10 # detect stalls
hard_timeout_minutes: 30 # pause auto mode
```
### `budget_ceiling`
Maximum USD to spend during auto mode. No `$` sign — just the number.
```yaml
budget_ceiling: 50.00
```
### `budget_enforcement`
How the budget ceiling is enforced:
| Value | Behavior |
|-------|----------|
| `warn` | Log a warning but continue |
| `pause` | Pause auto mode (default when ceiling is set) |
| `halt` | Stop auto mode entirely |
### `context_pause_threshold`
Context window usage percentage (0-100) at which auto mode pauses for checkpointing. Set to `0` to disable.
```yaml
context_pause_threshold: 80 # pause at 80% context usage
```
Default: `0` (disabled)
### `uat_dispatch`
Enable automatic UAT (User Acceptance Test) runs after slice completion:
```yaml
uat_dispatch: true
```
### Verification (v2.26)
Configure shell commands that run automatically after every task execution. Failures trigger auto-fix retries before advancing.
```yaml
verification_commands:
- npm run lint
- npm run test
verification_auto_fix: true # auto-retry on failure (default: true)
verification_max_retries: 2 # max retry attempts (default: 2)
```
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `verification_commands` | string[] | `[]` | Shell commands to run after task execution |
The `fetch_page` tool blocks requests to private and internal network addresses to prevent server-side request forgery (SSRF). This protects against the agent being tricked into accessing internal services, cloud metadata endpoints, or local files.
**Blocked by default:**
| Category | Examples |
|----------|----------|
| Private IP ranges | `10.x.x.x`, `172.16-31.x.x`, `192.168.x.x`, `127.x.x.x` |
Public URLs (`https://example.com`, `http://8.8.8.8`) are not affected.
**Allowing specific internal hosts:**
If you need the agent to fetch from internal URLs (self-hosted docs, internal APIs behind a VPN), add their hostnames to `fetchAllowedUrls` in global settings (`~/.gsd/agent/settings.json`):
Allowed hostnames bypass the blocklist checks. The protocol restriction (HTTP/HTTPS only) still applies — `file://` and `ftp://` cannot be allowlisted.
> **Note:** This setting is global-only. Project-level settings.json cannot override the URL allowlist — this prevents a cloned repo from directing `fetch_page` at internal infrastructure.
| `merge_strategy` | string | `"squash"` | How worktree branches merge: `"squash"` (combine all commits) or `"merge"` (preserve individual commits) |
| `isolation` | string | `"worktree"` | Auto-mode isolation: `"worktree"` (separate directory), `"branch"` (work in project root — useful for submodule-heavy repos), or `"none"` (no isolation — commits on current branch, no worktree or milestone branch) |
| `commit_docs` | boolean | `true` | Commit `.gsd/` planning artifacts to git. Set `false` to keep local-only |
| `manage_gitignore` | boolean | `true` | When `false`, GSD will not modify `.gitignore` at all — no baseline patterns, no self-healing. Use if you manage your own `.gitignore` |
| `worktree_post_create` | string | (none) | Script to run after worktree creation. Receives `SOURCE_DIR` and `WORKTREE_DIR` env vars |
| `auto_pr` | boolean | `false` | Automatically create a pull request when a milestone completes. Requires `auto_push: true` and `gh` CLI installed and authenticated |
| `pr_target_branch` | string | (main branch) | Target branch for auto-created PRs (e.g. `develop`, `qa`). Defaults to `main_branch` if not set |
#### `git.worktree_post_create`
Script to run after a worktree is created (both auto-mode and manual `/worktree`). Useful for copying `.env` files, symlinking asset directories, or running setup commands that worktrees don't inherit from the main tree.
The path can be absolute or relative to the project root. The script runs with a 30-second timeout. Failure is non-fatal — GSD logs a warning and continues.
#### `git.auto_pr`
Automatically create a pull request when a milestone completes. Designed for teams using Gitflow or branch-based workflows where work should go through PR review before merging to a target branch.
```yaml
git:
auto_push: true
auto_pr: true
pr_target_branch: develop # or qa, staging, etc.
```
**Requirements:**
-`auto_push: true` — the milestone branch must be pushed before a PR can be created
- [`gh` CLI](https://cli.github.com/) installed and authenticated (`gh auth login`)
**How it works:**
1. Milestone completes → GSD squash-merges the worktree to the main branch
2. Pushes the main branch to remote (if `auto_push: true`)
3. Pushes the milestone branch to remote
4. Creates a PR from the milestone branch to `pr_target_branch` via `gh pr create`
If `pr_target_branch` is not set, the PR targets the `main_branch` (or auto-detected main branch). PR creation failure is non-fatal — GSD logs and continues.
### `github` (v2.39)
GitHub sync configuration. When enabled, GSD auto-syncs milestones, slices, and tasks to GitHub Issues, PRs, and Milestones.
```yaml
github:
enabled: true
repo: "owner/repo" # auto-detected from git remote if omitted
labels: [gsd, auto-generated] # labels applied to created issues/PRs
**macOS delivery:** GSD uses [`terminal-notifier`](https://github.com/julienXX/terminal-notifier) when available, falling back to `osascript`. We recommend installing `terminal-notifier` for reliable notification delivery:
```bash
brew install terminal-notifier
```
Why: `osascript display notification` is attributed to your terminal app (Ghostty, iTerm2, etc.), which may not have notification permissions in System Settings → Notifications. `terminal-notifier` registers as its own app and prompts for permission on first use. See [Troubleshooting: Notifications not appearing on macOS](troubleshooting.md#notifications-not-appearing-on-macos) if notifications aren't working.
Skills can be bare names (looked up in `~/.agents/skills/` and `.agents/skills/`) or absolute paths.
### `skill_rules`
Situational skill routing with human-readable triggers:
```yaml
skill_rules:
- when: task involves authentication
use: [clerk]
- when: frontend styling work
prefer: [frontend-design]
- when: working with legacy code
avoid: [aggressive-refactor]
```
### `custom_instructions`
Durable instructions appended to every session:
```yaml
custom_instructions:
- "Always use TypeScript strict mode"
- "Prefer functional patterns over classes"
```
For project-specific knowledge (patterns, gotchas, lessons learned), use `.gsd/KNOWLEDGE.md` instead — it's injected into every agent prompt automatically. Add entries with `/gsd knowledge rule|pattern|lesson <description>`.
### `RUNTIME.md` — Runtime Context (v2.39)
Declare project-level runtime context in `.gsd/RUNTIME.md`. This file is inlined into task execution prompts, giving the agent accurate information about your runtime environment without relying on hallucinated paths or URLs.
**Location:** `.gsd/RUNTIME.md`
**Example:**
```markdown
# Runtime Context
## API Endpoints
- Main API: https://api.example.com
- Cache: redis://localhost:6379
## Environment Variables
- DEPLOYMENT_ENV: staging
- DB_POOL_SIZE: 20
## Local Services
- PostgreSQL: localhost:5432
- Redis: localhost:6379
```
Use this for information that the agent needs during execution but that doesn't belong in `DECISIONS.md` (architectural) or `KNOWLEDGE.md` (patterns/rules). Common examples: API base URLs, service ports, deployment targets, and environment-specific configuration.
### `dynamic_routing`
Complexity-based model routing. See [Dynamic Model Routing](./dynamic-model-routing.md).