diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e148b4f..3ffb5663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 8061e09a..0537048c 100644 --- a/README.md +++ b/README.md @@ -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 ``` @@ -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) | @@ -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 } ``` @@ -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": [...] } ``` --- @@ -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 diff --git a/docs/_config.yml b/docs/_config.yml index 4ae37c6e..6704c9ba 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -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": diff --git a/docs/_sass/color_schemes/rust.scss b/docs/_sass/color_schemes/rust.scss new file mode 100644 index 00000000..1790ab0b --- /dev/null +++ b/docs/_sass/color_schemes/rust.scss @@ -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; diff --git a/docs/ai-agents.md b/docs/ai-agents.md index bf3b425d..a466d4c5 100644 --- a/docs/ai-agents.md +++ b/docs/ai-agents.md @@ -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 }
@@ -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 { @@ -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 @@ -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 | diff --git a/docs/architecture.md b/docs/architecture.md index cf60becd..5f5557a4 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -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 diff --git a/docs/cli.md b/docs/cli.md index a386b408..7e584ec8 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -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. @@ -86,6 +89,7 @@ specsync watch | `--strict` | Warnings become errors. Recommended for CI. | | `--require-coverage N` | Fail if file coverage < N%. | | `--root ` | 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. | --- @@ -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 }] } ``` diff --git a/docs/configuration.md b/docs/configuration.md index c60cea3e..3ded63ca 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -40,7 +40,9 @@ Creates `specsync.json` with defaults. SpecSync also works without a config file "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 } ``` @@ -58,6 +60,8 @@ Creates `specsync.json` with defaults. SpecSync also works without a config file | `excludeDirs` | `string[]` | `["__tests__"]` | Directory names skipped during coverage scanning | | `excludePatterns` | `string[]` | Common test globs | File patterns excluded from coverage (additive with language-specific test exclusions) | | `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 | --- diff --git a/docs/index.md b/docs/index.md index 0f1a0a45..16d2ab9b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,6 +37,7 @@ specsync init # create specsync.json specsync check # validate specs against code specsync coverage # see what's covered specsync generate # scaffold specs for unspecced modules +specsync generate --ai # AI-powered specs (reads code, writes content) specsync watch # re-validate on file changes ```