An open API service indexing awesome lists of open source software.

https://github.com/jkaloger/lazyspec

A little TUI for project documentation.
https://github.com/jkaloger/lazyspec

ai cli sdd spec-driven tui

Last synced: about 1 month ago
JSON representation

A little TUI for project documentation.

Awesome Lists containing this project

README

          


🤖

lazyspec



A little TUI & CLI for project documentation.


CI
Rust 2021
Status: Experimental
Version
Last commit
Nix Flake

screenshot of a terminal interface displaying codebase documentation, categorised by type

> [!WARNING]
> Lazyspec is experimental. APIs and CLI interfaces will change frequently and without notice.

## Features

Lazyspec manages project documentation as version-controlled markdown files with YAML frontmatter. Documents live in your repo, so agents and humans read from the same source of truth.

- Create, update, link, and validate documents. Typed relationships (`implements`, `supersedes`, `blocks`, `related-to`) keep the chain explicit.
- Catch broken links, orphaned documents, and incomplete frontmatter before they rot. `lazyspec validate` exits non-zero on errors, so it slots into CI.
- Embed `@ref` directives in your specs to point at source code. Lazyspec expands them inline using `git show`, with symbol-level extraction for Rust and TypeScript.
- Fuzzy search, markdown preview, live file watching, and document creation without leaving the terminal.
- Every command supports `--json` output for automation and agent integration.
- Define your own types, templates, and directory layout in `.lazyspec.toml`.

## Install

### Nix

```sh
nix profile install github:jkaloger/lazyspec
```

Or run without installing:

```sh
nix run github:jkaloger/lazyspec
```

### Cargo

```sh
cargo install --git https://github.com/jkaloger/lazyspec
```

### From Source

```sh
git clone https://github.com/jkaloger/lazyspec
cd lazyspec
cargo install --path .
```

### Shell Completions

Generate and source a completion script for your shell:

```sh
# zsh
source <(lazyspec completions zsh)

# bash
source <(lazyspec completions bash)

# fish
lazyspec completions fish | source
```

Add the appropriate line to your shell profile (`~/.zshrc`, `~/.bashrc`, etc.) to load completions on startup. Completions include subcommands, flags, document IDs, and relationship types.

## Skills

Lazyspec includes a set of agent skills that enforce its workflow:

| Skill | Purpose |
| ------------------ | -------------------------------------------------------------------- |
| `plan-work` | Detect existing artifacts and determine the right entry point |
| `write-rfc` | Propose a design with intent, interface sketches, and identify stories |
| `create-story` | Create stories with acceptance criteria linked to an RFC |
| `resolve-context` | Gather full document chain (RFC -> Story -> Iteration) before work |
| `create-iteration` | Plan an iteration with task breakdown and test plan |
| `build` | Implement tasks from an iteration with subagent dispatch |
| `review-iteration` | Two-stage review -- AC compliance first, then code quality |
| `create-audit` | Criteria-based review (health check, security, accessibility, etc.) |

## Usage

### Quick Start

Initialise a new project, then launch the TUI:

```sh
lazyspec init
lazyspec
```

> [!TIP]
> Check the `examples/` directory for a complete project setup including config, templates, and agent skill definitions you can use as a starting point.
> This repo dogfoods lazyspec, so you can also check out the `docs/` directory or run `lazyspec` from this repo.

### TUI

Running `lazyspec` with no subcommand opens the interactive dashboard. It provides fuzzy search, markdown preview, document creation, and live file watching -- documents update automatically when changed on disk.

CLI

All document management is available as subcommands. Most accept `--json` for machine-readable output.

| Command | Description |
| ------------------------------------ | --------------------------------------------------------------------- |
| `init` | Initialise lazyspec in the current project |
| `create [--author X]` | Create a document (rfc, adr, story, iteration) |
| `list [type] [--status X]` | List documents with optional filters |
| `show [-e]` | Display a document by path or shorthand ID (e.g. `RFC-001`) |
| `update --status X --title X` | Update document frontmatter |
| `delete ` | Delete a document |
| `link ` | Add a typed relationship (implements, supersedes, blocks, related-to) |
| `unlink ` | Remove a relationship between documents |
| `search [--doc-type X]` | Full-text search across all documents |
| `context ` | Show the full document chain (RFC -> Story -> Iteration) |
| `status` | Show full project status with all documents and validation |
| `ignore ` | Mark a document to skip validation |
| `unignore ` | Remove validation skip from a document |
| `validate [--warnings]` | Check document integrity and link consistency |
| `fix [paths] [--dry-run]` | Fix documents with broken or incomplete frontmatter |
| `pin ` | Pin blob hashes onto `@ref` directives in a document |
| `reservations list` | Show all reservation refs on the remote |
| `reservations prune [--dry-run]` | Remove refs for documents that already exist locally |

