Configuration
SpecSync is configured via .specsync/config.toml (v4) or legacy specsync.json / .specsync.toml in your project root. All fields are optional — sensible defaults apply.
Getting Started
specsync init
Creates .specsync/config.toml (v4) with defaults. SpecSync also works without a config file.
TOML Config
Config resolution order: .specsync/config.toml → .specsync/config.json → .specsync.toml (legacy) → specsync.json (legacy) → defaults. If .specsync/config.local.toml exists (gitignored), it’s merged on top for per-developer overrides.
Example:
specs_dir = "specs"
source_dirs = ["src"]
schema_dir = "db/migrations"
ai_provider = "anthropic"
ai_model = "claude-sonnet-4-20250514"
ai_timeout = 120
export_level = "member"
required_sections = ["Purpose", "Public API", "Invariants", "Behavioral Examples", "Error Cases", "Dependencies", "Change Log"]
exclude_dirs = ["__tests__"]
exclude_patterns = ["**/__tests__/**", "**/*.test.ts"]
task_archive_days = 30
[rules]
max_changelog_entries = 20
require_behavioral_examples = true
min_invariants = 1
[github]
drift_labels = ["spec-drift"]
verify_issues = true
Config resolution order: .specsync/config.toml → .specsync/config.json → .specsync.toml (legacy) → specsync.json (legacy) → defaults. Per-developer overrides via .specsync/config.local.toml are merged on top.
Full Config
{
"specsDir": "specs",
"sourceDirs": ["src"],
"schemaDir": "db/migrations",
"schemaPattern": "CREATE (?:VIRTUAL )?TABLE(?:\\s+IF NOT EXISTS)?\\s+(\\w+)",
"requiredSections": ["Purpose", "Public API", "Invariants", "Behavioral Examples", "Error Cases", "Dependencies", "Change Log"],
"excludeDirs": ["__tests__"],
"excludePatterns": ["**/__tests__/**", "**/*.test.ts", "**/*.spec.ts"],
"sourceExtensions": [],
"exportLevel": "member",
"aiProvider": "anthropic",
"aiModel": "claude-sonnet-4-20250514",
"aiCommand": null,
"aiApiKey": null,
"aiBaseUrl": null,
"aiTimeout": 120,
"taskArchiveDays": 30,
"modules": {},
"rules": {
"maxChangelogEntries": 20,
"requireBehavioralExamples": true,
"minInvariants": 1,
"maxSpecSizeKb": 50,
"requireDependsOn": false
},
"github": {
"repo": "owner/repo",
"driftLabels": ["spec-drift"],
"verifyIssues": true
}
}
Options
| Option | Type | Default | Description |
|---|---|---|---|
specsDir | string | "specs" | Directory containing *.spec.md files (searched recursively) |
sourceDirs | string[] | ["src"] | Source directories for coverage analysis |
schemaDir | string? | — | SQL schema directory for db_tables validation |
schemaPattern | string? | CREATE TABLE regex | Custom regex for extracting table names (first capture group = table name) |
requiredSections | string[] | 7 defaults | Markdown ## sections every spec must include |
excludeDirs | string[] | ["__tests__"] | Directory names skipped during coverage scanning |
excludePatterns | string[] | Common test globs | File patterns excluded from coverage (additive with language-specific test exclusions) |
sourceExtensions | string[] | All supported | Restrict to specific extensions (e.g., ["ts", "rs"]) |
aiProvider | string? | — | AI provider name: claude, anthropic, openai, ollama, copilot, or custom |
aiModel | string? | Provider default | Model name override (e.g., "claude-sonnet-4-20250514", "gpt-4o", "mistral") |
aiCommand | string? | — | Custom CLI command for AI generation (reads stdin prompt, writes stdout markdown) |
aiApiKey | string? | — | API key for anthropic or openai providers (prefer env vars ANTHROPIC_API_KEY / OPENAI_API_KEY instead) |
aiBaseUrl | string? | — | Custom base URL for API providers (e.g., for proxies or self-hosted endpoints) |
aiTimeout | number? | 120 | Seconds before AI command times out per module |
exportLevel | string? | "member" | Export validation depth: "type" (classes/structs only) or "member" (all public symbols) |
modules | object? | {} | Custom module definitions mapping module names to { files, depends_on } |
rules | object? | {} | Custom validation rules (see Validation Rules below) |
taskArchiveDays | number? | — | Days after which completed tasks in companion tasks.md files are auto-archived |
github | object? | — | GitHub integration settings (see GitHub Config below) |
AI Provider Resolution
When you run specsync generate --provider auto, the provider is resolved in this order:
--providerCLI flag (explicit)aiCommandin config — checked in shared config first, then.specsync/config.local.toml(gitignored, per-developer overrides)aiProviderin config (same merge order as above)SPECSYNC_AI_COMMANDenv var- Auto-detect: installed CLIs (
claude,copilot,ollama— alphabetical), then API keys
Multi-agent teams: Don’t put
ai_providerorai_commandin the sharedconfig.toml. Instead, each contributor creates.specsync/config.local.tomlwith their preferred AI settings. This file is automatically gitignored.
API Providers
The anthropic and openai providers call their respective APIs directly — no CLI tool needed. Just set the API key:
{
"aiProvider": "anthropic"
}
Then set ANTHROPIC_API_KEY in your environment (or use aiApiKey in config for local use — not recommended for shared repos).
Validation Rules
Fine-tune validation behavior with the rules object:
{
"rules": {
"maxChangelogEntries": 20,
"requireBehavioralExamples": true,
"minInvariants": 2,
"maxSpecSizeKb": 50,
"requireDependsOn": false
}
}
| Rule | Type | Description |
|---|---|---|
maxChangelogEntries | number? | Warn if a spec’s Change Log exceeds this many entries |
requireBehavioralExamples | bool? | Require at least one Behavioral Example scenario |
minInvariants | number? | Minimum number of invariants required per spec |
maxSpecSizeKb | number? | Warn if spec file exceeds this size in KB |
requireDependsOn | bool? | Require non-empty depends_on in frontmatter |
GitHub Config
Configure GitHub integration for drift detection and issue verification:
{
"github": {
"repo": "owner/repo",
"driftLabels": ["spec-drift"],
"verifyIssues": true
}
}
| Option | Type | Default | Description |
|---|---|---|---|
repo | string? | Auto-detected | Repository in owner/repo format (auto-detected from git remote) |
driftLabels | string[] | ["spec-drift"] | Labels applied when creating drift issues |
verifyIssues | bool | true | Whether to verify linked issues exist during specsync check |
Custom Module Definitions
Map custom module names to specific files when auto-detection doesn’t fit your layout:
{
"modules": {
"auth": {
"files": ["src/auth/service.ts", "src/auth/middleware.ts"],
"dependsOn": ["database"]
},
"api": {
"files": ["src/routes/"],
"dependsOn": ["auth", "database"]
}
}
}
Module definitions override the default subdirectory/flat-file discovery for specsync generate and specsync coverage.
Example Configs
TypeScript project
{
"specsDir": "specs",
"sourceDirs": ["src"],
"excludePatterns": ["**/__tests__/**", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}
Rust project
{
"specsDir": "specs",
"sourceDirs": ["src"],
"sourceExtensions": ["rs"]
}
Monorepo
{
"specsDir": "docs/specs",
"sourceDirs": ["packages/core/src", "packages/api/src"],
"schemaDir": "packages/db/migrations"
}
Minimal
{
"requiredSections": ["Purpose", "Public API"]
}