46 KiB
SF Preferences Reference
Full documentation for ~/.sf/PREFERENCES.md (global) and .sf/PREFERENCES.md (project).
Notes
- Keep this skill-first.
- Prefer explicit skill names or absolute paths.
- Use absolute paths for personal/local skills when you want zero ambiguity.
- These preferences guide which skills SF should load and follow; they do not override higher-priority instructions in the current conversation.
- For Claude marketplace/plugin import behavior, see
~/.sf/agent/extensions/sf/docs/claude-marketplace-import.md.
Semantics
Empty Arrays vs Omitted Fields
Empty arrays ([]) are equivalent to omitting the field entirely. During validation, SF deletes empty arrays from the preferences object (see validatePreferences() in preferences.ts):
for (const key of [
"always_use_skills",
"prefer_skills",
"avoid_skills",
"custom_instructions",
] as const) {
if (validated[key] && validated[key]!.length === 0) {
delete validated[key];
}
}
These are functionally identical:
# Explicit empty arrays — will be normalized away
prefer_skills: []
avoid_skills: []
skill_rules: []
# Omitted entirely — same result
# (just don't write these fields)
Recommendation: Omit fields you don't need. Empty arrays add noise with no effect.
Global vs Project Preferences
Preferences are loaded from two locations and merged:
- Global:
~/.sf/PREFERENCES.md— applies to all projects - Project:
.sf/PREFERENCES.md— applies to the current project only
Merge behavior (see mergePreferences() in preferences.ts):
- Scalar fields (
skill_discovery,budget_ceiling, etc.): Project wins if defined, otherwise global. Uses nullish coalescing (??). - Array fields (
always_use_skills,prefer_skills, etc.): Concatenated viamergeStringLists()(global first, then project). - Object fields (
models,git,auto_supervisor): Shallow merge via spread operator{ ...base, ...override }.
For models, project settings override global at the phase level. If global has planning: opus and project has planning: sonnet, the project wins. But if project omits research, global's research setting is preserved.
Skill Discovery vs Skill Preferences
These are separate concerns:
| Field | What it controls | Code reference |
|---|---|---|
skill_discovery |
Whether SF looks for relevant skills during research | resolveSkillDiscoveryMode() in preferences.ts |
always_use_skills, prefer_skills, avoid_skills |
Which skills to use when they're found relevant | renderPreferencesForSystemPrompt() in preferences.ts |
Setting prefer_skills: [] does not disable skill discovery — it just means you have no preference overrides. Use skill_discovery: off to disable discovery entirely.
Field Guide
-
version: schema version. Start at1. -
mode: workflow mode —"solo"or"team". Sets sensible defaults for git and project settings based on your workflow. Mode defaults are the lowest priority layer — any explicit preference overrides them. Omit to configure everything manually.Setting soloteamgit.auto_pushtruefalsegit.push_branchesfalsetruegit.pre_merge_checkfalsetruegit.merge_strategy"squash""squash"git.isolation"worktree""worktree"unique_milestone_idsfalsetrueQuick setup:
/mode(global) or/mode project(project-level). -
always_use_skills: skills SF should use whenever they are relevant. -
prefer_skills: soft defaults SF should prefer when relevant. -
avoid_skills: skills SF should avoid unless clearly needed. -
skill_rules: situational rules with a human-readablewhentrigger and one or more ofuse,prefer, oravoid. -
custom_instructions: extra durable instructions related to skill use. For operational project knowledge (recurring rules, gotchas, patterns), use.sf/KNOWLEDGE.mdinstead — it's injected into every agent prompt automatically and agents can append to it during execution. -
models: per-stage model selection (applies to both autonomous mode and guided-flow dispatches). Keys:research,planning,discuss,execution,execution_simple,completion,validation,subagent. Values can be:- Simple string:
"claude-sonnet-4-6"— single model, no fallbacks - Provider-qualified string:
"bedrock/claude-sonnet-4-6"— targets a specific provider when the same model ID exists across multiple providers - Object with fallbacks:
{ model: "claude-opus-4-6", fallbacks: ["glm-5", "minimax-m2.5"] }— tries fallbacks in order if primary fails - Object with provider:
{ model: "claude-opus-4-6", provider: "bedrock" }— explicit provider targeting in object format - Omit a key to use whatever model is currently active (except
discussandvalidationwhich fall back toplanningwhen unset). Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.). discuss— used for milestone/slice discussion (interactive context gathering). Falls back toplanningif unset.validation— used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back toplanningif unset.
- Simple string:
-
persist_model_changes: boolean — controls whethersetModel()updates also persist to the default provider/model settings. Default:true. Setfalseto keep autonomous mode and recovery model switches session-local. -
skill_staleness_days: number — skills unused for this many days get deprioritized during discovery. Set to0to disable staleness tracking. Default:60. -
skill_discovery: controls how SF discovers and applies skills during autonomous mode. Valid values:auto— skills are found and applied automatically without prompting.suggest— (default) skills are identified during research but not installed automatically.off— skill discovery is disabled entirely.
-
auto_supervisor: configures the autonomous mode supervisor that monitors agent progress and enforces timeouts. Keys:model: model ID to use for the supervisor process (defaults to the currently active model).soft_timeout_minutes: minutes before the supervisor issues a soft warning (default: 20).idle_timeout_minutes: minutes of inactivity before the supervisor intervenes (default: 10).hard_timeout_minutes: minutes before the supervisor forces termination (default: 30).solver_max_iterations: maximum autonomous solver iterations for one unit before pausing (default:30000, min:1, max:100000).solver_eval_on_autonomous_exit: automatically run and record the built-in solver eval when/autonomousexits (default:true; setfalseonly to disable lifecycle eval evidence).completion_nudge_after: tool calls in a complete-slice unit before nudging the agent to callsf_slice_complete(default: 10; set0to disable).runaway_guard_enabled: enable active-loop diagnosis for long-running units (default:true).runaway_tool_call_warning: unit tool calls before a runaway warning (default:60; set0to disable this signal).runaway_token_warning: unit tokens before a runaway warning (default:1000000; set0to disable this signal).runaway_elapsed_minutes: elapsed unit minutes before a runaway warning (default:20; set0to disable this signal).runaway_changed_files_warning: changed files since unit start before a runaway warning (default:75; set0to disable this signal).runaway_diagnostic_turns: number of diagnostic turns the agent gets before pause if budget keeps growing (default:2).runaway_hard_pause: pause autonomous mode after diagnostic turns if budget keeps growing (default:true).
-
git: configures SF's git behavior. All fields are optional — omit any to use defaults. Keys:auto_push: boolean — automatically push commits to the remote after committing. Default:false.push_branches: boolean — push the milestone branch to the remote after commits. Default:false.remote: string — git remote name to push to. Default:"origin".snapshots: boolean — create snapshot commits (WIP saves) during long-running tasks. Default:true.pre_merge_check: boolean or"auto"— run pre-merge checks before merging a worktree back to the integration branch.truealways runs,falsenever runs,"auto"runs when CI is detected. Default:"auto".commit_type: string — override the conventional commit type prefix. Must be one of:feat,fix,refactor,docs,test,chore,perf,ci,build,style. Default: inferred from diff content.main_branch: string — the primary branch name for new git repos (e.g.,"main","master","trunk"). Also used bygetMainBranch()as the preferred branch when auto-detection is ambiguous. Default:"main".merge_strategy:"squash"or"merge"— controls how worktree branches are merged back."squash"combines all commits into one;"merge"preserves individual commits. Default:"squash".isolation:"worktree","branch", or"none"— controls autonomous mode git isolation strategy."worktree"creates a milestone worktree for isolated work;"branch"works directly in the project root but creates a milestone branch (useful for submodule-heavy repos);"none"works directly on the current branch with no worktree or milestone branch (ideal for assisted mode with hot reloads). Default:"worktree".manage_gitignore: boolean — whenfalse, SF will not touch.gitignoreat all. Useful when your project has a strictly managed.gitignoreand you don't want SF adding entries. Default:true.worktree_post_create: string — script to run after a worktree is created (both autonomous mode and manual/worktree). ReceivesSOURCE_DIRandWORKTREE_DIRas environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.auto_pr: boolean — automatically create a GitHub pull request after a milestone branch is merged. RequiresghCLI to be installed. Default:false.pr_target_branch: string — branch to target whenauto_pris enabled. Defaults tomain_branchwhen omitted.- Deprecated:
commit_docs— no longer valid;.sf/is always gitignored. Remove this setting. - Deprecated:
merge_to_main— no longer valid; milestone-level merge is always used. Remove this setting.
-
unique_milestone_ids: boolean — whentrue, generates milestone IDs inM{seq}-{rand6}format (e.g.M001-eh88as) instead of plain sequentialM001. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existingM001-style milestones remain valid. Default:false. -
budget_ceiling: number — maximum dollar amount to spend on autonomous mode. When reached, behavior is controlled bybudget_enforcement. Default: no limit. -
budget_enforcement:"warn","pause", or"halt"— action taken whenbudget_ceilingis reached.warn— log a warning but continue execution.pause— pause autonomous mode and wait for user confirmation.halt— stop autonomous mode immediately.- Default:
"pause".
-
context_pause_threshold: number (0-100) — context window usage percentage at which autonomous mode should pause to suggest checkpointing. Set to0to disable. Default:0(disabled). -
token_profile:"budget","balanced","quality", or"burn-max"— coordinates model selection, phase skipping, and context compression.budgetskips research/reassessment and uses cheaper models;balanced(default) skips research/reassessment to reduce token burn;qualityprefers higher-quality models;burn-maxkeeps full-context defaults, disables downgrade routing, and keeps phase skips off. -
phases: fine-grained control over which phases run. Usually set bytoken_profile, but can be overridden. Keys:skip_research: boolean — skip milestone-level research. Default:false.reassess_after_slice: boolean — run roadmap reassessment after each completed slice. Default:true.skip_reassess: boolean — force-disable roadmap reassessment even ifreassess_after_sliceis enabled. Default:false.skip_slice_research: boolean — skip per-slice research. Default:false.
-
codebase: configures fallback.sf/CODEBASE.mdand the optional Sift code-intelligence backend. Keys:exclude_patterns: string[] — extra file or directory patterns to omit from CODEBASE.md.max_files: number — maximum files to include in CODEBASE.md. Default:500.collapse_threshold: number — files-per-directory threshold before collapsing a directory summary. Default:20.indexer_backend:"sift"or"none"— codebase-indexer backend used for prompt guidance and/codebase indexer status. Default:"sift"./codebase indexer statusreports Sift status. Installrupurt/siftonPATHor setSIFT_PATH.
-
remote_questions: route interactive questions to Slack/Discord for machine-surface autonomous runs. Keys:channel:"slack"or"discord"— channel type.channel_id: string or number — channel ID.timeout_minutes: number — question timeout in minutes (clamped 1-30).poll_interval_seconds: number — poll interval in seconds (clamped 2-30).
-
notifications: configures desktop notification behavior during autonomous mode. Keys:enabled: boolean — master toggle for all notifications. Default:true.on_complete: boolean — notify when a unit completes. Default:true.on_error: boolean — notify on errors. Default:true.on_budget: boolean — notify when budget thresholds are reached. Default:true.on_milestone: boolean — notify when a milestone finishes. Default:true.on_attention: boolean — notify when manual attention is needed. Default:true.
-
cmux: configures cmux terminal integration when SF is running inside a cmux workspace. Keys:enabled: boolean — master toggle for cmux integration. Default:false.notifications: boolean — route desktop notifications through cmux. Default:truewhen enabled.sidebar: boolean — publish status, progress, and log metadata to the cmux sidebar. Default:truewhen enabled.splits: boolean — run supported subagent work in visible cmux splits. Default:false.browser: boolean — reserve the future browser integration flag. Default:false.
-
dynamic_routing: configures the dynamic model router that adjusts model selection based on task complexity. Keys:enabled: boolean — enable dynamic routing. Default:false.tier_models: object — model overrides per complexity tier. Keys:light,standard,heavy. Values are model ID strings.escalate_on_failure: boolean — escalate to a higher-tier model when the current one fails. Default:true.budget_pressure: boolean — downgrade model tier when budget is under pressure. Default:true.cross_provider: boolean — allow routing across different providers. Default:true.hooks: boolean — enable routing hooks. Default:true.capability_routing: boolean — enable capability-profile scoring for model selection within a tier. Requiresenabled: true. Default:false.
-
uok: orchestration kernel controls. Keys:enabled: boolean — enable kernel wrappers and contract observers. Default:true.gates.enabled: boolean — route checks through the unified gate runner and persistgate_runs. Default:true.model_policy.enabled: boolean — enforce policy filtering before model capability scoring. Default:true.execution_graph.enabled: boolean — enable DAG scheduler facade/adapters for execution. Default:true.gitops.enabled: boolean — persist turn-level git transaction records. Default:true.gitops.turn_action:"commit"|"snapshot"|"status-only"— turn transaction mode. Default:"commit".gitops.turn_push: boolean — whether turn transactions should include push intent metadata. Default:false.audit_envelope.enabled: boolean — dual-write audit envelope events. Default:true.planning_flow.enabled: boolean — enable bounded clarify/research/draft/compile planning flow. Default:true.
-
context_management: configures context hygiene for autonomous mode sessions. Keys:observation_masking: boolean — mask old tool results to reduce context bloat. Default:true.observation_mask_turns: number — keep this many recent turns verbatim (1-50). Default:8.compaction_threshold_percent: number — trigger compaction at this % of context window (0.5-0.95). Lower values fire compaction earlier, reducing drift. Default:0.70.tool_result_max_chars: number — max chars per tool result in SF sessions (200-10000). Default:800.
-
auto_visualize: boolean — show a visualizer hint after each milestone completion in autonomous mode. Default:false. -
auto_report: boolean — generate an HTML report snapshot after each milestone completion. Default:true. -
search_provider:"brave","tavily","serper","exa","ollama","combosearch","native", or"auto"— selects the search backend for research phases."combosearch"fans out across all configured custom search backends and merges the results."native"forces Anthropic's built-in web search only; provider values force that backend and disable native search;"auto"uses the default heuristic. Default:"auto". -
context_selection:"full"or"smart"— controls how files are inlined into context."full"inlines entire files;"smart"uses semantic chunking to include only the most relevant sections. Default is derived fromtoken_profile. -
parallel: configures parallel orchestration for running multiple slices concurrently. Keys:enabled: boolean — enable parallel execution. Default:false.max_workers: number — maximum concurrent workers (1-4). Default:2.budget_ceiling: number — optional per-parallel-run budget ceiling.merge_strategy:"per-slice"or"per-milestone"— when to merge worktree results back. Default:"per-milestone".auto_merge:"auto","confirm", or"manual"— merge behavior after completion."auto"merges immediately;"confirm"asks first;"manual"leaves branches for you. Default:"confirm".worker_model: string — optional model override for parallel milestone workers. When set, workers use this model (e.g."claude-haiku-4-5") instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.
-
verification_commands: string[] — shell commands to run as verification after task execution (e.g.,["npm test", "npm run lint"]). Commands run in order; if any fails, the task is marked as needing fixes. -
verification_auto_fix: boolean — whentrue, automatically attempt to fix verification failures instead of just reporting them. Default:false. -
verification_max_retries: number — maximum number of fix-and-retry cycles for verification failures. Default:0(no retries). -
uat_dispatch: boolean — whentrue, enables UAT (User Acceptance Testing) dispatch mode. Default:false. -
post_unit_hooks: array — hooks that fire after a unit completes. Each entry has:name: string — unique hook identifier.after: string[] — unit types that trigger this hook (e.g.,["execute-task"]).prompt: string — prompt sent to the LLM. Supports{milestoneId},{sliceId},{taskId}substitutions.max_cycles: number — max times this hook fires per trigger (default: 1, max: 10).model: string — optional model override.artifact: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).retry_on: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.agent: string — agent definition file to use for hook execution.enabled: boolean — toggle without removing (default:true).
-
pre_dispatch_hooks: array — hooks that fire before a unit is dispatched. Each entry has:name: string — unique hook identifier.before: string[] — unit types to intercept.action:"modify","skip", or"replace"— what to do with the unit.prepend: string — text prepended to unit prompt (for"modify"action).append: string — text appended to unit prompt (for"modify"action).prompt: string — replacement prompt (for"replace"action; required when action is"replace").unit_type: string — override unit type label (for"replace"action).skip_if: string — for"skip"action: only skip if this file exists (relative to unit dir).model: string — optional model override when this hook fires.enabled: boolean — toggle without removing (default:true).
Action validation:
"modify"requires at least one ofprependorappend."replace"requiresprompt."skip"is valid with no additional fields.
Known unit types for
before/after:research-milestone,plan-milestone,research-slice,plan-slice,execute-task,complete-slice,replan-slice,reassess-roadmap,run-uat. -
experimental: opt-in experimental features. All features here are off by default — you must explicitly set each one totrueto enable it. Features in this block may change or be removed without a deprecation cycle while in experimental status. Keys:rtk: boolean — enable RTK (Real-Time Kompression) shell-command compression. When enabled, SF wraps shell commands through the RTK binary to reduce token usage during command execution. RTK is downloaded automatically on first use if not already installed. Default:false(opt-in required). SetSF_RTK_DISABLED=1in the environment to force-disable regardless of this preference.
Best Practices
- Keep
always_use_skillsshort. - Use
skill_rulesfor situational routing, not broad personality preferences. - Prefer skill names for stable built-in skills.
- Prefer absolute paths for local personal skills.
- Omit fields you don't need — empty arrays add noise with no effect.
Workflow Mode Examples
Solo developer — auto-push, simple IDs:
---
version: 1
mode: solo
---
Equivalent to setting git.auto_push: true, git.push_branches: false, git.pre_merge_check: false, git.merge_strategy: squash, git.isolation: worktree, unique_milestone_ids: false.
Team — unique IDs, push branches, pre-merge checks:
---
version: 1
mode: team
---
Equivalent to setting git.auto_push: false, git.push_branches: true, git.pre_merge_check: true, git.merge_strategy: squash, git.isolation: worktree, unique_milestone_ids: true.
Mode with overrides — team mode but with auto-push:
---
version: 1
mode: team
git:
auto_push: true
---
Gets all team defaults except auto_push, which is explicitly overridden to true. Any explicit setting always wins over the mode default.
Minimal Example
The cleanest preferences file only specifies what you actually want:
---
version: 1
always_use_skills:
- debug-like-expert
skill_discovery: suggest
models:
planning: claude-opus-4-6
execution: claude-sonnet-4-6
---
Everything else uses defaults. No prefer_skills: [], no avoid_skills: [], no auto_supervisor: {} — those are just noise.
Models Example
---
version: 1
models:
research: claude-sonnet-4-6
planning: claude-opus-4-6
execution: claude-sonnet-4-6
completion: claude-sonnet-4-6
---
Opus for planning (where architectural decisions matter most), Sonnet for everything else (faster, cheaper). Omit any key to use the currently selected model.
Models with Fallbacks Example
---
version: 1
models:
research:
model: openrouter/qwen/qwen3-coder:free
fallbacks:
- openrouter/minimax/minimax-m2.5:free
planning:
model: claude-opus-4-6
fallbacks:
- openrouter/z-ai/glm-4.5-air:free
- openrouter/openai/gpt-oss-120b:free
execution:
model: openrouter/z-ai/glm-4.5-air:free
fallbacks:
- openrouter/minimax/minimax-m2.5:free
completion: openrouter/minimax/minimax-m2.5:free
---
When a model fails to switch (provider unavailable, rate limited, credits exhausted), SF automatically tries the next model in the fallbacks list. This ensures autonomous mode continues even when your preferred provider hits limits.
Provider Targeting
When the same model ID exists across multiple providers (e.g., claude-sonnet-4-6 on both Anthropic and Bedrock), use the provider/model format or the provider field to target a specific one:
---
version: 1
models:
# String format: provider/model
research: bedrock/claude-sonnet-4-6
planning: anthropic/claude-opus-4-6
# Object format: explicit provider field
execution:
model: claude-sonnet-4-6
provider: bedrock
fallbacks:
- anthropic/claude-sonnet-4-6
---
If you use a bare model ID (no provider prefix) and it exists in multiple providers, SF will warn you and resolve to the first available match. Use provider/model format to avoid ambiguity.
To limit a provider to specific models, use provider_model_allow. Entries are
exact model IDs by default, and also support * globs plus :suffix shorthand.
SF always restricts OpenRouter to :free models and OpenCode to zero-cost/free
models. OpenCode Go stays unrestricted because it is the subscribed tier. You
can still add an explicit OpenRouter allow-list to narrow that free subset
further. Xiaomi regional token-plan aliases are hidden from normal selection;
use xiaomi/* for the default AMS-backed endpoint. Claude Code is hidden from
normal SF model selection because SF routes through managed provider keys here.
Mistral live discovery hides non-selection endpoints such as embeddings, OCR,
moderation, TTS/transcription/realtime audio, and private fine-tunes.
---
version: 1
allowed_providers:
- openrouter
provider_model_allow:
openrouter:
- ":free"
---
Cost-optimized example — use cheap models with expensive ones as fallback for critical phases:
---
version: 1
models:
research: openrouter/qwen/qwen3-coder:free
planning:
model: claude-opus-4-6 # $5/$25 — best for architecture
fallbacks:
- openrouter/z-ai/glm-4.5-air:free
execution: openrouter/minimax/minimax-m2.5:free
completion: openrouter/minimax/minimax-m2.5:free
---
Example Variations
Minimal — always load a UAT skill and route Clerk tasks:
---
version: 1
always_use_skills:
- /Users/you/.claude/skills/verify-uat
skill_rules:
- when: finishing implementation and human judgment matters
use:
- /Users/you/.claude/skills/verify-uat
---
Richer routing — prefer cleanup and authentication skills:
---
version: 1
prefer_skills:
- commit-ignore
skill_rules:
- when: task involves Clerk authentication
use:
- clerk
- clerk-setup
- when: the user is looking for installable capability rather than implementation
prefer:
- find-skills
---
Git Preferences Example
---
version: 1
git:
auto_push: true
push_branches: true
remote: origin
snapshots: true
pre_merge_check: auto
commit_type: feat
---
All git fields are optional. Omit any field to use the default behavior. Project-level preferences override global preferences on a per-field basis.
Budget & Cost Control Example
---
version: 1
budget_ceiling: 10.00
budget_enforcement: pause
context_pause_threshold: 80
---
Sets a $10 budget ceiling. Autonomous mode pauses when the ceiling is reached. Context window pauses at 80% usage for checkpointing.
Notifications Example
---
version: 1
notifications:
enabled: true
on_complete: false
on_error: true
on_budget: true
on_milestone: true
on_attention: true
---
Disables per-unit completion notifications (noisy in long runs) while keeping error, budget, milestone, and attention notifications enabled.
cmux Example
---
version: 1
cmux:
enabled: true
notifications: true
sidebar: true
splits: true
browser: false
---
Enables cmux-aware notifications, sidebar metadata, and visible subagent splits when SF is running inside a cmux terminal.
Post-Unit Hooks Example
---
version: 1
post_unit_hooks:
- name: code-review
after:
- execute-task
prompt: "Review the code changes in {sliceId}/{taskId} for quality, security, and test coverage."
max_cycles: 1
artifact: REVIEW.md
---
Runs an automated code review after each task execution. Skips if REVIEW.md already exists (idempotent).
Pre-Dispatch Hooks Examples
Modify — inject instructions before every task:
---
version: 1
pre_dispatch_hooks:
- name: enforce-standards
before:
- execute-task
action: modify
prepend: "Follow our TypeScript coding standards and always run linting."
---
Skip — skip per-slice research when a research file already exists:
---
version: 1
pre_dispatch_hooks:
- name: skip-existing-research
before:
- research-slice
action: skip
skip_if: RESEARCH.md
---
Replace — substitute a custom prompt for task execution:
---
version: 1
pre_dispatch_hooks:
- name: tdd-execute
before:
- execute-task
action: replace
prompt: "Implement the task using strict TDD. Write failing tests first, then implement, then refactor."
model: claude-opus-4-6
---
Token Profile & Phases Example
---
version: 1
token_profile: budget
phases:
skip_research: true
skip_reassess: true
skip_slice_research: false
---
Uses the budget profile to minimize token usage, with explicit override to keep slice-level research enabled.
Remote Questions Example
---
version: 1
remote_questions:
channel: slack
channel_id: "C0123456789"
timeout_minutes: 15
poll_interval_seconds: 10
---
Routes interactive questions to a Slack channel for machine-surface autonomous sessions. Questions time out after 15 minutes if unanswered.
Dynamic Routing Example
---
version: 1
dynamic_routing:
enabled: true
tier_models:
light: openrouter/minimax/minimax-m2.5:free
standard: claude-sonnet-4-6
heavy: claude-opus-4-6
escalate_on_failure: true
budget_pressure: true
---
Automatically selects model tier based on task complexity. Simple tasks use the light model, complex tasks escalate to heavy. Under budget pressure, tasks are routed to cheaper tiers.
Parallel Execution Example
---
version: 1
parallel:
enabled: true
max_workers: 3
merge_strategy: per-milestone
auto_merge: confirm
---
Runs up to 3 slices concurrently in separate worktrees. Results are merged per-milestone with user confirmation.
Verification Example
---
version: 1
verification_commands:
- npm test
- npm run lint
- npm run typecheck
verification_auto_fix: true
verification_max_retries: 2
---
Runs test, lint, and typecheck after each task. On failure, auto-fix is attempted up to 2 times before reporting the issue.
Experimental Features Example
---
version: 1
experimental:
rtk: true
---
Opts in to RTK shell-command compression. RTK is downloaded automatically on first use. Set SF_RTK_DISABLED=1 to force-disable at the environment level regardless of this setting.
Execution Timeouts & Limits (Tier 1.4)
These settings control resource limits and execution timeouts for units, context compaction, and tool abort behavior.
-
context_compact_at: Token threshold for compacting context snapshots. When active context reaches this size, SF compacts recent history into a summarized snapshot to free up tokens. Must be <=context_hard_limit. Default:20000(solo),25000(team).Example:
context_compact_at: 18000(compact at 18k tokens). -
context_hard_limit: Absolute context hard limit in tokens. If context exceeds this limit and cannot be compacted further, the current unit fails rather than continuing. This prevents runaway context explosion. Default:35000(solo),40000(team).Example:
context_hard_limit: 32000(fail if context > 32k). -
unit_timeout: Single unit execution timeout in seconds. If a unit (research, planning, execute-task, etc.) runs longer than this, it is terminated. Default:300(5 minutes).Example:
unit_timeout: 600(allow up to 10 minutes per unit). -
unit_timeout_by_phase: Phase-specific execution timeouts. Overrideunit_timeoutfor specific unit types. Use object notation with phase names as keys.Example:
unit_timeout_by_phase: research: 180 # Research phases timeout after 3 minutes execute: 900 # Execution phases timeout after 15 minutes validation: 300 # Validation phases timeout after 5 minutesRecognized phases:
research,planning,execution,validation,discussion,replan. -
max_agents_by_phase: Max parallel agents (workers) per phase. Controls how many units of each type can run concurrently. Useful for managing resources on constrained deployments. Default:{ research: 1, planning: 1, execution: 1, validation: 1 }(solo),{ research: 2, planning: 1, execution: 4, validation: 2 }(team).Example:
max_agents_by_phase: research: 2 # Up to 2 concurrent research units execution: 4 # Up to 4 concurrent execute-task unitsRecognized phases:
research,planning,execution,validation,discussion,replan. -
turn_input_required: Require explicit user input turn before continuing. Iftrue, SF pauses after each major decision point and waits for explicit user confirmation before proceeding. Useful for cautious workflows. Default:false(solo),true(team).Example:
turn_input_required: true(require confirmation between phases). -
worktree_mode: Worktree management mode. Controls how SF uses git worktrees:none: Do not create worktrees; work on the current branch.auto: Automatically create worktrees for isolation when needed.manual: Require explicit worktree setup; fail if not available.
Default:
auto(solo),manual(team).Example:
worktree_mode: manual(require explicit worktree setup). -
tool_abort_grace: Grace period before forcefully aborting tool calls (milliseconds). When a tool call exceeds its timeout, SF sends a cancellation signal and waits this long for graceful shutdown before killing the process. Default:5000(solo),8000(team).Example:
tool_abort_grace: 10000(allow 10 seconds for graceful shutdown). -
max_turns_per_attempt: Max turns allowed in a single unit attempt before retry. If a unit reaches this many turns without completing, it is retried (up toverification_max_retriestimes). Default:50(solo),60(team).Example:
max_turns_per_attempt: 100(allow up to 100 turns before retry). -
hot_cache_turns: Number of recent turns to keep in hot memory cache. Older turns are archived to disk. Larger values improve query speed but consume more RAM. Default:5(solo),10(team).Example:
hot_cache_turns: 20(keep 20 recent turns in fast memory).
Execution Timeouts & Limits Example
---
version: 1
mode: team
context_compact_at: 22000
context_hard_limit: 38000
unit_timeout: 300
unit_timeout_by_phase:
research: 180
planning: 240
execution: 600
max_agents_by_phase:
research: 2
execution: 4
turn_input_required: true
worktree_mode: manual
tool_abort_grace: 8000
max_turns_per_attempt: 75
hot_cache_turns: 12
---
This team-mode configuration:
- Compacts context at 22k tokens, fails hard at 38k.
- Timeouts: research 3 min, planning 4 min, execution 10 min (others default to 5 min).
- Runs up to 2 research and 4 execution units in parallel.
- Requires explicit user confirmation between phases.
- Uses manual worktree setup (must be created ahead of time).
- Gives tool calls 8 seconds to shut down gracefully.
- Allows up to 75 turns per unit attempt.
- Keeps 12 turns in fast memory for query performance.
Doctor Checks
Run /doctor to validate your config:
- Error:
context_compact_at>context_hard_limit(illogical; compact must happen before hitting hard limit). - Error: Invalid
worktree_modevalue. - Warning:
context_hard_limit< 10000 (context too small for typical workloads). - Warning:
unit_timeout< 60 seconds (most units need multiple minutes). - Warning:
max_turns_per_attempt< 5 or > 200 (out of typical range). - Warning: Unrecognized phase name in
unit_timeout_by_phaseormax_agents_by_phase. - Warning: Phase timeout < 60 seconds or agent count out of range [1, 16].
Run /doctor --fix to auto-correct fixable errors (e.g., context_compact_at > context_hard_limit).
Vault Secret Resolver (Tier 1.1)
Overview
The Vault Secret Resolver allows you to store sensitive credentials (API keys, OAuth tokens) in HashiCorp Vault instead of plaintext in environment variables or config files.
URI Format: vault://secret/path/to/secret#fieldname
Example: vault://secret/anthropic/prod#api_key resolves the api_key field from the Vault secret at secret/anthropic/prod.
Setup
1. Install Vault
Download and install HashiCorp Vault from https://www.vaultproject.io/downloads.html.
Start a local dev server (for testing):
vault server -dev
This outputs a root token and VAULT_ADDR.
2. Create a Secret
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='<root-token>'
vault kv put secret/anthropic/prod api_key='sk-ant-...'
vault kv put secret/openai/prod api_key='sk-...'
3. Configure SF to Use Vault
Set your API key as a Vault URI in environment variables or .env:
# Option A: Environment variable
export ANTHROPIC_API_KEY='vault://secret/anthropic/prod#api_key'
# Option B: .env file
OPENAI_API_KEY=vault://secret/openai/prod#api_key
4. Authenticate SF to Vault
Use one of these methods (tried in order):
Method 1: Environment Variable (Simplest)
export VAULT_TOKEN='<your-root-token>'
sf execute-task "Hello"
Method 2: Token File (Recommended for Local Dev)
# Save token to ~/.vault-token (readable only by you)
vault token lookup # Confirm token is valid
cat ~/.vault-token # Should show token
# Now SF will automatically use this token
ANTHROPIC_API_KEY='vault://secret/anthropic/prod#api_key' sf execute-task "Hello"
Method 3: AppRole (Kubernetes / CI/CD)
# Create AppRole on Vault (admin only)
vault auth enable approle
vault write auth/approle/role/sf-role token_ttl=1h policies="sf-policy"
vault read auth/approle/role/sf-role/role-id
vault generate-and-list-secret auth/approle/role/sf-role/secret-id
# Set environment variables
export VAULT_ROLE_ID='<role-id>'
export VAULT_SECRET_ID='<secret-id>'
Examples
Solo Developer
# Start vault dev server
vault server -dev
# Create a secret
vault kv put secret/my-keys anthropic_key='sk-ant-...' openai_key='sk-...'
# Run SF with vault URIs
export VAULT_TOKEN='<dev-root-token>'
export ANTHROPIC_API_KEY='vault://secret/my-keys#anthropic_key'
export OPENAI_API_KEY='vault://secret/my-keys#openai_key'
sf execute-task "Write a poem"
Team Deployment
Store secrets in a production Vault instance:
# Production Vault setup (admin responsibility)
# 1. Create AppRole for SF
# 2. Create secrets: secret/anthropic/prod, secret/openai/prod, etc.
# 3. Assign read policy for SF role
# SF deployment (.env or deployment config)
VAULT_ADDR=https://vault.company.com
VAULT_ROLE_ID=<role-id>
VAULT_SECRET_ID=<secret-id>
ANTHROPIC_API_KEY=vault://secret/anthropic/prod#api_key
OPENAI_API_KEY=vault://secret/openai/prod#api_key
Troubleshooting
Run /doctor to check Vault setup:
/doctor
Common Issues:
vault_no_credentials— No VAULT_TOKEN or ~/.vault-token found. Set one using methods above.vault_invalid_uri_format— URI doesn't matchvault://path#field. Check format.vault_unreachable— Can't connect to Vault server. Check VAULT_ADDR and firewall.- Vault secret not found — Path doesn't exist in Vault. Create it:
vault kv put secret/path field='value'.
Behavior
- Lazy resolution: Secrets are only fetched when an API key is actually used (not at startup).
- Caching: Resolved secrets are cached in memory for 5 minutes to avoid repeated vault requests.
- Fail-open: If Vault is unavailable, SF falls back to the plaintext URI (so you can continue working).
- No persistent cache: Secrets are not cached to disk; Vault can revoke/update them at any time.
Security Notes
- Never commit
.envor config files withvault://URIs to version control. - Keep
VAULT_TOKENandVAULT_SECRET_IDin a secure location (use~/.vault-tokenor secret management). - Use AppRole in production; avoid root tokens.
- Vault audit logs will record all secret access; review regularly.
Related Documentation
- Preferences Overview: See top of this file for global vs project merging behavior.
- Mode Defaults: See
modefield for workflow-specific defaults. - Memory System: See
docs/dev/MEMORY-SYSTEM-ARCHITECTURE.mdfor cache behavior integration. - UOK Architecture: See
docs/adr/0075-uok-gate-architecture.mdanddocs/adr/0076-uok-memory-integration.md.
turn_status Marker System (Tier 2.5)
Overview
The turn_status marker system allows agents to signal semantic state during task execution, enabling SF to respond appropriately without relying on timeouts or error detection.
Marker Format: <turn_status>complete|blocked|giving_up</turn_status> (placed at end of agent output)
Three States:
complete— Task verified and finished; normal completion path.blocked— Discovered prerequisite or upstream failure; pause and wait for user input.giving_up— Multiple approaches failed; transition to phase reassessment.
Why Use turn_status Markers?
Instead of waiting for timeouts or detecting errors, agents can explicitly signal:
- Completion — "I've successfully completed the task; move to next phase."
- Blockers — "I found a prerequisite missing; I'm pausing pending user input."
- Reassessment — "I've tried multiple approaches and none work; let's reconsider the strategy."
This enables faster iteration and clearer agent-harness communication.
How It Works
- Agent adds marker — At the end of their output, agent writes:
<turn_status>blocked</turn_status> - Harness extracts marker — SF parses the marker from agent output
- Harness responds — SF triggers appropriate action (continue, pause, or reassess)
Examples
Example 1: Normal Completion
Agent output:
I've successfully implemented the feature. Tests pass, code is clean.
<turn_status>complete</turn_status>
Harness action: Continue to next phase (normal completion path).
Example 2: Blocked by Missing Dependency
Agent output:
I need the database schema to implement this feature, but it's not documented.
I'll pause here pending your input on the schema definition.
<turn_status>blocked</turn_status>
Harness action: Pause unit and wait for user to provide missing information (e.g., schema documentation).
Example 3: Giving Up After Multiple Attempts
Agent output:
I've tried three approaches to optimize this query:
1. Indexing — didn't help
2. Query rewrite — made it slower
3. Caching layer — requires architectural changes
None of these approaches work within the current constraints.
I recommend reassessing the problem statement or constraints.
<turn_status>giving_up</turn_status>
Harness action: Transition to phase reassessment (strategy change).
Best Practices
- Be explicit — Include the marker only when you have semantic knowledge about completion, blockers, or failure.
- Use complete for verification — Only mark
completewhen you've tested and verified the result. - Use blocked for prerequisites — Use
blockedwhen external input or dependency is missing, not for internal implementation details. - Use giving_up for reassessment — Use
giving_upwhen you've exhausted multiple approaches within the current constraints. - Fallback behavior — If no marker is present, SF assumes
complete(normal completion).
Doctor Check
Run /doctor to validate turn_status marker coverage:
- Warning: Executive prompts missing turn_status marker templates. Agents won't be able to signal
blockedorgiving_upstate.
If prompts are missing markers, SF will still function normally, but agents won't have a clear way to signal blockers or reassessment needs.
Related Documentation
- Turn Status Parser: See
src/resources/extensions/sf/turn-status-parser.jsfor implementation. - Prompt Templates: See
src/resources/extensions/sf/prompts/*.mdfor marker usage in agent instructions. - Tier 2.5 Architecture: See
docs/adr/for Tier 2.5 design decisions.