singularity-forge/docs/user-docs/configuration.md
2026-05-08 01:34:07 +02:00

839 lines
29 KiB
Markdown

# Configuration
SF preferences live in `~/.sf/PREFERENCES.md` (global) or `.sf/PREFERENCES.md` (project-local). Manage interactively with `/prefs`.
## `/prefs` Commands
| Command | Description |
|---------|-------------|
| `/prefs` | Open the global preferences wizard (default) |
| `/prefs global` | Interactive wizard for global preferences (`~/.sf/PREFERENCES.md`) |
| `/prefs project` | Interactive wizard for project preferences (`.sf/PREFERENCES.md`) |
| `/prefs status` | Show current preference files, merged values, and skill resolution status |
| `/prefs wizard` | Alias for `/prefs global` |
| `/prefs setup` | Alias for `/prefs wizard` — creates preferences file if missing |
| `/prefs import-claude` | Import Claude marketplace plugins and skills as namespaced SF components |
| `/prefs import-claude global` | Import to global scope |
| `/prefs import-claude project` | Import to project scope |
## Preferences File Format
Preferences use YAML frontmatter in a markdown file:
```yaml
---
version: 1
models:
research: claude-sonnet-4-6
planning: claude-opus-4-6
execution: claude-sonnet-4-6
completion: claude-sonnet-4-6
skill_discovery: suggest
auto_supervisor:
soft_timeout_minutes: 20
idle_timeout_minutes: 10
hard_timeout_minutes: 30
budget_ceiling: 50.00
token_profile: balanced
---
```
## Global vs Project Preferences
| Scope | Path | Applies to |
|-------|------|-----------|
| Global | `~/.sf/PREFERENCES.md` | All projects |
| Project | `.sf/PREFERENCES.md` | Current project only |
**Merge behavior:**
- **Scalar fields** (`skill_discovery`, `budget_ceiling`): project wins if defined
- **Array fields** (`always_use_skills`, etc.): concatenated (global first, then project)
- **Object fields** (`models`, `git`, `auto_supervisor`): shallow-merged, project overrides per-key
## Global API Keys (`/config`)
Tool API keys are stored globally in `~/.sf/agent/auth.json` and apply to all projects automatically. Set them once with `/config` — no need to configure per-project `.env` files.
```bash
/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 |
|------|---------------------|---------|-----------|
| Tavily Search | `TAVILY_API_KEY` | Web search for non-Anthropic models | [tavily.com/app/api-keys](https://tavily.com/app/api-keys) |
| MiniMax Search | `MINIMAX_API_KEY` (`MINIMAX_CODE_PLAN_KEY` and `MINIMAX_CODING_API_KEY` also accepted) | Web search for non-Anthropic models | MiniMax key |
| Brave Search | `BRAVE_API_KEY` | Web search for non-Anthropic models | [brave.com/search/api](https://brave.com/search/api) |
| Context7 Docs | `CONTEXT7_API_KEY` | Library documentation lookup | [context7.com/dashboard](https://context7.com/dashboard) |
### How it works
1. `/config` saves keys to `~/.sf/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
SF 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 SF extensions.
### Config file locations
SF reads MCP client configuration from these project-local paths:
- `.mcp.json`
- `.sf/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
- `.sf/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 SF session:
```text
mcp_servers
mcp_discover(server="my-server")
mcp_call(server="my-server", tool="<tool_name>", args={...})
```
Recommended verification order:
1. `mcp_servers` — confirms SF can see the config file and parse the server entry
2. `mcp_discover` — confirms the server process starts and responds to `tools/list`
3. `mcp_call` — confirms at least one real tool invocation works
### Notes
- Use absolute paths for local executables and scripts when possible.
- For `stdio` servers, prefer setting required environment variables directly in the MCP config instead of relying on an interactive shell profile.
- SF hydrates supported model and tool keys saved in `~/.sf/agent/auth.json`, so external 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 `.sf/mcp.json`.
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `SF_HOME` | `~/.sf` | Global SF directory. All paths derive from this unless individually overridden. Affects preferences, skills, sessions, and per-project state. (v2.39) |
| `SF_PROJECT_ID` | (auto-hash) | Override the automatic project identity hash. Per-project state goes to `$SF_HOME/projects/<SF_PROJECT_ID>/` instead of the computed hash. Useful for CI/CD or sharing state across clones of the same repo. (v2.39) |
| `SF_STATE_DIR` | `$SF_HOME` | Per-project state root. Controls where `projects/<repo-hash>/` directories are created. Takes precedence over `SF_HOME` for project state. |
| `SF_CODING_AGENT_DIR` | `$SF_HOME/agent` | Agent directory containing managed resources, extensions, and auth. Takes precedence over `SF_HOME` for agent paths. |
| `SF_ALLOWED_COMMAND_PREFIXES` | (built-in list) | Comma-separated command prefixes allowed for `!command` value resolution. Overrides `allowedCommandPrefixes` in settings.json. See [Custom Models — Command Allowlist](custom-models.md#command-allowlist). |
| `SF_FETCH_ALLOWED_URLS` | (none) | Comma-separated hostnames exempted from `fetch_page` URL blocking. Overrides `fetchAllowedUrls` in settings.json. See [URL Blocking](#url-blocking-fetch_page). |
## All Settings
### `models`
Per-phase model selection. Each key accepts a model string or an object with fallbacks.
```yaml
models:
research: claude-sonnet-4-6
planning:
model: claude-opus-4-6
fallbacks:
- openrouter/z-ai/glm-5
execution: claude-sonnet-4-6
execution_simple: claude-haiku-4-5-20250414
completion: claude-sonnet-4-6
subagent: claude-sonnet-4-6
```
**Phases:** `research`, `planning`, `execution`, `execution_simple`, `completion`, `subagent`
- `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 `~/.sf/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.
SF resolves models.json with fallback logic:
1. `~/.sf/agent/models.json` — primary (SF)
2. `~/.pi/agent/models.json` — fallback (Pi)
3. If neither exists, creates `~/.sf/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), SF automatically tries the next model in the `fallbacks` list.
### Community Provider Extensions
For providers not built into SF, community extensions can add full provider support with proper model definitions, thinking format configuration, and interactive API key setup.
| Extension | Provider | Models | Install |
|-----------|----------|--------|---------|
| [`pi-dashscope`](https://www.npmjs.com/package/pi-dashscope) | Alibaba DashScope (ModelStudio) | Qwen3, GLM-5, MiniMax M2.5, Kimi K2.5 | `sf install npm:pi-dashscope` |
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).
Values: `budget`, `balanced` (default), `quality`
| Profile | Behavior |
|---------|----------|
| `budget` | Skips research + reassessment phases, uses cheaper models |
| `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 autonomous 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 autonomous 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 SF finds and applies skills during autonomous 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 autonomous 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 autonomous mode
solver_max_iterations: 30000
solver_eval_on_autonomous_exit: true
completion_nudge_after: 10 # complete-slice tool calls before nudging sf_slice_complete
```
### `budget_ceiling`
Maximum USD to spend during autonomous 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 autonomous mode (default when ceiling is set) |
| `halt` | Stop autonomous mode entirely |
### `context_pause_threshold`
Context window usage percentage (0-100) at which autonomous 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 |
| `verification_auto_fix` | boolean | `true` | Auto-retry when verification fails |
| `verification_max_retries` | number | `2` | Maximum auto-fix retry attempts |
### URL Blocking (`fetch_page`)
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` |
| Link-local / cloud metadata | `169.254.x.x` (AWS/GCP instance metadata) |
| Cloud metadata hostnames | `metadata.google.internal`, `instance-data` |
| Localhost | `localhost` (any port) |
| Non-HTTP protocols | `file://`, `ftp://` |
| IPv6 private ranges | `::1`, `fc00:`, `fd`, `fe80:` |
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 (`~/.sf/agent/settings.json`):
```json
{
"fetchAllowedUrls": ["internal-docs.company.com", "192.168.1.50"]
}
```
Alternatively, set the `SF_FETCH_ALLOWED_URLS` environment variable (comma-separated). The env var takes precedence over settings.json:
```bash
export SF_FETCH_ALLOWED_URLS="internal-docs.company.com,192.168.1.50"
```
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.
### `auto_report` (v2.26)
Auto-generate HTML reports after milestone completion:
```yaml
auto_report: true # default: true
```
Reports are written to `.sf/reports/` as self-contained HTML files with embedded CSS/JS.
### `unique_milestone_ids`
Generate milestone IDs with a random suffix to avoid collisions in team workflows:
```yaml
unique_milestone_ids: true
# Produces: M001-eh88as instead of M001
```
### `git`
Git behavior configuration. All fields optional:
```yaml
git:
auto_push: false # push commits to remote after committing
push_branches: false # push milestone branch to remote
remote: origin # git remote name
snapshots: true # WIP snapshot commits during long tasks
pre_merge_check: auto # run checks before worktree merge (true/false/"auto")
commit_type: feat # override conventional commit prefix
main_branch: main # primary branch name
merge_strategy: squash # how worktree branches merge: "squash" or "merge"
isolation: worktree # git isolation: "worktree", "branch", or "none"
commit_docs: true # commit .sf/ artifacts to git (set false to keep local)
manage_gitignore: true # set false to prevent SF from modifying .gitignore
worktree_post_create: .sf/hooks/post-worktree-create # script to run after worktree creation
auto_pr: false # create a PR on milestone completion (requires push_branches)
pr_target_branch: develop # target branch for auto-created PRs (default: main branch)
```
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `auto_push` | boolean | `false` | Push commits to remote after committing |
| `push_branches` | boolean | `false` | Push milestone branch to remote |
| `remote` | string | `"origin"` | Git remote name |
| `snapshots` | boolean | `true` | WIP snapshot commits during long tasks |
| `pre_merge_check` | bool/string | `"auto"` | Run checks before merge (`true`/`false`/`"auto"`) |
| `commit_type` | string | (inferred) | Override conventional commit prefix (`feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`) |
| `main_branch` | string | `"main"` | Primary branch name |
| `merge_strategy` | string | `"squash"` | How worktree branches merge: `"squash"` (combine all commits) or `"merge"` (preserve individual commits) |
| `isolation` | string | `"worktree"` | Autonomous 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 `.sf/` planning artifacts to git. Set `false` to keep local-only |
| `manage_gitignore` | boolean | `true` | When `false`, SF 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 autonomous 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.
```yaml
git:
worktree_post_create: .sf/hooks/post-worktree-create
```
The script receives two environment variables:
- `SOURCE_DIR` — the original project root
- `WORKTREE_DIR` — the newly created worktree path
Example hook script (`.sf/hooks/post-worktree-create`):
```bash
#!/bin/bash
# Copy environment files and symlink assets into the new worktree
cp "$SOURCE_DIR/.env" "$WORKTREE_DIR/.env"
cp "$SOURCE_DIR/.env.local" "$WORKTREE_DIR/.env.local" 2>/dev/null || true
ln -sf "$SOURCE_DIR/assets" "$WORKTREE_DIR/assets"
```
The path can be absolute or relative to the project root. The script runs with a 30-second timeout. Failure is non-fatal — SF 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 → SF 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 — SF logs and continues.
### `github` (v2.39)
GitHub sync configuration. When enabled, SF 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: [sf, auto-generated] # labels applied to created issues/PRs
project: "Project ID" # optional GitHub Project board
```
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `enabled` | boolean | `false` | Enable GitHub sync |
| `repo` | string | (auto-detected) | GitHub repository in `owner/repo` format |
| `labels` | string[] | `[]` | Labels to apply to created issues and PRs |
| `project` | string | (none) | GitHub Project ID for project board integration |
**Requirements:**
- `gh` CLI installed and authenticated (`gh auth login`)
- Sync mapping is persisted in `.sf/.github-sync.json`
- Rate-limit aware — skips sync when GitHub API rate limit is low
**Commands:**
- `/github-sync bootstrap` — initial setup and sync
- `/github-sync status` — show sync mapping counts
### `notifications`
Control what notifications SF sends during autonomous mode:
```yaml
notifications:
enabled: true
on_complete: true # notify on unit completion
on_error: true # notify on errors
on_budget: true # notify on budget thresholds
on_milestone: true # notify when milestone finishes
on_attention: true # notify when manual attention needed
```
### `remote_questions`
Route interactive questions to Slack or Discord when run control and the
permission profile require human input:
```yaml
remote_questions:
channel: slack # or discord
channel_id: "C1234567890"
timeout_minutes: 15 # question timeout (1-30 minutes)
poll_interval_seconds: 10 # poll interval (2-30 seconds)
```
### `post_unit_hooks`
Custom hooks that fire after specific unit types complete:
```yaml
post_unit_hooks:
- name: code-review
after: [execute-task]
prompt: "Review the code changes for quality and security issues."
model: claude-opus-4-6 # optional: model override
max_cycles: 1 # max fires per trigger (1-10, default: 1)
artifact: REVIEW.md # optional: skip if this file exists
retry_on: NEEDS-REWORK.md # optional: re-run trigger unit if this file appears
agent: review-agent # optional: agent definition to use
enabled: true # optional: disable without removing
```
**Known unit types for `after`:** `research-milestone`, `plan-milestone`, `research-slice`, `plan-slice`, `execute-task`, `complete-slice`, `replan-slice`, `reassess-roadmap`, `run-uat`
**Prompt substitutions:** `{milestoneId}`, `{sliceId}`, `{taskId}` are replaced with current context values.
### `pre_dispatch_hooks`
Hooks that intercept units before dispatch. Three actions available:
**Modify** — prepend/append text to the unit prompt:
```yaml
pre_dispatch_hooks:
- name: add-standards
before: [execute-task]
action: modify
prepend: "Follow our coding standards document."
append: "Run linting after changes."
```
**Skip** — skip the unit entirely:
```yaml
pre_dispatch_hooks:
- name: skip-research
before: [research-slice]
action: skip
skip_if: RESEARCH.md # optional: only skip if this file exists
```
**Replace** — replace the unit prompt entirely:
```yaml
pre_dispatch_hooks:
- name: custom-execute
before: [execute-task]
action: replace
prompt: "Execute the task using TDD methodology."
unit_type: execute-task-tdd # optional: override unit type label
model: claude-opus-4-6 # optional: model override
```
All pre-dispatch hooks support `enabled: true/false` to toggle without removing.
### `always_use_skills` / `prefer_skills` / `avoid_skills`
Skill routing preferences:
```yaml
always_use_skills:
- debug-like-expert
prefer_skills:
- frontend-design
avoid_skills: []
```
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 `.sf/KNOWLEDGE.md` instead — it's injected into every agent prompt automatically. Add entries with `/knowledge rule|pattern|lesson <description>`.
### `RUNTIME.md` — Runtime Context (v2.39)
Declare project-level runtime context in `.sf/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:** `.sf/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).
```yaml
dynamic_routing:
enabled: true
capability_routing: true # score models by task capability (v2.59)
tier_models:
light: claude-haiku-4-5
standard: claude-sonnet-4-6
heavy: claude-opus-4-6
escalate_on_failure: true
budget_pressure: true
cross_provider: true
```
### `context_management` (v2.59)
Controls observation masking and tool result truncation during autonomous mode sessions. Reduces context bloat between compactions with zero LLM overhead.
```yaml
context_management:
observation_masking: true # replace old tool results with placeholders (default: true)
observation_mask_turns: 8 # keep results from last N user turns (1-50, default: 8)
compaction_threshold_percent: 0.70 # target compaction at 70% context usage (0.5-0.95, default: 0.70)
tool_result_max_chars: 800 # cap individual tool result content (200-10000, default: 800)
```
### `service_tier` (v2.42)
OpenAI service tier preference for supported models. Toggle with `/fast`.
| Value | Behavior |
|-------|----------|
| `"priority"` | Priority tier — 2x cost, faster responses |
| `"flex"` | Flex tier — 0.5x cost, slower responses |
| (unset) | Default tier |
```yaml
service_tier: priority
```
### `forensics_dedup` (v2.43)
Opt-in: search existing issues and PRs before filing from `/forensics`. Uses additional AI tokens.
```yaml
forensics_dedup: true # default: false
```
### `show_token_cost` (v2.44)
Opt-in: show per-prompt and cumulative session token cost in the footer.
```yaml
show_token_cost: true # default: false
```
### `auto_visualize`
Show the workflow visualizer automatically after milestone completion:
```yaml
auto_visualize: true
```
See [Workflow Visualizer](./visualizer.md).
### `parallel`
Run multiple milestones simultaneously. Disabled by default.
```yaml
parallel:
enabled: false # Master toggle
max_workers: 2 # Concurrent workers (1-4)
budget_ceiling: 50.00 # Aggregate cost limit in USD
merge_strategy: "per-milestone" # "per-slice" or "per-milestone"
auto_merge: "confirm" # "auto", "confirm", or "manual"
```
See [Parallel Orchestration](./parallel-orchestration.md) for full documentation.
## Full Example
```yaml
---
version: 1
# Model selection
models:
research: openrouter/deepseek/deepseek-r1
planning:
model: claude-opus-4-6
fallbacks:
- openrouter/z-ai/glm-5
execution: claude-sonnet-4-6
execution_simple: claude-haiku-4-5-20250414
completion: claude-sonnet-4-6
# Token optimization
token_profile: balanced
# Dynamic model routing
dynamic_routing:
enabled: true
escalate_on_failure: true
budget_pressure: true
# Budget
budget_ceiling: 25.00
budget_enforcement: pause
context_pause_threshold: 80
# Supervision
auto_supervisor:
soft_timeout_minutes: 15
hard_timeout_minutes: 25
# Git
git:
auto_push: true
merge_strategy: squash
isolation: worktree # "worktree", "branch", or "none"
commit_docs: true
# Skills
skill_discovery: suggest
skill_staleness_days: 60 # Skills unused for N days get deprioritized (0 = disabled)
always_use_skills:
- debug-like-expert
skill_rules:
- when: task involves authentication
use: [clerk]
# Notifications
notifications:
on_complete: false
on_milestone: true
on_attention: true
# Visualizer
auto_visualize: true
# Service tier
service_tier: priority # "priority" or "flex" (for /fast)
# Diagnostics
forensics_dedup: true # deduplicate before filing forensics issues
show_token_cost: true # show per-prompt cost in footer
# Hooks
post_unit_hooks:
- name: code-review
after: [execute-task]
prompt: "Review {sliceId}/{taskId} for quality and security."
artifact: REVIEW.md
---
```