Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

OptionTypeDefaultDescription
specsDirstring"specs"Directory containing *.spec.md files (searched recursively)
sourceDirsstring[]["src"]Source directories for coverage analysis
schemaDirstring?SQL schema directory for db_tables validation
schemaPatternstring?CREATE TABLE regexCustom regex for extracting table names (first capture group = table name)
requiredSectionsstring[]7 defaultsMarkdown ## sections every spec must include
excludeDirsstring[]["__tests__"]Directory names skipped during coverage scanning
excludePatternsstring[]Common test globsFile patterns excluded from coverage (additive with language-specific test exclusions)
sourceExtensionsstring[]All supportedRestrict to specific extensions (e.g., ["ts", "rs"])
aiProviderstring?AI provider name: claude, anthropic, openai, ollama, copilot, or custom
aiModelstring?Provider defaultModel name override (e.g., "claude-sonnet-4-20250514", "gpt-4o", "mistral")
aiCommandstring?Custom CLI command for AI generation (reads stdin prompt, writes stdout markdown)
aiApiKeystring?API key for anthropic or openai providers (prefer env vars ANTHROPIC_API_KEY / OPENAI_API_KEY instead)
aiBaseUrlstring?Custom base URL for API providers (e.g., for proxies or self-hosted endpoints)
aiTimeoutnumber?120Seconds before AI command times out per module
exportLevelstring?"member"Export validation depth: "type" (classes/structs only) or "member" (all public symbols)
modulesobject?{}Custom module definitions mapping module names to { files, depends_on }
rulesobject?{}Custom validation rules (see Validation Rules below)
taskArchiveDaysnumber?Days after which completed tasks in companion tasks.md files are auto-archived
githubobject?GitHub integration settings (see GitHub Config below)

AI Provider Resolution

When you run specsync generate --provider auto, the provider is resolved in this order:

  1. --provider CLI flag (explicit)
  2. aiCommand in config — checked in shared config first, then .specsync/config.local.toml (gitignored, per-developer overrides)
  3. aiProvider in config (same merge order as above)
  4. SPECSYNC_AI_COMMAND env var
  5. Auto-detect: installed CLIs (claude, copilot, ollama — alphabetical), then API keys

Multi-agent teams: Don’t put ai_provider or ai_command in the shared config.toml. Instead, each contributor creates .specsync/config.local.toml with 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
  }
}
RuleTypeDescription
maxChangelogEntriesnumber?Warn if a spec’s Change Log exceeds this many entries
requireBehavioralExamplesbool?Require at least one Behavioral Example scenario
minInvariantsnumber?Minimum number of invariants required per spec
maxSpecSizeKbnumber?Warn if spec file exceeds this size in KB
requireDependsOnbool?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
  }
}
OptionTypeDefaultDescription
repostring?Auto-detectedRepository in owner/repo format (auto-detected from git remote)
driftLabelsstring[]["spec-drift"]Labels applied when creating drift issues
verifyIssuesbooltrueWhether 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"]
}