Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [1.2.0] - 2026-03-19

### Added

- **`specsync generate --ai`** — AI-powered spec generation. Reads source code, sends it to an LLM, and generates specs with real content (Purpose, Public API tables, Invariants, Error Cases) instead of template stubs. Configurable via `aiCommand` and `aiTimeout` in `specsync.json`, or `SPECSYNC_AI_COMMAND` env var. Defaults to Claude CLI, works with any LLM that reads stdin and writes stdout.
- **LOC coverage tracking** — `specsync coverage` now reports lines-of-code coverage alongside file coverage. JSON output includes `loc_coverage`, `loc_covered`, `loc_total`, and `uncovered_files` with per-file LOC counts sorted by size.
- **Flat file module detection** — `generate` and `coverage` now detect single-file modules (e.g., `src/config.rs`) in addition to subdirectory-based modules.
- `aiCommand` and `aiTimeout` config options in `specsync.json`.

### Changed

- Rewrote README for density — every line carries new information, no filler.
- Documented `generate --ai` workflow, AI command configuration, and LOC coverage in README and docs site.
- Streamlined docs site pages to complement rather than duplicate the README.
- Updated CHANGELOG with previously missing 1.1.1 and 1.1.2 entries.

Expand Down
67 changes: 57 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ specsync init # Create specsync.json config
specsync check # Validate specs against code
specsync coverage # Show file/module coverage
specsync generate # Scaffold specs for unspecced modules
specsync generate --ai # AI-powered specs (reads code, writes content)
specsync watch # Re-validate on every file change
```

Expand Down Expand Up @@ -246,7 +247,7 @@ specsync [command] [flags]
|---------|-------------|
| `check` | Validate all specs against source code **(default)** |
| `coverage` | File and module coverage report |
| `generate` | Scaffold specs for modules missing one |
| `generate` | Scaffold specs for modules missing one (`--ai` for AI-powered content) |
| `init` | Create default `specsync.json` |
| `watch` | Live validation on file changes (500ms debounce) |

Expand Down Expand Up @@ -313,7 +314,9 @@ Create `specsync.json` in your project root (or run `specsync init`):
"requiredSections": ["Purpose", "Public API", "Invariants", "Behavioral Examples", "Error Cases", "Dependencies", "Change Log"],
"excludeDirs": ["__tests__"],
"excludePatterns": ["**/__tests__/**", "**/*.test.ts", "**/*.spec.ts"],
"sourceExtensions": []
"sourceExtensions": [],
"aiCommand": "claude -p --output-format text",
"aiTimeout": 120
}
```

Expand All @@ -327,25 +330,68 @@ Create `specsync.json` in your project root (or run `specsync init`):
| `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 --ai` (reads stdin prompt, writes stdout markdown) |
| `aiTimeout` | `number?` | `120` | Seconds before AI command times out per module |

---

## For AI Agents
## Spec Generation

- **`--json`** outputs structured results, no color codes to strip
- **Exit code 1** = needs fixing; **0** = all clear
- **`specsync generate`** bootstraps specs for existing codebases
- **Spec files are plain markdown** — any LLM can read and write them
- **Public API tables** use backtick-quoted names, unambiguous to parse
`specsync generate` scans your source directories, finds modules without spec files, and scaffolds `*.spec.md` files for each one.

### JSON shapes
```bash
specsync generate # Scaffold template specs for all unspecced modules
specsync generate --ai # Use AI to generate filled-in specs from source code
specsync coverage # See what's still missing
```

### Template mode (default)

Uses your custom template (`specs/_template.spec.md`) or the built-in default. Generates frontmatter + stubbed sections with TODOs.

