Spec-driven development CLI plus a Claude Code plugin. Specs are the source of truth; code serves specs.
Two parts shipped from this one repo:
- CLI – plumbing for spec management:
init,new,changes,info,archive,validate,refs,link,unlink. No skill installation, no priming -- those moved to the plugin. - Claude Code plugin –
skills/,agents/,plugins/claude/hooks/at the repo root, plus.claude-plugin/plugin.json. Users install it via Claude Code's plugin mechanism. The SessionStart hookcatsplugins/claude/hooks/prime.mdto prime the agent at session start.
The plugin tree is generated by shablon from .shablon/templates/. Edit templates, run just plugins (= shablon generate), commit both the templates and the rendered output.
.shablon/ # Source of truth for plugin content
├── vars.py # Render context (version, spexl --help)
├── config.toml
└── templates/
├── _includes/prime.md # Shared partial for SessionStart hook body
├── skills/<skill>/SKILL.md
├── agents/<agent>.md
└── plugins/claude/hooks/{hooks.json,prime.md}
skills/, agents/, plugins/ # Rendered plugin tree (committed)
.claude-plugin/plugin.json # Plugin manifest (hand-written)
src/spexl/
├── __init__.py # main() entry point, argparse routing
├── __main__.py # `python -m spexl`
├── config.py # .spexl.toml discovery/loading
├── errors.py # SpexlError + exit-code conventions
├── specroot.py # locate specs/ from CWD
└── cli/
├── changes.py # new, changes, info, archive
├── init.py # init (project scaffold)
├── refs.py
├── links.py # link, unlink
└── validate.py # validate (+ --fix)
specs/ # spexl's own specs (dogfooding)
tests/ # pytest
.spexl.toml # Project config
plugin_src is a symlink to .shablon/ for editor discoverability -- one source tree, two names.
uv run spexl– run the CLI locallyuv run pytest– run testsjust plugins– re-render the plugin tree from.shablon/templates/uv tool install -e .– install the CLI locally for end-to-end testing
spexl is intended for use by AI agents. All errors exit 1 with a clear explanation so the agent can reason about what went wrong. Prefer crashing over silent failures.
Whenever plumbing commands are updated, check whether validate (+ --fix) logic needs updating to cover new fields or invariants.
explore [topic] → Think before proposing
propose [description] → Create change + all artifacts (proposal, deltas, design, tasks)
refine [instruction] → Update any artifact
apply [spec slug] → Implement and verify
archive [spec slug] → Sync deltas to reference + archive
- Edit the template under
.shablon/templates/. - Run
just plugins(orshablon generate). - Commit both the template change and the rendered output. Tests assert the rendered tree exists; CI catches stale renders.
Update CHANGELOG.md when committing notable changes.
Items should start with verbs like 'added', 'removed', 'fixed', 'improved', 'changed', etc.
- Increment version number. Stick to 'zero-ver', as breaking changes are still possible.
- Update CHANGELOG.md: change
## [Unreleased]to version + date - Update
project.version=in pyproject.toml. - Commit and tag:
git add <relevant files> git commit -m "release: v0.4.0" git tag v0.4.0 git push && git push origin v0.4.0