Use conventional commits:
<type>(<scope>): <subject>
Types: feat, fix, perf, refactor, docs, test, chore, style, ci
Subject: imperative mood, 50 chars max, no period.
AI-authored commits should be prefixed with claude: before the type (e.g. claude: feat(parser): add range expressions). The changelog tooling strips this prefix automatically.
Releases are managed by scripts/release.sh and a GitHub Actions workflow.
- On the
mainbranch with a clean working tree - All CI checks passing
cd specl
# 1. Run the release script with the new version
./scripts/release.sh 0.2.0
# This will:
# - Validate semver format (X.Y.Z)
# - Update version in workspace Cargo.toml (workspace.package.version + dependency versions)
# - Run cargo check --workspace
# - Create commit: chore(release): v0.2.0
# - Create annotated tag: v0.2.0
# 2. Review the commit
git log -1
git diff HEAD~1
# 3. Push to trigger the release workflow
git push && git push --tagsPushing the tag triggers .github/workflows/release.yml which:
- Runs the full CI suite (fmt, clippy, tests)
- Cross-compiles
speclfor 4 targets (x86_64/aarch64 Linux and macOS) - Generates release notes from the changelog (
git-cliff --latest) - Creates a GitHub Release with the binaries as tarballs
The changelog is generated by git-cliff from conventional commits. Configuration is in specl/cliff.toml.
To preview the changelog locally:
cd specl
git cliff # print to stdout
git cliff --latest # only the latest tag rangeTo regenerate the full CHANGELOG.md:
cd specl
git cliff --output CHANGELOG.md