### AI mode (`--ai`)

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:
1. `"aiCommand"` in `specsync.json`
2. `SPECSYNC_AI_COMMAND` environment variable
3. `claude -p --output-format text` (default, requires [Claude CLI](https://docs.anthropic.com/en/docs/claude-code))

Any command that reads a prompt from stdin and writes markdown to stdout works:

```json
{ "aiCommand": "claude -p --output-format text" }
{ "aiCommand": "ollama run llama3" }
```

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:

```bash
specsync generate --ai # AI writes specs from source code
specsync check --json # validate, get structured feedback
# LLM fixes errors from JSON output # iterate until clean
specsync check --strict --require-coverage 100 # enforce full coverage in CI
```

Every output format is designed for machine consumption:
- **`--json`** on 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

```json
// specsync check --json
{ "passed": false, "errors": ["..."], "warnings": ["..."], "specs_checked": 12 }

// specsync coverage --json
{ "file_coverage": 85.33, "files_covered": 23, "files_total": 27, "modules": [{"name": "helpers", "has_spec": false}] }
{ "file_coverage": 85.33, "files_covered": 23, "files_total": 27, "loc_coverage": 79.12, "loc_covered": 4200, "loc_total": 5308, "modules": [...] }
```

---
Expand All @@ -355,6 +401,7 @@ Create `specsync.json` in your project root (or run `specsync init`):
```
src/
├── main.rs CLI entry + output formatting
├── ai.rs AI-powered spec generation (prompt builder + command runner)
├── types.rs Data types + config schema
├── config.rs specsync.json loading
├── parser.rs Frontmatter + spec body parsing
Expand Down
2 changes: 1 addition & 1 deletion docs/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ baseurl: "/spec-sync"

remote_theme: just-the-docs/just-the-docs@v0.10.0

color_scheme: dark
color_scheme: rust

aux_links:
"GitHub":
Expand Down
30 changes: 30 additions & 0 deletions docs/_sass/color_schemes/rust.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Rust-themed dark color scheme for SpecSync docs
// Based on just-the-docs dark scheme with orange/rust accents

$body-background-color: #1e1e1e;
$sidebar-color: #171717;
$body-text-color: #e0e0e0;
$body-heading-color: #f0f0f0;

// Rust orange accent colors
$link-color: #e87d2f;
$btn-primary-color: #e87d2f;
$feedback-color: darken($link-color, 3%);

// Code blocks
$code-background-color: #2a2a2a;
$code-linenumber-color: #6e7681;
$border-color: #3d3d3d;

// Search
$search-background-color: #2a2a2a;
$search-result-preview-color: #b0b0b0;

// Tables
$table-background-color: #252525;

// Navigation
$nav-child-link-color: #c0c0c0;

// Footer
$footer-background-color: #171717;
115 changes: 90 additions & 25 deletions docs/ai-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ nav_order: 6
# For AI Agents
{: .no_toc }

SpecSync is built to work well with LLM-powered coding tools.
SpecSync is built for LLM-powered coding tools — structured output, machine-readable specs, and automated scaffolding.
{: .fs-6 .fw-300 }

<details open markdown="block">
Expand All @@ -19,30 +19,85 @@ SpecSync is built to work well with LLM-powered coding tools.

---

## Why It Works
## AI-Powered Generation (`--ai`)

- Specs are plain markdown — any LLM can read and write them
- `--json` outputs structured data, no terminal color codes
- Exit code 1 = needs fixing, 0 = all clear
- `specsync generate` bootstraps specs for existing codebases
- Public API tables use backtick-quoted names, unambiguous to parse
`specsync generate --ai` reads your source code, sends it to an LLM, and generates specs with real content — not just templates with TODOs. Purpose, Public API tables, Invariants, Error Cases — all filled in from the code.

```bash
specsync generate --ai
# Generating specs/auth/auth.spec.md with AI...
# │ ---
# │ module: auth
# │ ...
# ✓ Generated specs/auth/auth.spec.md (3 files)
```

### Configuring the AI command

The AI command is resolved in order:
1. `"aiCommand"` in `specsync.json`
2. `SPECSYNC_AI_COMMAND` environment variable
3. `claude -p --output-format text` (default, requires Claude CLI)

Any command that reads a prompt from stdin and writes markdown to stdout works:

```json
{
"aiCommand": "claude -p --output-format text",
"aiTimeout": 300
}
```

```json
{
"aiCommand": "ollama run llama3",
"aiTimeout": 60
}
```

If AI generation fails for a module, it falls back to template generation automatically.

### Template mode (no `--ai`)

Without `--ai`, `specsync generate` scaffolds template specs — frontmatter populated, required sections stubbed with TODOs. Place `_template.spec.md` in your specs directory to control the generated structure.

---

## Workflow
## End-to-End Workflow

```bash
specsync check --json # 1. assess current state
# fix errors in specs or source # 2. resolve issues
specsync generate # 3. scaffold missing specs
specsync check --strict --require-coverage 100 # 4. verify
# One command: AI reads code, writes specs
specsync generate --ai

# Validate the generated specs against code
specsync check --json

# LLM fixes errors from JSON output, iterates until clean

# CI gate with full coverage
specsync check --strict --require-coverage 100
```

Each step produces machine-readable output. No human in the loop required (though humans can review at any step).

---

## JSON Shapes
## Why SpecSync Works for LLMs

### Check
| Feature | Why it matters |
|---------|---------------|
| Plain markdown specs | Any LLM can read and write them — no custom format to learn |
| `--json` flag on every command | Structured output, no ANSI codes to strip |
| Exit code 0/1 | Pass/fail without parsing |
| Backtick-quoted names in API tables | Unambiguous extraction — first backtick-quoted string per row |
| `specsync generate` | Bootstrap from zero — LLM fills in content, not boilerplate |
| Deterministic validation | Same input → same output, no flaky checks |

---

## JSON Output Shapes

### `specsync check --json`

```json
{
Expand All @@ -53,29 +108,35 @@ specsync check --strict --require-coverage 100 # 4. verify
}
```

- **Errors**: spec references something that doesn't exist in code — must fix
- **Errors**: spec references something missing from code — must fix
- **Warnings**: code exports something the spec doesn't mention — informational
- **`--strict`**: promotes warnings to errors

### Coverage
### `specsync coverage --json`

```json
{
"file_coverage": 85.33,
"files_covered": 23,
"files_total": 27,
"modules": [{ "name": "helpers", "has_spec": false }]
"loc_coverage": 79.12,
"loc_covered": 4200,
"loc_total": 5308,
"modules": [{ "name": "helpers", "has_spec": false }],
"uncovered_files": [{ "file": "src/helpers/utils.ts", "loc": 340 }]
}
```

Use `modules` with `has_spec: false` to identify what `generate` would scaffold. `uncovered_files` shows LOC per uncovered file, sorted by size — prioritize the largest gaps.

---

## Writing Specs Programmatically

1. Frontmatter requires `module`, `version`, `status`, `files`
2. Status: `draft`, `review`, `stable`, `deprecated`
3. Files: non-empty list, paths relative to project root
4. Public API tables: backtick-quoted names in first column
2. Status values: `draft`, `review`, `stable`, `deprecated`
3. `files` must be non-empty, paths relative to project root
4. Public API tables: first backtick-quoted string per row is the export name
5. Default required sections: Purpose, Public API, Invariants, Behavioral Examples, Error Cases, Dependencies, Change Log

### Minimal valid spec
Expand Down Expand Up @@ -121,9 +182,13 @@ None

---

## Integration Ideas
## Integration Patterns

- **Pre-commit hook**: `specsync check --strict`
- **PR review bot**: parse `specsync check --json` output, post as PR comment
- **Spec generation**: run `specsync generate` after adding modules
- **AI code review**: feed JSON output to an LLM for spec update suggestions
| Pattern | Command | How |
|---------|---------|-----|
| **Pre-commit hook** | `specsync check --strict` | Block commits with spec errors |
| **PR review bot** | `specsync check --json` | Parse output, post as PR comment |
| **Bootstrap coverage** | `specsync generate --ai` | AI writes specs from source code |
| **Template scaffold** | `specsync generate` | Scaffold templates after adding new modules |
| **AI code review** | `specsync check --json` | Feed errors to LLM for spec updates |
| **Coverage gate** | `specsync check --strict --require-coverage 100` | CI enforces full coverage |
1 change: 1 addition & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ How SpecSync is built. Useful for contributors and anyone adding language suppor
```
src/
├── main.rs CLI entry point (clap) + output formatting
├── ai.rs AI-powered spec generation (prompt builder + command runner)
├── types.rs Core data types + config schema
├── config.rs specsync.json loading
├── parser.rs Frontmatter + spec body parsing
Expand Down
12 changes: 10 additions & 2 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ specsync coverage --json
Scaffold spec files for modules that don't have one. Uses `specs/_template.spec.md` if present.

```bash
specsync generate
specsync generate # template mode — stubs with TODOs
specsync generate --ai # AI mode — reads code, writes real content
```

With `--ai`, source code is piped to an LLM which generates filled-in specs (Purpose, Public API tables, Invariants, etc.). The AI command is resolved from: `aiCommand` in config → `SPECSYNC_AI_COMMAND` env var → `claude -p --output-format text`. See [Configuration](configuration) for `aiCommand` and `aiTimeout`.

### `init`

Create a default `specsync.json` in the current directory.
Expand All @@ -86,6 +89,7 @@ specsync watch
| `--strict` | Warnings become errors. Recommended for CI. |
| `--require-coverage N` | Fail if file coverage < N%. |
| `--root <path>` | Project root directory (default: cwd). |
| `--ai` | Use AI to generate filled-in specs instead of templates (with `generate`). |
| `--json` | Structured JSON output, no color codes. |

---
Expand Down Expand Up @@ -119,6 +123,10 @@ specsync watch
"file_coverage": 85.33,
"files_covered": 23,
"files_total": 27,
"modules": [{ "name": "helpers", "has_spec": false }]
"loc_coverage": 79.12,
"loc_covered": 4200,
"loc_total": 5308,
"modules": [{ "name": "helpers", "has_spec": false }],
"uncovered_files": [{ "file": "src/helpers/utils.ts", "loc": 340 }]
}
```
Loading
Loading