Architecture

How SpecSync is built. Useful for contributors and anyone adding language support.

Table of contents
  1. Source Layout
  2. Design Principles
  3. Validation Pipeline
    1. Stage 1: Structural
    2. Stage 2: API Surface
    3. Stage 3: Dependencies
  4. Adding a Language
  5. Dependencies
    1. Dev

Source Layout

src/
├── main.rs              CLI entry point (clap) + output formatting
├── ai.rs                AI-powered spec generation (prompt builder + command runner)
├── mcp.rs               MCP server (JSON-RPC over stdio, tools for check/generate/score)
├── scoring.rs           Spec quality scoring (0–100, weighted rubric)
├── types.rs             Core data types + config schema
├── config.rs            specsync.json / specsync.toml loading
├── parser.rs            Frontmatter + spec body parsing
├── validator.rs         Validation + coverage computation
├── generator.rs         Spec scaffolding
├── watch.rs             File watcher (notify, 500ms debounce)
└── exports/
    ├── mod.rs            Language dispatch + file utilities
    ├── typescript.rs     TS/JS exports
    ├── rust_lang.rs      Rust pub items
    ├── go.rs             Go uppercase identifiers
    ├── python.rs         Python __all__ / top-level
    ├── swift.rs          Swift public/open items
    ├── kotlin.rs         Kotlin top-level
    ├── java.rs           Java public items
    ├── csharp.rs         C# public items
    └── dart.rs           Dart public items

Design Principles

Single binary, no runtime deps. Download and run. No Node.js, no Python, no package managers.

Zero YAML dependencies. Frontmatter parsed with a purpose-built regex parser. Keeps the binary small and compile times fast.

Regex-based export extraction. Each language backend uses pattern matching, not AST parsing. Trades some precision for portability — works without compilers or language servers installed.

Release-optimized. LTO, symbol stripping, opt-level = 3.


Validation Pipeline

Stage 1: Structural

  • Parse YAML frontmatter
  • Check required fields: module, version, status, files
  • Verify every file in files exists on disk
  • Check all requiredSections present as ## Heading lines
  • Validate depends_on paths exist
  • Validate db_tables exist in schema files (if schemaDir configured)

Stage 2: API Surface

  • Detect language from file extensions
  • Extract public exports using language-specific regex
  • Extract symbol names from Public API tables (backtick-quoted)
  • In spec but not in code = Error (phantom/stale)
  • In code but not in spec = Warning (undocumented)

Stage 3: Dependencies

  • depends_on paths must point to existing spec files
  • ### Consumed By section: referenced files must exist

Adding a Language

  1. Create extractorsrc/exports/yourlang.rs, return Vec<String> of exported names
  2. Add enum variantLanguage in src/types.rs
  3. Wire dispatch — in src/exports/mod.rs: extension detection, match arm, test file patterns
  4. Write tests — common patterns, edge cases, test file exclusion

Each extractor: strip comments, apply regex, return symbol names. No compiler needed.


Dependencies

Crate Purpose
clap CLI parsing (derive macros)
serde + serde_json JSON for config and --json output
regex Export extraction + frontmatter parsing
walkdir Recursive directory traversal
colored Terminal colors
notify + notify-debouncer-full File watching for watch command
toml TOML config file parsing
tokio Async runtime for MCP server

Dev

Crate Purpose
tempfile Temp dirs for integration tests
assert_cmd CLI test utilities
predicates Output assertions