Specular is a CLI for enforcing spec-driven development.
It turns a plan into JSON checks.
Use it when an agent builds code from a plan and "done" is too weak.
Use it for code, docs, deps, and checks.
It is strict. It prints JSON. It fails when work drifts from the spec.
Install with
cargo install --git https://github.com/agent-quality-controls/specularTell your agent to use Specular. It should write the spec, add any scripts, and
work until verify exits 0.
Tell it to use the least custom spec that works. It should use a predefined category when one fits, use that category's builtin when one exists, and use custom only when no predefined category fits.
Specular uses JSON specs to check a plan. It gives an agent a test loop. The agent reads the plan, writes the spec, runs it, fixes the repo, and runs it again.
Exit codes:
0: the spec is valid, or the repo matches it.1: the repo does not match it.2: the spec, verifier, call shape, timeout, or run failed.
Agents can read the JSON result. Status is a pass or fail.
An agent can say the plan is done. Specular makes it prove the work.
Use this loop:
- Turn the plan into a typed JSON spec.
- Run the spec before coding.
- Confirm it fails where work is still missing.
- Build the code.
- Run
specular verifyuntil it exits0.
Use it for plans with clear parts: files, text, exports, deps, named cases, or script checks.
Use this prompt:
Use Specular for this plan.
Make a JSON spec.
Run specular lint.
Write a coverage map.
Use predefined categories first.
Use built-in verifiers when they exist.
Add verifier scripts only when no built-in fits.
Use custom only when no predefined category fits.
Run specular verify before coding.
Keep working until specular verify exits 0.
Use specular --help for the spec shape and script calls.
There are three patterns:
- Predefined categories with built-ins:
tree,content, Cargodependencies, and Rustenumerations. Use these first. - Predefined categories with no built-in for your stack:
dependencies,exports,enumerations. Use one script per block. - Custom categories: put any JSON under
custom, then write the script. Use this only when no predefined category fits.
Every non-empty block has one block-level verifier command. Built-ins are explicit:
{
"version": 4,
"requirements": {
"tree": {
"verifier": ["builtin:tree"],
"required": ["src/lib.rs"]
},
"content": [
{
"verifier": ["builtin:content"],
"files": ["README.md"],
"required": ["Specular is a CLI"]
}
],
"dependencies": [
{
"verifier": ["builtin:cargo-dependencies"],
"files": ["Cargo.toml"],
"required": ["serde"],
"forbidden": ["openssl"],
"forbiddenGlobs": ["g3*"]
}
],
"enumerations": [
{
"verifier": ["builtin:rust-enumerations"],
"files": ["src/**/*.rs"],
"name": "Category",
"values": ["Tree", "Content", "Dependencies"]
}
]
}
}Predefined categories have fixed fields. Custom entries can hold any JSON except
verifier, which Specular owns.
Do not put tree, content, Cargo package, or Rust enum checks in custom. Do
not write a script for checks the built-ins can judge.
For builtin:cargo-dependencies, required, exists, and forbidden use
exact Cargo package names. forbiddenGlobs uses package-name globs. Renamed
deps use Cargo package identity, so serde_json = { package = "serde-json", version = "..." } is checked by serde-json.
For builtin:rust-enumerations, files selects Rust files, name is an enum
name or an inline-module-qualified name such as wire::Status, and values is
the exact variant set.
Run specular --help before writing a spec. It has full examples and script
call rules.
A verifier is one command. It is encoded as argv, not as a shell string or a list of verifiers. Scripts can use any language; examples use Python.
"verifier": ["python3", "scripts/verify_deps.py", "--workspace"]Typed script blocks are called once per block:
<command...> <spec.json> <category> <blockIndex>
Custom scripts are called once per entry:
<command...> <spec.json> custom <blockIndex>
Verifier scripts print JSON proof lines. Their exit code says whether the script ran cleanly. The proof carries pass and fail.