Architecture
How SpecSync is built. Useful for contributors and anyone adding language support.
Table of contents
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
filesexists on disk - Check all
requiredSectionspresent as## Headinglines - Validate
depends_onpaths exist - Validate
db_tablesexist in schema files (ifschemaDirconfigured)
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_onpaths must point to existing spec files### Consumed Bysection: referenced files must exist
Adding a Language
- Create extractor —
src/exports/yourlang.rs, returnVec<String>of exported names - Add enum variant —
Languageinsrc/types.rs - Wire dispatch — in
src/exports/mod.rs: extension detection, match arm, test file patterns - 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 |