SpecSync
Bidirectional spec-to-code validation. Written in Rust. Single binary. 9 languages.
Quick Start • Spec Format • CLI • GitHub Action • Config • Docs Site
What It Does
SpecSync validates markdown module specs (*.spec.md) against your source code in both directions:
| Direction | Severity | Meaning |
|---|---|---|
| Code exports something not in the spec | Warning | Undocumented export |
| Spec documents something missing from code | Error | Stale/phantom entry |
| Source file in spec was deleted | Error | Missing file |
| DB table in spec missing from schema | Error | Phantom table |
| Required markdown section missing | Error | Incomplete spec |
Supported Languages
Auto-detected from file extensions. Same spec format for all.
| Language | Exports Detected | Test Exclusions |
|---|---|---|
| TypeScript/JS | export function/class/type/const/enum, re-exports |
.test.ts, .spec.ts, .d.ts |
| Rust | pub fn/struct/enum/trait/type/const/static/mod |
#[cfg(test)] modules |
| Go | Uppercase func/type/var/const, methods |
_test.go |
| Python | __all__, or top-level def/class (no _ prefix) |
test_*.py, *_test.py |
| Swift | public/open func/class/struct/enum/protocol/actor |
*Tests.swift |
| Kotlin | Top-level declarations (excludes private/internal) | *Test.kt, *Spec.kt |
| Java | public class/interface/enum/record/methods |
*Test.java, *Tests.java |
| C# | public class/struct/interface/enum/record/delegate |
*Test.cs, *Tests.cs |
| Dart | Top-level (no _ prefix), class/mixin/enum/typedef |
*_test.dart |
Install
GitHub Action (recommended)
- uses: CorvidLabs/spec-sync@v1
with:
strict: 'true'
require-coverage: '100'
Crates.io
Pre-built binaries
Download from GitHub Releases:
# macOS (Apple Silicon)
|
# macOS (Intel)
|
# Linux (x86_64)
|
# Linux (aarch64)
|
Windows: download specsync-windows-x86_64.exe.zip from the releases page.
From source
Quick Start
Spec Format
Specs are markdown files (*.spec.md) with YAML frontmatter in your specs directory.
Frontmatter
---
module: auth # Module name (required)
version: 3 # Spec version (required)
status: stable # draft | review | stable | deprecated (required)
files: # Source files covered (required, non-empty)
- src/auth/service.ts
- src/auth/middleware.ts
db_tables: # Validated against schema dir (optional)
- users
- sessions
depends_on: # Other spec paths, validated for existence (optional)
- specs/database/database.spec.md
---
Required Sections
Every spec must include these ## sections (configurable in specsync.json):
Purpose, Public API, Invariants, Behavioral Examples, Error Cases, Dependencies, Change Log
Public API Tables
SpecSync extracts the first backtick-quoted name per row and cross-references it against code exports:
module: auth
version: 3
status: stable
files:
- - - - -
Handles authentication and session management. Validates bearer tokens,
manages session lifecycle, provides middleware for route protection.
1. 2.3.
- --
- --
CLI Reference
specsync [command] [flags]
Commands
| Command | Description |
|---|---|
check |
Validate all specs against source code (default) |
coverage |
File and module coverage report |
generate |
Scaffold specs for modules missing one (--provider for AI-powered content) |
score |
Quality-score spec files (0–100) with improvement suggestions |
mcp |
Start MCP server for AI agent integration (Claude Code, Cursor, etc.) |
init |
Create default specsync.json |
watch |
Live validation on file changes (500ms debounce) |
Flags
| Flag | Description |
|---|---|
--strict |
Warnings become errors (recommended for CI) |
--require-coverage N |
Fail if file coverage < N% |
--root <path> |
Project root (default: cwd) |
--provider <name> |
AI provider: auto, anthropic, openai, or command. auto detects installed provider. Without --provider, generate uses templates only. |
--json |
Structured JSON output |
Exit Codes
| Code | Meaning |
|---|---|
0 |
All checks passed |
1 |
Errors, strict warnings, or coverage below threshold |
GitHub Action
Available on the GitHub Marketplace. Auto-detects OS/arch, downloads the binary, runs validation.
Inputs
| Input | Default | Description |
|---|---|---|
version |
latest |
Release version to download |
strict |
false |
Treat warnings as errors |
require-coverage |
0 |
Minimum file coverage % |
root |
. |
Project root directory |
args |
'' |
Extra CLI arguments |
Workflow example
name: Spec Check
on:
jobs:
specsync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: CorvidLabs/spec-sync@v1
with:
strict: 'true'
require-coverage: '100'
Configuration
Create specsync.json in your project root (or run specsync init):
| Option | Type | Default | Description |
|---|---|---|---|
specsDir |
string |
"specs" |
Directory containing *.spec.md files |
sourceDirs |
string[] |
["src"] |
Source directories for coverage analysis |
schemaDir |
string? |
— | SQL schema dir for db_tables validation |
schemaPattern |
string? |
CREATE TABLE regex |
Custom regex for table name extraction |
requiredSections |
string[] |
7 defaults | Markdown sections every spec must include |
excludeDirs |
string[] |
["__tests__"] |
Directories excluded from coverage |
excludePatterns |
string[] |
Common test globs | File patterns excluded from coverage |
sourceExtensions |
string[] |
All supported | Restrict to specific extensions (e.g., ["ts", "rs"]) |
aiCommand |
string? |
claude -p ... |
Command for generate --provider command (reads stdin prompt, writes stdout markdown) |
aiTimeout |
number? |
120 |
Seconds before AI command times out per module |
Spec Generation
specsync generate scans your source directories, finds modules without spec files, and scaffolds *.spec.md files for each one.
Template mode (default)
Uses your custom template (specs/_template.spec.md) or the built-in default. Generates frontmatter + stubbed sections with TODOs.
AI mode (--provider)
Reads your source code, sends it to an LLM, and generates specs with real content — Purpose, Public API tables, Invariants, Error Cases, all filled in from the code. No manual filling required.
The AI command is resolved in order:
"aiCommand"inspecsync.jsonSPECSYNC_AI_COMMANDenvironment variableclaude -p --output-format text(default, requires Claude CLI)
Any command that reads a prompt from stdin and writes markdown to stdout works:
Set "aiTimeout" in specsync.json to control per-module timeout (default: 120 seconds).
Designed for AI agents
The generate command is the entry point for LLM-powered spec workflows:
# LLM fixes errors from JSON output # iterate until clean
Every output format is designed for machine consumption:
--jsonon any command → structured JSON, no ANSI codes- Exit code 0/1 → pass/fail, no parsing needed
- Spec files are plain markdown → any LLM can read and write them
- Public API tables use backtick-quoted names → unambiguous to extract
JSON output shapes
// specsync check --json
// specsync coverage --json
Architecture
src/
├── main.rs CLI entry + output formatting
├── ai.rs AI-powered spec generation (prompt builder + command runner)
├── mcp.rs MCP server for AI agent integration (JSON-RPC stdio)
├── scoring.rs Spec quality scoring (0–100, weighted rubric)
├── types.rs 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
├── 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: Single binary, no runtime deps. Frontmatter parsed with regex (no YAML library). Language backends use regex, not ASTs — works without compilers installed. Release builds use LTO + strip + opt-level 3.
Contributing
- Fork, branch (
git checkout -b feat/my-feature), implement cargo test+cargo clippy- Open a PR
Adding a language
- Create
src/exports/yourlang.rs— returnVec<String>of exported names - Add variant to
Languageenum intypes.rs - Wire extension detection + dispatch in
src/exports/mod.rs - Add tests for common patterns