#### `show` Flags

| Flag | Description |
| --------------------------- | ------------------------------------------------ |
| `-e`, `--expand-references` | Expand `@ref` directives into fenced code blocks |
| `--max-ref-lines N` | Max lines per expanded ref (default: 25) |


@ref Syntax

Documents can embed references to source code using `@ref` directives. By default, `lazyspec show` renders them as-is. Pass `-e` to expand them inline.

```
@ref # entire file
@ref # # specific type or struct
@ref #@ # symbol at a specific git commit
@ref #123 # line 123
@ref #123@ # line 123 at a specific git commit
```

Expansion resolves content via `git show` (committed state, not working tree). Supported languages for symbol extraction are TypeScript (`.ts`/`.tsx`) and Rust (`.rs`).

Each expanded ref includes a caption line showing the file path, short git SHA, and symbol or line info. Expanded blocks are truncated to 25 lines by default; when truncated, a trailing comment shows how many lines were omitted. Use `--max-ref-lines` to adjust the limit.

**Example**

A document containing:

```
@ref src/engine/store.rs#Store
```

Renders as:

````
```rust
pub struct Store { ... }
```
````

Unresolvable refs render as:

```
> [unresolved: src/engine/store.rs#Store]
```

Configuration

`lazyspec init` creates a `.lazyspec.toml` in your project root with four built-in document types:

```toml
[directories]
rfcs = "docs/rfcs"
adrs = "docs/adrs"
stories = "docs/stories"
iterations = "docs/iterations"

[templates]
dir = ".lazyspec/templates"

[naming]
pattern = "{type}-{n:03}-{title}.md"
```

### Custom Types

Instead of `[directories]`, you can define types explicitly with `[[types]]`. This lets you rename the defaults, add new types, or set custom prefixes and icons used in the TUI.

```toml
[[types]]
name = "rfc"
plural = "rfcs"
dir = "docs/rfcs"
prefix = "RFC"
icon = "●"

[[types]]
name = "spec"
plural = "specs"
dir = "docs/specs"
prefix = "SPEC"
icon = "◆"
```

### Validation Rules

Validation rules define structural constraints between document types. Two shapes are supported:

- `parent-child` -- the child type must link to a parent type via a given relationship.
- `relation-existence` -- documents of a given type must have at least one relationship.

```toml
[[rules]]
shape = "parent-child"
name = "stories-need-rfcs"
child = "story"
parent = "rfc"
link = "implements"
severity = "warning"

[[rules]]
shape = "relation-existence"
name = "adrs-need-relations"
type = "adr"
require = "any-relation"
severity = "error"
```

### Numbering

Document numbers are assigned automatically during `create`. Three strategies are available per type:

| Strategy | Behaviour |
|---------------|-----------|
| `incremental` | Next sequential integer from existing files (default) |
| `sqids` | Short hash-like IDs derived from a timestamp, configured via `[numbering.sqids]` |
| `reserved` | Reserves numbers on a git remote before creating files, preventing distributed collisions |

Reserved numbering uses git custom refs (`refs/reservations/*`) to coordinate across branches. It wraps either incremental or sqids formatting with an atomic push-based lock, so two people never get the same number.

```toml
[[types]]
name = "rfc"
prefix = "RFC"
numbering = "reserved"

[numbering.reserved]
remote = "origin" # default
format = "incremental" # or "sqids"
max_retries = 5 # push retry attempts before failing
```

If the remote is unreachable, `create` fails rather than silently falling back. Use `lazyspec reservations prune` to clean up refs for documents that have been created.

### Templates

Place markdown templates in the templates directory (`.lazyspec/templates/` by default). When creating a document, lazyspec uses the template matching the document type name (e.g. `rfc.md`, `story.md`).

## Development

### Nix (recommended)

The repo includes a Nix flake that provides the full toolchain. With [direnv](https://direnv.net/) installed:

```sh
direnv allow
```

Or enter the dev shell manually:

```sh
nix develop
```

This gives you cargo, clippy, rustfmt, and rust-analyzer at pinned versions.

To run all checks (clippy, tests, formatting):

```sh
nix flake check
```

### Without Nix

```sh
cargo build
cargo test
```