CLI

The specdown command line drives every workflow: scaffolding projects, running specs, generating reports, and dumping Alloy models.

Getting Started

A specdown workflow has three parts: a spec documentdepends that describes behavior, a configuration filedepends that registers adapters, and the specdown run command.

$ specdown version
... (1 line)dev

Dry-run mode parses and validates spec files without executing adapters. This is useful for checking syntax before a full run.

$ specdown run -dry-run 2>&1 | grep 'spec(s)'
... (1 line)total: 12 spec(s), 125 case(s)

Init

specdown init scaffolds a new project with a config file, entry file, and example spec. The generated project is runnable immediately.

Scaffold a new project and verify it runs
rm -rf .tmp-test/init-test && mkdir -p .tmp-test/init-test && cd .tmp-test/init-test && specdown init 2>&1
$ cd .tmp-test/init-test && specdown run -dry-run 2>&1 | grep 'spec(s)'
... (1 line)total: 2 spec(s), 0 case(s)

Commands

Command Description
specdown init Scaffold a new project
specdown run Parse, execute, and generate reports in one pass
specdown trace Validate trace graph and output results
specdown install skills Install Claude Code skills for this project
specdown version Print the build version
specdown alloy dump Generate Alloy model .als files without running adapters

Every command listed above must appear in the help output.

Verify all commands appear in help
help=$(specdown --help 2>&1) echo "$help" | grep -q "init" echo "$help" | grep -q "run" echo "$help" | grep -q "trace" echo "$help" | grep -q "install skills" echo "$help" | grep -q "version" echo "$help" | grep -q "alloy dump"

Flags

Flag Default Description
-config specdown.json Config file path
-out (per config file) HTML report output path
-filter (none) Case filter (heading substring or type:, block:, check: prefix)
-jobs 1 Number of spec files to run in parallel
-dry-run false Parse and validate only
-show-bindings false Print resolved variable bindings for each case
-quiet false Suppress progress output; show only final summary

Trace Flags

Flag Default Description
-config specdown.json Config file path
-format json Output format: json, dot, or matrix
-strict false Suppress output and exit non-zero when validation errors exist

Trace

The specdown trace command validates the traceabilitydepends graph configured in specdown.json and outputs the result.

Without -strict, validation errors are printed to stderr but the graph is still written to stdout and the command exits successfully. With -strict, any validation error causes a non-zero exit.

Three output formats are supported: json (structured graph data), dot (Graphviz), and matrix (tabular traceability matrix).

The trace command requires a trace key in the config file.

Verify trace command rejects configs without trace key
! specdown trace -config .tmp-test/builtin-shell-cfg.json 2>/dev/null

Filter

The -filter flag selects which cases to run. Without a prefix it matches heading paths by substring, preserving backward compatibility.

$ specdown run -dry-run -filter "Filter" 2>&1 | head -1
... (1 line)spec: specs/cli.spec.md

Type Filter

A type: prefix selects cases by kind.

Filter Matches
type:code Code blocks (run:*)
type:table Check table rows
type:expect Inline expect assertions
type:alloy Alloy model checks only
type:alloy keeps only alloy checks; block:shell keeps only code blocks
mkdir -p .tmp-test printf '%s\n' '# Typed' '' '## Code' '' '```run:shell' 'echo hello' '```' '' '## Model' '' '```alloy:model(tf)' 'module tf' 'sig A {}' 'assert noEmpty { some A }' 'check noEmpty for 3' '```' > .tmp-test/typed-filter.spec.md printf '# T\n\n- [Typed](typed-filter.spec.md)\n' > .tmp-test/index.spec.md printf '{"entry":"index.spec.md","adapters":[]}' > .tmp-test/typed-filter-cfg.json alloy_dry=$(specdown run -config .tmp-test/typed-filter-cfg.json -dry-run -filter "type:alloy" 2>&1) echo "$alloy_dry" | grep -q 'alloy:' ! echo "$alloy_dry" | grep -q '\[run:shell\]' block_dry=$(specdown run -config .tmp-test/typed-filter-cfg.json -dry-run -filter "block:shell" 2>&1) echo "$block_dry" | grep -q '\[run:shell\]' ! echo "$block_dry" | grep -q 'alloy:'

Block and Check Filters

A block: prefix matches code blocks by adapter target. A check: prefix matches check table rows by check name.

Combining Filters

A single -filter flag selects cases. Only one filter can be active at a time — if -filter is passed multiple times, the last value wins.

A filter that matches nothing produces zero cases
specdown run -dry-run -filter "NoSuchHeading" 2>&1 | grep -q '0 case'

Install Skills

specdown install skills creates a .claude/skills/specdown/ directory with a SKILL.md and all reference specs so that Claude Code can write, run, and fix specs without leaving the editor.

Install skills into a fresh directory and list created files
rm -rf .tmp-test/skill-install && mkdir -p .tmp-test/skill-install cd .tmp-test/skill-install && specdown install skills 2>/dev/null

The installed files are the skill definition plus one reference per spec:

$ ls .tmp-test/skill-install/.claude/skills/specdown/ | sort
SKILL.md adapter-protocol.md alloy.md best-practices.md cli.md config.md internals.md overview.md report.md syntax.md traceability.md validation.md

Running the command again without --overwrite is rejected:

$ cd .tmp-test/skill-install && specdown install skills 2>&1 | grep -q 'already exists' && echo "blocked"
blocked

With --overwrite, existing files are replaced:

Overwrite succeeds
cd .tmp-test/skill-install && specdown install skills --overwrite 2>/dev/null

Error Messages

The CLI reports clear errors for common mistakes.

Missing Config File

When -config points to a non-existent file, the error is immediate.

! specdown run -config nonexistent.json 2>/dev/null

Invalid JSON Config

Malformed JSON in the config file is reported as a parse error.

Reject syntactically invalid JSON
printf 'NOT JSON' > .tmp-test/invalid.json ! specdown run -config .tmp-test/invalid.json 2>/dev/null