CLI Usage¶
Specwright includes a command-line tool for scaffolding projects, generating code, validating coverage, and producing documentation.
Overview¶
| Command | Description |
|---|---|
specwright init |
Scaffold a new project |
specwright new function |
Generate a @spec-decorated function |
specwright new statemachine |
Generate a StateMachine subclass |
specwright validate |
Check specs and test coverage |
specwright docs |
Generate API documentation |
specwright init¶
Scaffold a complete project with the right structure:
Creates:
my_project/
pyproject.toml # Poetry config with specwright dependency
.specwright.toml # Specwright configuration
README.md
my_project/
__init__.py # Sample @spec function
tests/
__init__.py
examples/
Default Project Name¶
What's in the Generated Files¶
pyproject.toml — Pre-configured with specwright as a dependency and pytest settings:
[tool.poetry.dependencies]
python = "^3.11"
specwright = "^0.1.0"
[tool.pytest.ini_options]
testpaths = ["tests"]
specwright_test_enforcement = "strict"
__init__.py — A sample @spec function to get you started:
from specwright import spec
@spec
def hello(name: str) -> str:
"""Greet someone by name."""
return f"Hello, {name}!"
.specwright.toml — Project-level configuration:
Existing directory
init will refuse to overwrite an existing directory:
specwright new function¶
Generate a @spec-decorated function and its test file:
Creates two files:
calculate_score.py:
from specwright import spec
@spec
def calculate_score(base: int, multiplier: float) -> float:
"""TODO: Describe what calculate_score does."""
...
test_calculate_score.py:
from calculate_score import calculate_score
def test_calculate_score_happy_path():
result = calculate_score(0, 0.0)
# TODO: Add assertions
...
Interactive Mode¶
Omit --params and --returns to be prompted:
$ specwright new function greet
Parameters (e.g. 'x: int, y: str') [x: int]: name: str, excited: bool
Return type [int]: str
Created greet.py
Created test_greet.py
Options¶
| Flag | Description |
|---|---|
--params |
Parameter list (e.g. "x: int, y: str") |
--returns |
Return type (e.g. "int") |
--no-tests |
Skip test file generation |
--output-dir |
Output directory (default: .) |
Test File Placement¶
If a tests/ directory exists in the output directory, the test file goes there:
$ ls
tests/
$ specwright new function calc --params "x: int" --returns int
Created calc.py
Created tests/test_calc.py # Placed in tests/
Validation¶
Invalid Python identifiers are rejected:
Existing files are not overwritten:
specwright new statemachine¶
Generate a StateMachine subclass with sequential transitions:
Creates order_processor.py with a class OrderProcessor containing transitions between consecutive states (pending -> paid -> shipped -> delivered).
Options¶
| Flag | Description |
|---|---|
--states |
Comma-separated state names |
--initial |
Initial state (default: first state) |
--no-tests |
Skip test file generation |
--output-dir |
Output directory (default: .) |
Interactive Mode¶
Omit --states to be prompted:
$ specwright new statemachine workflow
States (comma-separated) [idle,running,done]: open,review,merged,closed
Created workflow.py
Created test_workflow.py
Custom Initial State¶
The initial state must be in the states list:
$ specwright new statemachine machine --states a,b --initial z
Error: Initial state 'z' not in states: ['a', 'b']
specwright validate¶
Scan a project and check that all @spec-decorated functions have tests and state machines are well-formed:
What It Checks¶
- Test coverage — Every
@spec-decorated function should have at least onetest_<name>_*function - @requires_tests compliance — All required test names from
@requires_testsdecorators must exist - State machine reachability — All states should be reachable from the initial state via transitions
Output¶
┌────────────────────────────┬────────┐
│ Check │ Status │
├────────────────────────────┼────────┤
│ Tests for add │ pass │
│ Tests for multiply │ FAIL │
│ SM OrderProcessor reacha… │ pass │
└────────────────────────────┴────────┘
1 issue(s) found:
x No tests found for 'multiply' (expected test_multiply_*)
Exit code is 1 if any issues are found, 0 if everything passes.
No Specs Found¶
If the scanned directory has no @spec functions or state machines:
specwright docs¶
Generate Markdown API documentation from @spec metadata:
Output to File¶
Include State Diagrams¶
This generates DOT-format state diagrams for each StateMachine class found.
Generated Format¶
The output includes:
- Function name and docstring
- Parameter table (name, type)
- Return type
- Required tests (from
@requires_tests) - State machine states, transitions table, and optional diagrams
Workflow¶
The typical Specwright workflow:
# 1. Scaffold a project
specwright init my_project
cd my_project
# 2. Generate components
specwright new function process_payment \
--params "amount: float, currency: str" \
--returns dict
specwright new statemachine order_flow \
--states pending,paid,shipped,delivered
# 3. Fill in implementations (you or an LLM)
# 4. Validate coverage
specwright validate
# 5. Generate docs
specwright docs --output API.md
Why this matters for LLM-assisted development
The CLI generates the spec scaffolding — type hints, docstrings, test stubs, state machine structure. An LLM can then fill in the implementations, guided by the spec. The validate command ensures nothing was forgotten, and docs produces documentation directly from the code's metadata.