Generated: 2026-01-01 Project: CLI tool for managing specifications and change proposals
Spectr enforces a three-stage workflow: propose → validate → archive. Specs (spectr/specs/) represent current truth. Changes (spectr/changes/) are proposed deltas. Archive merges deltas and preserves history.
spectr/
├── cmd/ # CLI commands (Kong framework)
├── internal/ # Business logic (not importable externally)
│ ├── validation/ # Spec/change validation rules
│ ├── markdown/ # Custom parser (lexer + AST)
│ ├── parsers/ # Requirement/delta parsing
│ ├── archive/ # Spec merging and archiving
│ ├── initialize/ # Init wizard + templates
│ ├── pr/ # PR creation via git worktree
│ ├── tui/ # Bubble Tea interactive UI
│ └── [other packages] # Domain types, discovery, etc.
├── spectr/ # Spec-driven workflow
│ ├── specs/ # Current truth
│ ├── changes/ # Proposals (deltas)
│ └── changes/archive/ # Completed changes
└── testdata/ # Fixtures and integration tests
| Task | Location | Notes |
|---|---|---|
| CLI entry points | cmd/*.go | Kong framework, thin layer |
| Markdown parsing | internal/markdown/ | Custom lexer/parser, NOT goldmark |
| Validation logic | internal/validation/ | Spec format enforcement |
| Spec merging | internal/archive/ | Delta → spec merge algorithm |
| PR workflow | internal/pr/ | Git worktree isolation |
| TUI components | internal/tui/ | Bubble Tea, lipgloss styles |
| Symbol | Type | Location | Role |
|---|---|---|---|
| CLI | struct | cmd/root.go | Kong CLI entry point |
| Parse() | func | internal/markdown/api.go | Main parser entry |
| ValidateSpec() | func | internal/validation/ | Spec validation |
| ValidateChange() | func | internal/validation/ | Change validation |
| Archive() | func | internal/archive/ | Archive workflow |
| NewSpecMerger() | func | internal/archive/ | Spec merging |
- No external importability: internal/ packages cannot be imported outside this project
- Table-driven tests: Use t.Run() subtests, fixtures in testdata/
- Nix dev shell: All commands run in
nix developornix develop -c - Go 1.25+: Required toolchain
- NEVER suppress type errors: No
as any,@ts-ignore,@ts-expect-error - NEVER commit without request: Explicit user approval required
- NO circular dependencies: cmd → internal flow only
- DON'T shotgun debug: Fix root causes, not symptoms
- Markdown parser: Custom implementation (NOT goldmark), two-phase (lexer → parser)
- Spec-driven: All work tracked in spectr/ with proposals before implementation
- Incremental parsing: Tree-sitter-style diff-based reparsing (ParseIncremental)
# Development
nix develop -c tests # Run all tests with race detector
nix develop -c lint # golangci-lint + markdownlint on spectr/
nix fmt # Format Go + Nix files
go build -o spectr # Build binary
# Spectr workflow
spectr list # List active changes
spectr validate <id> # Validate change
spectr accept <id> # Convert tasks.md → tasks.jsonc
spectr pr archive <id> # Archive + create PR- Validation is strict: All issues treated as errors (no warnings in strict mode)
- Archive is atomic: Spec merge + move happens together or not at all
- tasks.md vs tasks.jsonc: Both coexist after accept. Update statuses in .jsonc, regenerate from .md on structure changes
- Git worktrees: PR commands create isolated worktrees, cleanup automatically
- Multi-platform PRs: Supports GitHub (gh), GitLab (glab), Gitea/Forgejo (tea), Bitbucket (manual)
Instructions for AI coding assistants using Spectr for spec-driven development.
- Search existing work: Read
spectr/changes/andspectr/specs/directories (usergfor full-text search) - Decide scope: new capability vs modify existing capability
- Pick a unique
change-id: kebab-case, verb-led (add-,update-,remove-,refactor-) - Scaffold:
proposal.md,tasks.md,design.md(only if needed), and delta specs per affected capability - Write deltas: use
## ADDED|MODIFIED|REMOVED|RENAMED Requirements; include at least one#### Scenario:per requirement - Validate:
spectr validate [change-id]and fix issues - Request approval: Do not start implementation until proposal is approved
Create proposal when you need to:
- Add features or functionality
- Make breaking changes (API, schema)
- Change architecture or patterns
- Optimize performance (changes behavior)
- Update security patterns
Loose matching guidance:
- Contains one of:
proposal,change,spec - With one of:
create,plan,make,start,help
Skip proposal for:
- Bug fixes (restore intended behavior)
- Typos, formatting, comments
- Dependency updates (non-breaking)
- Configuration changes
- Tests for existing behavior
Workflow:
- Review
spectr/project.mdand readspectr/specs/andspectr/changes/directories to understand current context. - Choose a unique verb-led
change-idand scaffoldproposal.md,tasks.md, optionaldesign.md, and spec deltas underspectr/changes/<id>/. - Draft spec deltas using
## ADDED|MODIFIED|REMOVED Requirementswith at least one#### Scenario:per requirement. - Run
spectr validate <id>and resolve any issues before sharing the proposal.
Track these steps as TODOs and complete them one by one.
- Read proposal.md - Understand what's being built
- Read design.md (if exists) - Review technical decisions
- Read tasks.md - Get implementation checklist
- Implement tasks sequentially - Complete in order
- Confirm completion - Ensure every item in
tasks.mdis finished before updating statuses - Update checklist - After all work is done, set every task to
- [x]so the list reflects reality - Approval gate - Do not start implementation until the proposal is reviewed and approved
Context Checklist:
- Read relevant specs in
specs/[capability]/spec.md - Check pending changes in
changes/for conflicts - Read
spectr/project.mdfor conventions - Read
spectr/changes/directory to see active changes - Read
spectr/specs/directory to see existing capabilities
Before Creating Specs:
- Always check if capability already exists
- Prefer modifying existing specs over creating duplicates
- Read
spectr/specs/<capability>/spec.mddirectly to review current state - If request is ambiguous, ask 1-2 clarifying questions before scaffolding
- Enumerate specs: Read
spectr/specs/directory (orspectr spec list --longfor formatted output) - Enumerate changes: Read
spectr/changes/directory (orspectr listfor formatted output) - Read details directly:
- Spec: Read
spectr/specs/<capability>/spec.md - Change: Read
spectr/changes/<change-id>/proposal.md
- Spec: Read
- Full-text search (use ripgrep):
rg -n "Requirement:|Scenario:" spectr/specs
# Essential commands
spectr list # List active changes
spectr list --specs # List specifications
spectr validate [item] # Validate changes or specs
# Project management
spectr init [path] # Initialize or update instruction files
# Interactive mode
spectr validate # Bulk validation mode
# Debugging
spectr validate [change]Reading Specs and Changes (for AI agents):
- Specs: Read
spectr/specs/<capability>/spec.mddirectly - Changes: Read
spectr/changes/<change-id>/proposal.mddirectly - Tasks: Read
spectr/changes/<change-id>/tasks.mddirectly
--json- Machine-readable output--type change|spec- Disambiguate items--no-interactive- Disable prompts
spectr/
├── project.md # Project conventions
├── specs/ # Current truth - what IS built
│ └── [capability]/ # Single focused capability
│ ├── spec.md # Requirements and scenarios
│ └── design.md # Implementation details (code structures, APIs, data models)
├── changes/ # Proposals - what SHOULD change
│ ├── [change-name]/
│ │ ├── proposal.md # Why, what, impact
│ │ ├── tasks.md # Implementation checklist
│ │ ├── design.md # Implementation details (optional; see criteria)
│ │ └── specs/ # Delta changes
│ │ └── [capability]/
│ │ └── spec.md # ADDED/MODIFIED/REMOVED
│ └── archive/ # Completed changes
| Task | Location | Notes |
|---|---|---|
| Create proposals | spectr/changes/ | Scaffold with proposal.md, tasks.md, delta specs |
| Validate changes | spectr validate | Enforce scenarios, formatting rules |
| Accept proposals | spectr accept | Convert tasks.md → tasks.jsonc |
| Archive changes | spectr archive | Merge deltas into specs/ |
| View status | spectr view | Interactive dashboard |
- Verb-led IDs: Use
add-,update-,remove-,refactor-prefixes - Delta operations: Use
## ADDED,## MODIFIED,## REMOVED,## RENAMED Requirements - Scenario format: Use
#### Scenario:(4 hashtags) with WHEN/THEN bullets - tasks.md + tasks.jsonc: Both coexist, update status in .jsonc after accept
- Spec-driven development: All features tracked in specs/ before implementation
- Three-stage workflow: Propose → Validate (pre-implementation) → Archive (post-deployment)
- Dual task files: tasks.md (human-readable) + tasks.jsonc (machine-readable)
- NEVER implement without proposal: Features need change in spectr/changes/
- DON'T skip validation: Always run
spectr validatebeforespectr accept - NO partial MODIFIED: MODIFIED requirements must include complete content (header + all scenarios)
- NO scenario-less requirements: Every requirement must have at least one scenario
New request?
├─ Bug fix restoring spec behavior? → Fix directly
├─ Typo/format/comment? → Fix directly
├─ New feature/capability? → Create proposal
├─ Breaking change? → Create proposal
├─ Architecture change? → Create proposal
└─ Unclear? → Create proposal (safer)
-
Create directory:
changes/[change-id]/(kebab-case, verb-led, unique) -
Write proposal.md:
# Change: [Brief description of change]
## Why
[1-2 sentences on problem/opportunity]
## What Changes
- [Bullet list of changes]
- [Mark breaking changes with BREAKING]
## Impact
- Affected specs: [list capabilities]
- Affected code: [key files/systems]- Create spec deltas:
specs/[capability]/spec.md
## ADDED Requirements
### Requirement: New Feature
The system SHALL provide...
#### Scenario: Success case
- WHEN user performs action
- THEN expected result
## MODIFIED Requirements
### Requirement: Existing Feature
[Complete modified requirement]
## REMOVED Requirements
### Requirement: Old Feature
Reason: [Why removing]
Migration: [How to handle]If multiple capabilities are affected, create multiple delta files under
changes/[change-id]/specs/<capability>/spec.md—one per capability.
- Create tasks.md:
## 1. Implementation
- [ ] 1.1 Create database schema
- [ ] 1.2 Implement API endpoint
- [ ] 1.3 Add frontend component
- [ ] 1.4 Write tests- Create design.md when needed:
Create design.md if any of the following apply; otherwise omit it:
- Cross-cutting change (multiple services/modules) or a new architectural pattern
- New external dependency or significant data model changes
- Security, performance, or migration complexity
- Ambiguity that benefits from technical decisions before coding
Minimal design.md skeleton:
## Implementation Details
[Specific implementation details such as:]
- Data structures and type definitions
- API signatures and interfaces
- File and directory structures
- Code snippets showing patterns
- Configuration schemas
## Context
[Background, constraints, stakeholders]
## Goals / Non-Goals
- Goals: [...]
- Non-Goals: [...]
## Decisions
- Decision: [What and why]
- Alternatives considered: [Options + rationale]
## Risks / Trade-offs
- [Risk] → Mitigation
## Migration Plan
[Steps, rollback]
## Open Questions
- [...]Proposals can declare dependencies on other proposals using YAML frontmatter:
---
id: feat-dashboard
requires:
- id: feat-auth
reason: "needs user model and session management"
- id: feat-db
reason: "needs schema migrations for dashboard tables"
enables:
- id: feat-analytics
reason: "unlocks event tracking on dashboard"
---Fields:
id: Optional explicit ID for this proposalrequires: List of proposals that must be archived before this can be acceptedenables: Informational list of proposals this unlocks (not enforced)
Behavior:
spectr validate: Warns if required proposals aren't archived, errors on cyclesspectr accept: Hard fails if anyrequiresentries aren't archivedspectr graph: Visualizes the proposal dependency DAG
Commands:
# View dependency graph (ASCII)
spectr graph
# View graph for specific proposal
spectr graph <change-id>
# Output in Graphviz DOT format
spectr graph --dot
# Output in JSON format
spectr graph --jsonExample Graph Output:
feat-dashboard (⧖)
├── requires: feat-auth ✓
├── requires: feat-db ⧖
└── enables: feat-analytics
Legend: ✓ = archived, ⧖ = active/pending
CORRECT (use #### headers):
#### Scenario: User login success
- WHEN valid credentials provided
- THEN return JWT tokenWRONG (don't use bullets or bold):
- Scenario: User login ❌
Scenario: User login ❌
### Scenario: User login ❌Every requirement MUST have at least one scenario.
- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)
## ADDED Requirements- New capabilities## MODIFIED Requirements- Changed behavior## REMOVED Requirements- Deprecated features## RENAMED Requirements- Name changes
Headers matched with trim(header) - whitespace ignored.
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren't explicitly changing the existing requirement, add a new requirement under ADDED instead.
Authoring a MODIFIED requirement correctly:
- Locate the existing requirement in
spectr/specs/<capability>/spec.md. - Copy the entire requirement block (from
### Requirement: ...through its scenarios). - Paste it under
## MODIFIED Requirementsand edit to reflect the new behavior. - Ensure the header text matches exactly (whitespace-insensitive) and keep at
least one
#### Scenario:.
Example for RENAMED:
## RENAMED Requirements
- FROM: `### Requirement: Login`
- TO: `### Requirement: User Authentication`"Change must have at least one delta"
- Check
changes/[name]/specs/exists with .md files - Verify files have operation prefixes (## ADDED Requirements)
"Requirement must have at least one scenario"
- Check scenarios use
#### Scenario:format (4 hashtags) - Don't use bullet points or bold for scenario headers
Silent scenario parsing failures
- Exact format required:
#### Scenario: Name - Debug by reading the delta spec file directly:
spectr/changes/<change-id>/specs/<capability>/spec.md
# Validate a change (validation is always strict by default)
spectr validate [change]For validation debugging:
- Read delta specs directly:
spectr/changes/<change-id>/specs/<capability>/spec.md - Check spec content by reading:
spectr/specs/<capability>/spec.md
# 1) Explore current state
spectr spec list --long
spectr list
# Optional full-text search:
# rg -n "Requirement:|Scenario:" spectr/specs
# rg -n "^#|Requirement:" spectr/changes
# 2) Choose change id and scaffold
CHANGE=add-two-factor-auth
mkdir -p spectr/changes/$CHANGE/{specs/auth}
printf "## Why\\n...\\n\\n## What Changes\\n- ...\\n\\n## Impact\\n- ...\\n" \
> spectr/changes/$CHANGE/proposal.md
printf "## 1. Implementation\\n- [ ] 1.1 ...\\n" \
> spectr/changes/$CHANGE/tasks.md
# 3) Add deltas (example)
cat > spectr/changes/$CHANGE/specs/auth/spec.md << 'EOF'
## ADDED Requirements
### Requirement: Two-Factor Authentication
Users MUST provide a second factor during login.
#### Scenario: OTP required
- WHEN valid credentials are provided
- THEN an OTP challenge is required
EOF
# 4) Validate
spectr validate $CHANGEspectr/changes/add-2fa-notify/
├── proposal.md
├── tasks.md
└── specs/
├── auth/
│ └── spec.md # ADDED: Two-Factor Authentication
└── notifications/
└── spec.md # ADDED: OTP email notification
auth/spec.md
## ADDED Requirements
### Requirement: Two-Factor Authentication
...notifications/spec.md
## ADDED Requirements
### Requirement: OTP Email Notification
...- Default to <100 lines of new code
- Single-file implementations until proven insufficient
- Avoid frameworks without clear justification
- Choose boring, proven patterns
Only add complexity with:
- Performance data showing current solution too slow
- Concrete scale requirements (>1000 users, >100MB data)
- Multiple proven use cases requiring abstraction
- Use
file.ts:42format for code locations - Reference specs as
specs/auth/spec.md - Link related changes and PRs
- Use verb-noun:
user-auth,payment-capture - Single purpose per capability
- 10-minute understandability rule
- Split if description needs "AND"
- Use kebab-case, short and descriptive:
add-two-factor-auth - Prefer verb-led prefixes:
add-,update-,remove-,refactor- - Ensure uniqueness; if taken, append
-2,-3, etc.
| Task | Tool | Why |
|---|---|---|
| Find files by pattern | Glob | Fast pattern matching |
| Search code content | Grep | Optimized regex search |
| Read specific files | Read | Direct file access |
| Explore unknown scope | Task | Multi-step investigation |
- Read
spectr/changes/directory to see active changes - Check for overlapping specs
- Coordinate with change owners
- Consider combining proposals
- Run
spectr validate(validation is always strict) - Check JSON output for details
- Verify spec file format
- Ensure scenarios properly formatted
- Read project.md first
- Check related specs
- Review recent archives
- Ask for clarification
Reading Details (for AI agents):
- Read
spectr/specs/<capability>/spec.mdfor spec details - Read
spectr/changes/<change-id>/proposal.mdfor change details
Remember: Specs are truth. Changes are proposals. Keep them in sync.