chore(main): release 0.6.0 (#163)

* chore(main): release 0.6.0

* fix(release-engineering): align validators with release tooling

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Magnus Hedemark <magnus919@pm.me>
This commit is contained in:
github-actions[bot]
2026-08-02 21:59:20 -04:00
committed by GitHub
co-authored by github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Magnus Hedemark
parent a57c96a9d5
commit 22ee6494b1
10 changed files with 367 additions and 31 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
{
".": "0.5.0"
".": "0.6.0"
}
+96
View File
@@ -1,5 +1,101 @@
# Changelog
## [0.6.0](https://github.com/magnus919/agent-skills/compare/v0.5.0...v0.6.0) (2026-08-03)
### Features
* add CNCF Landscape technology selection skill ([622f341](https://github.com/magnus919/agent-skills/commit/622f341ea467616174592e036c5d3fa8f121ae03))
* add comic chat PNG renderer skill ([2494a66](https://github.com/magnus919/agent-skills/commit/2494a663952f32d5807f900804bafc05aa417352))
* add lightweight test-hardening path to neckbeard ([#230](https://github.com/magnus919/agent-skills/issues/230)) ([36d3fa8](https://github.com/magnus919/agent-skills/commit/36d3fa837e928951aa17bfc7ec4dc772f47becc6))
* **agent-production-operations:** add agent production operations bundle ([#229](https://github.com/magnus919/agent-skills/issues/229)) ([ac1ad5d](https://github.com/magnus919/agent-skills/commit/ac1ad5dbd905fe8de6ea3298896b56d845f30fc7)), closes [#201](https://github.com/magnus919/agent-skills/issues/201)
* binary-analysis skill with Ghidra backend ([0d4a365](https://github.com/magnus919/agent-skills/commit/0d4a3652e4ccb3c25869f5baca52a29f08ddbf44))
* **binary-analysis:** implement CLI skeleton with argparse, JSON envelope, and exit codes ([e9397bb](https://github.com/magnus919/agent-skills/commit/e9397bbb542b195e6c9741805bad491a13ff9ef5))
* **bundles:** define bundle manifests and lifecycle capability matrix ([#203](https://github.com/magnus919/agent-skills/issues/203)) ([#231](https://github.com/magnus919/agent-skills/issues/231)) ([aa893e3](https://github.com/magnus919/agent-skills/commit/aa893e3ec20594da4982f645a31b2675f0abdcf8))
* **capacity-and-cost-engineering:** add capacity-and-cost-engineering skill ([#199](https://github.com/magnus919/agent-skills/issues/199)) ([#224](https://github.com/magnus919/agent-skills/issues/224)) ([a471888](https://github.com/magnus919/agent-skills/commit/a4718886761af0f90438cfd7c14f2460f4dfff89))
* **ci:** add linting, formatting, coverage, and security configs ([476d7e1](https://github.com/magnus919/agent-skills/commit/476d7e11b02f2bee65a2368adff02d9366376791))
* **ci:** add mypy, radon, and deptry to CI pipeline ([bfe05ef](https://github.com/magnus919/agent-skills/commit/bfe05ef18aed5f90e17b2da4b725d1a4d565bfe1))
* **conditional-customer-success:** add conditional customer success skill ([#192](https://github.com/magnus919/agent-skills/issues/192)) ([#218](https://github.com/magnus919/agent-skills/issues/218)) ([1dd564e](https://github.com/magnus919/agent-skills/commit/1dd564e3d9eb8d73129332658d8b7504beeb0f89))
* **decompile:** implement decompile command with pseudocode, address map, and diagnostics ([3e4f07a](https://github.com/magnus919/agent-skills/commit/3e4f07a34cf14550802005c111f91eb76aa710b9))
* **doctor-bootstrap:** implement doctor, bootstrap, and version commands ([55c1451](https://github.com/magnus919/agent-skills/commit/55c145185fd88d51267f5fa776d67207546fd874))
* **domain-foundation:** implement canonical domain model with entities, enums, schemas, errors, and selectors ([3481663](https://github.com/magnus919/agent-skills/commit/3481663595a097a8cb5b1d9fa87db74024ff7813))
* **fake-backend:** implement FakeAdapter with controllable backend testing ([6184673](https://github.com/magnus919/agent-skills/commit/6184673f3585da829d5b64feaba1a6154f16ace4))
* fix remaining agent readiness signals for level 5 ([865a1e9](https://github.com/magnus919/agent-skills/commit/865a1e90c6bb6bdb23c2b182be2fddbf26fd0c17))
* **fix-coverage-config:** add .coveragerc with placeholder module omissions and exclude plain-text output helpers ([86b248e](https://github.com/magnus919/agent-skills/commit/86b248e89a2425fdff520be48eb6aa042f4c6579))
* **fix-fake-adapter-env:** add BINARY_FAKE_* env var support to FakeAdapter ([c408259](https://github.com/magnus919/agent-skills/commit/c408259a7269da8528c250961e6f52b0875df66b))
* **fix-missing-tests:** add register_binary(), clamp warnings in JSON envelope, and new tests ([50e48de](https://github.com/magnus919/agent-skills/commit/50e48deeb7b318b630a6fe4f645e9a34de176246))
* **function-queries:** implement functions, disassemble, and bytes CLI commands ([3cf347b](https://github.com/magnus919/agent-skills/commit/3cf347b06035f6651585686966d867e43e19a5d7))
* **ghidra-adapter:** implement GhidraAdapter skeleton with PyGhidra bridge ([9e8234f](https://github.com/magnus919/agent-skills/commit/9e8234f70f8df1d77b6ca6484f6942bc42f4739e))
* **implementation-planning:** add implementation planning skill ([#217](https://github.com/magnus919/agent-skills/issues/217)) ([f82515e](https://github.com/magnus919/agent-skills/commit/f82515e85d6620e962a93d6341be9d0474b83215)), closes [#186](https://github.com/magnus919/agent-skills/issues/186)
* **import-analyze:** implement binary import, analyze, and metadata commands ([f4e254a](https://github.com/magnus919/agent-skills/commit/f4e254ac6703005fcdb702b63aa64dbaaaa0dfa4))
* improve agent readiness with dev tooling, CI checks, and tests ([6b44d6f](https://github.com/magnus919/agent-skills/commit/6b44d6f490481de100667d900066024f88deafe3))
* **incident-learning:** add incident-learning skill ([#226](https://github.com/magnus919/agent-skills/issues/226)) ([4f14ce3](https://github.com/magnus919/agent-skills/commit/4f14ce3df6e447848392dd477de13a9b5531c7d8)), closes [#200](https://github.com/magnus919/agent-skills/issues/200)
* **json-contracts:** implement JSON contract consistency across all commands ([801a5be](https://github.com/magnus919/agent-skills/commit/801a5be65f2478dd8a04677be1c0f7a90093cd75))
* **migration-engineering:** add migration-engineering skill ([#222](https://github.com/magnus919/agent-skills/issues/222)) ([652521a](https://github.com/magnus919/agent-skills/commit/652521a09e16f222ada2a74ce6a7ed760396dc91))
* **neckbeard:** issue-to-PR delivery workflow ([#181](https://github.com/magnus919/agent-skills/issues/181)-[#185](https://github.com/magnus919/agent-skills/issues/185)) ([#208](https://github.com/magnus919/agent-skills/issues/208)) ([4a4958b](https://github.com/magnus919/agent-skills/commit/4a4958b6761bcdb4382770e4096b92f5a644fcf7))
* **privacy-engineering:** add privacy-engineering skill ([#202](https://github.com/magnus919/agent-skills/issues/202)) ([#225](https://github.com/magnus919/agent-skills/issues/225)) ([6f429a9](https://github.com/magnus919/agent-skills/commit/6f429a91b1a41505c512fe529dd10d67f3b141eb))
* **product-adoption:** add product adoption skill ([#214](https://github.com/magnus919/agent-skills/issues/214)) ([11a6595](https://github.com/magnus919/agent-skills/commit/11a6595d1ca9539fb97e118fdd17fb5026788905))
* **product-analytics-and-measurement:** add product analytics and measurement skill ([#213](https://github.com/magnus919/agent-skills/issues/213)) ([6b650b7](https://github.com/magnus919/agent-skills/commit/6b650b722c2657a45c2f97630bca9ca72e687fcf))
* **product-experimentation:** add product experimentation skill ([#212](https://github.com/magnus919/agent-skills/issues/212)) ([0b32a96](https://github.com/magnus919/agent-skills/commit/0b32a96521e72b21fa5a387da271f19365ce8c0f))
* **product-lifecycle-learning:** add product lifecycle learning skill ([#194](https://github.com/magnus919/agent-skills/issues/194)) ([#219](https://github.com/magnus919/agent-skills/issues/219)) ([2c247a1](https://github.com/magnus919/agent-skills/commit/2c247a17473edce9b41ccd90f59f01e42d22a7ca))
* **product-lifecycle:** add thin product-lifecycle bundle ([#227](https://github.com/magnus919/agent-skills/issues/227)) ([46b92aa](https://github.com/magnus919/agent-skills/commit/46b92aa489891e45be0bf3afe3d69021394c1737)), closes [#187](https://github.com/magnus919/agent-skills/issues/187)
* **product-operations-and-governance:** add product operations and governance skill ([#216](https://github.com/magnus919/agent-skills/issues/216)) ([7756266](https://github.com/magnus919/agent-skills/commit/77562664b87cb3d556e154600735b5a1eb863a95)), closes [#193](https://github.com/magnus919/agent-skills/issues/193)
* **product-roadmapping-and-portfolio:** add product roadmapping and portfolio skill ([#215](https://github.com/magnus919/agent-skills/issues/215)) ([5d95dd6](https://github.com/magnus919/agent-skills/commit/5d95dd6a303303244af42ca821e998a4454efbd3)), closes [#189](https://github.com/magnus919/agent-skills/issues/189)
* **production-excellence:** add thin production-excellence bundle ([#228](https://github.com/magnus919/agent-skills/issues/228)) ([8c05a07](https://github.com/magnus919/agent-skills/commit/8c05a076bb1a29700bdadc246f2bf7a93faff34c))
* **production-readiness:** add production-readiness skill ([#221](https://github.com/magnus919/agent-skills/issues/221)) ([2183c22](https://github.com/magnus919/agent-skills/commit/2183c221352a939636c278b54e10087b6fe31aa9))
* **project-lifecycle:** implement all project lifecycle commands and state machine ([756b50e](https://github.com/magnus919/agent-skills/commit/756b50e285cfa038de4731aeb6204b737885804a))
* **project-system:** implement workspace, manifest, locking, and cache ([defe46c](https://github.com/magnus919/agent-skills/commit/defe46c1386d4c518318e95ba557a2ad96f74a33))
* **qa-methodology:** add 2 stdlib-only CLI scripts and colocated pytest suite ([974fde0](https://github.com/magnus919/agent-skills/commit/974fde017cf6760d491caec7f4c0c79bb1b54b04))
* **qa-methodology:** add 3 new traditional QA references ([ff69b09](https://github.com/magnus919/agent-skills/commit/ff69b0982f036543392352c635ecbefff78893da))
* **qa-methodology:** add 5 fillable templates and 3 assets ([3325787](https://github.com/magnus919/agent-skills/commit/332578766db926695a31adc24060aa6d0665abe8))
* **qa-methodology:** add modern agentic references (ai-code-quality-gates, agentic-eval-design) ([aa8c027](https://github.com/magnus919/agent-skills/commit/aa8c027a6e2d0ed8fba3af93f3bd7ce6dfe1e3de))
* **qa-methodology:** add modern QA career levels and SDET engineering references ([9b10ff5](https://github.com/magnus919/agent-skills/commit/9b10ff546ae968b6df9909ae6f7192c148543d33))
* **qa-methodology:** add mutation-guided test hardening evidence workflow ([8bd042e](https://github.com/magnus919/agent-skills/commit/8bd042eae5a851419c3f6324e4709eb894a8e36f)), closes [#209](https://github.com/magnus919/agent-skills/issues/209)
* **qa-methodology:** add schema-v1 evals with 7 output-quality cases ([107d6d1](https://github.com/magnus919/agent-skills/commit/107d6d11631f70e957b16605ca0bdf4a098e833d))
* **qa-methodology:** rebuild as thin-index QA/SDET skill bundle ([726de89](https://github.com/magnus919/agent-skills/commit/726de898e8d8b81b9cfb2a13902f38d0cf8c63a0))
* **qa-methodology:** rebuild SKILL.md as thin index and rewrite README.md ([8b0220b](https://github.com/magnus919/agent-skills/commit/8b0220b75b62907e9c954cc7dc60584ba077b616))
* **qa-methodology:** refresh 5 traditional QA support references ([5bad13a](https://github.com/magnus919/agent-skills/commit/5bad13af568567529071f65d4cd756ac8492a1c8))
* **qa-methodology:** refresh traditional QA core references and split monolithic file ([966edcf](https://github.com/magnus919/agent-skills/commit/966edcf0c75e2eb64f4320e1f455d64776928ba5))
* **reference-queries:** implement xrefs, callers, callees, and callgraph CLI commands ([93b0431](https://github.com/magnus919/agent-skills/commit/93b04315a9cdfe987d7390aff947aae5df59dd4d))
* **release-engineering:** add release engineering skill bundle ([818d8ca](https://github.com/magnus919/agent-skills/commit/818d8cafa2b435b1556fdafa8603aa70f39cf01d))
* **reporting:** implement export-report and audit commands ([010a308](https://github.com/magnus919/agent-skills/commit/010a3086aa373afc82edb4a0947ee8cfee16be4a))
* **resilience-and-recovery:** add resilience-and-recovery skill ([#223](https://github.com/magnus919/agent-skills/issues/223)) ([c032580](https://github.com/magnus919/agent-skills/commit/c032580197f2f370d4f96895fafc09b36c21f4dd))
* **safety-hardening:** implement path security, output limits, memory limits, and report containment ([e62cf47](https://github.com/magnus919/agent-skills/commit/e62cf47a9b2b01905bfbf0864be7fe13365c7908))
* **search-trace:** implement search and trace commands with cross-area integration flows ([1ead735](https://github.com/magnus919/agent-skills/commit/1ead735513a00bfb3b8dc5a93a82cfb074e30072))
* **security-rules:** implement suspicious-apis and capability-map commands ([d005b9a](https://github.com/magnus919/agent-skills/commit/d005b9aadaa2e7404d4718a7a55877a40c000f20))
* **skill-content:** write SKILL.md and README.md for binary-analysis skill ([72d8462](https://github.com/magnus919/agent-skills/commit/72d8462f073cb20cdeb8dc6b48c08c9515bfc431))
* **skill-evals:** write 6 eval cases for binary-analysis skill ([f79124d](https://github.com/magnus919/agent-skills/commit/f79124d360ae4212816bf595a7ccff9425252a90))
* **skill-references:** write 11 reference files for binary-analysis skill ([a799e0f](https://github.com/magnus919/agent-skills/commit/a799e0f7eb46d48867f0ca9cff5b94c0b22d21f7))
* **structural-queries:** implement sections, entrypoints, imports, exports, symbols, and strings CLI commands ([7df699b](https://github.com/magnus919/agent-skills/commit/7df699ba20d94d09479104caafbad403962269db))
* **triage-diagnostics:** implement triage and diagnostics commands ([0e05960](https://github.com/magnus919/agent-skills/commit/0e05960dd6c53ffa2b07b929469ffa5a22c61ec8))
* **worker:** implement optional local worker with start/stop/status commands and one-shot fallback ([5e8f1d3](https://github.com/magnus919/agent-skills/commit/5e8f1d3aafbb5f06a2aa7898cd16a4d390db7012))
### Bug Fixes
* **ci:** add binary-analysis to deptry extend_exclude ([8ea4053](https://github.com/magnus919/agent-skills/commit/8ea4053e01826008582b9e942fdecae7c3932361))
* **ci:** add sys.path setup in test __init__.py for unittest discover ([4c7f5c4](https://github.com/magnus919/agent-skills/commit/4c7f5c42f49cdc9eba4c537a47f6fe2352b20ded))
* **ci:** add sys.path setup to all test sub-package __init__.py files ([f9354df](https://github.com/magnus919/agent-skills/commit/f9354df2870a97fe85d15e66ad1df1de94afc3f7))
* **ci:** add sys.path setup to individual binary-analysis test files ([736859e](https://github.com/magnus919/agent-skills/commit/736859eafa9ab7c40d0291479a6d87f4a6895055))
* **ci:** prevent sys.modules cross-contamination between test directories in check-artifacts ([96f0bd4](https://github.com/magnus919/agent-skills/commit/96f0bd4e46c8023cd5035aba2299df70562c2837))
* **ci:** use full path for deptry binary-analysis exclude ([b56183b](https://github.com/magnus919/agent-skills/commit/b56183bbabed58089bf79e3d571433e8fe6dd217))
* permit removal of eval-covered skills ([687d7d7](https://github.com/magnus919/agent-skills/commit/687d7d7c33510b7496c50052161596f34ad58eae))
* **product-strategy:** correct stale RICE reference ([#211](https://github.com/magnus919/agent-skills/issues/211)) ([8d30f22](https://github.com/magnus919/agent-skills/commit/8d30f22cb89508b2982c36b8a627a79944f5f2b6))
* **release-engineering:** address review findings in DORA asset, cadence, link, metrics script ([2b90656](https://github.com/magnus919/agent-skills/commit/2b906565d443bf7d460cfe1a8f5d5c258844de51))
* **release-engineering:** align 0.x version bumps with Release Please's minor-feature policy
* **release-engineering:** validate Keep a Changelog and Release Please formats
* relocate binary analysis skill ([6387f7f](https://github.com/magnus919/agent-skills/commit/6387f7f4752a2dd8fd7a92a7e640ec6b62c11698))
* require dated commitments for CoS tasks ([857dfc6](https://github.com/magnus919/agent-skills/commit/857dfc6e1cecccf94ec241a89be20bca3a539fb3))
* **security-ship:** ensure diagnostics have both recoverable values and add pagination cursors to security commands ([d04af37](https://github.com/magnus919/agent-skills/commit/d04af37602eae8304e4c089076c047a0eae8fb9c))
* **security-ship:** fix --limit routing, truncation warnings, and clean confirmation order ([7b0109b](https://github.com/magnus919/agent-skills/commit/7b0109b328c097e6c40c1ff07ac3ce4c01e98aa2))
* **security-ship:** fix three scrutiny blocking issues ([a20adde](https://github.com/magnus919/agent-skills/commit/a20adde298209480b49279aca84a5b6e3c54457e))
* state CoS task-capture boundary ([f285316](https://github.com/magnus919/agent-skills/commit/f285316206258471343c66ea9bfaf15f07f3bfbc))
### Reverts
* restore clean base64 import in helpers.py ([746df95](https://github.com/magnus919/agent-skills/commit/746df95150e7ec092c2d37daa8261f4c3d12004a))
## [0.5.0](https://github.com/magnus919/agent-skills/compare/v0.4.0...v0.5.0) (2026-07-27)
+3 -1
View File
@@ -15,7 +15,7 @@ It also covers the parts of release work that quietly break teams: versioning an
| `references/` | 15 dense topic files: role-and-career, skills-competency-model, release-process-models, cd-and-pipeline-stages, progressive-delivery, change-governance-and-compliance, readiness-and-quality-gates, rollback-and-recovery, versioning-and-artifacts, feature-flag-lifecycle, monorepo-polyrepo-release, toolchain-landscape, supply-chain-security, metrics-and-dora, release-operations-and-triage |
| `templates/` | 6 fillable templates: release-plan, release-readiness-checklist, rollback-runbook, release-notes, change-governance-record, hotfix-emergency-release-plan |
| `assets/` | 4 quick-reference files: dora-metrics-reference, versioning-decision-table, deployment-strategy-matrix, release-toolchain-cheatsheet |
| `scripts/` | 5 Python CLIs: version_bump (next-SemVer from conventional commits), semver_check (validate/compare/sort), changelog_check (Keep a Changelog validator), dora_metrics (five-metric computation), release_plan_scaffold (plan generator) |
| `scripts/` | 5 Python CLIs: version_bump (next-SemVer from conventional commits, including the documented 0.x policy), semver_check (validate/compare/sort), changelog_check (Keep a Changelog and Release Please validator), dora_metrics (five-metric computation), release_plan_scaffold (plan generator) |
| `evals/` | Schema-v1 output-quality eval manifest (8 cases) |
## Quick Start
@@ -30,6 +30,8 @@ Validate a changelog before it ships:
```bash
python3 release-engineering/scripts/changelog_check.py CHANGELOG.md
# Or select Release Please's linked-header format explicitly:
python3 release-engineering/scripts/changelog_check.py CHANGELOG.md --format release-please
```
Compute the five DORA metrics from deployment and commit event data:
+3 -3
View File
@@ -93,7 +93,7 @@ Senior-to-principal release engineering methodology: designing and operating the
| `assets/release-toolchain-cheatsheet.md` | Quick tool lookup by category — one-liner and when-to-pick per tool |
| `scripts/version_bump.py` | Computing the next SemVer from conventional commits or a git range |
| `scripts/semver_check.py` | Validating, comparing, or sorting strict SemVer versions |
| `scripts/changelog_check.py` | Validating a CHANGELOG.md against Keep a Changelog |
| `scripts/changelog_check.py` | Validating Keep a Changelog or Release Please CHANGELOG.md files |
| `scripts/dora_metrics.py` | Computing the five DORA metrics from deployment and commit event data |
| `scripts/release_plan_scaffold.py` | Scaffolding a release plan document from flags or a git range |
| `evals/evals.json` | Running output-quality evals for this skill (schema v1, 8 cases) |
@@ -107,9 +107,9 @@ Senior-to-principal release engineering methodology: designing and operating the
| Script | Invocation | Purpose |
|--------|-----------|---------|
| version_bump | `python3 scripts/version_bump.py --current-version 1.4.0 --git-range v1.4.0..HEAD` | Computes the next SemVer from Conventional Commits — breaking → major, feat → minor, fix → patch; optional prerelease tag |
| version_bump | `python3 scripts/version_bump.py --current-version 1.4.0 --git-range v1.4.0..HEAD` | Computes the next SemVer from Conventional Commits — breaking → major (minor in 0.x), feat → minor, fix → patch; optional prerelease tag |
| semver_check | `python3 scripts/semver_check.py --check 1.2.3-beta.1` | Validates strict SemVer 2.0.0, compares two versions, or sorts a list |
| changelog_check | `python3 scripts/changelog_check.py CHANGELOG.md` | Validates a changelog against Keep a Changelog headers, dates, change types, link references |
| changelog_check | `python3 scripts/changelog_check.py CHANGELOG.md [--format auto|keep-a-changelog|release-please]` | Validates supported changelog headers, dates, sections, bullets, and links; reports selected/detected format |
| dora_metrics | `python3 scripts/dora_metrics.py --events events.json` | Computes all five DORA metrics from deployment and commit event data |
| release_plan_scaffold | `python3 scripts/release_plan_scaffold.py --version 2.0.0 --owner alice --output plan.md` | Scaffolds a release plan document with filled placeholders from flags or a git range |
@@ -36,9 +36,14 @@
| `BREAKING CHANGE:` footer, or `feat!` / `fix!` | MAJOR | `feat!: drop v1 API` |
| `feat` | MINOR | `feat(auth): add refresh tokens` |
| `fix` | PATCH | `fix(api): retry on 429` |
| `perf`, `refactor`, `docs`, `test`, `chore`, `ci`, `build`, `style` | No bump (or PATCH, if you choose) | `docs: update readme` |
| `perf`, `refactor`, `docs`, `test`, `chore`, `ci`, `build`, `style` | PATCH in this skill | `docs: update readme` |
> **Gotcha —** the bump is decided by the highest-priority type in the release range: one `BREAKING CHANGE` forces a major even if the rest are fixes. Automate with the `version_bump.py` script.
For `0.y.z`, this skill's Release Please-compatible policy maps both
`feat` and breaking changes to MINOR (`0.5.0` -> `0.6.0`), while fixes and
other changes remain PATCH. At `1.0.0` and later, normal SemVer priority
applies.
> **Gotcha —** the bump is decided by the highest-priority type in the release range: one `BREAKING CHANGE` forces a MAJOR at 1.0.0+, or a MINOR bump in 0.x, even if the rest are fixes. Automate with the `version_bump.py` script.
## Prerelease and Build Metadata Rules
@@ -42,7 +42,7 @@ Two rules that commonly surprise: numeric identifiers compare **numerically** (`
`0.y.z` means **initial development**: the spec explicitly states that "anything may change at any time" and the public API should not be considered stable. Practical consequences:
- `0.1.0``0.2.0` usually signals breaking changes in pre-1.0 libraries — the `1.0.0` MAJOR convention is effectively deferred.
- Many tools map `feat` commits to MINOR even in 0.x, which can silently bump `0.3.0``0.4.0` for an additive change. Decide and document your 0.x policy; a common choice is "breaking changes bump MINOR until 1.0."
- This skill's default Release Please-compatible policy maps `feat` and breaking commits to MINOR in 0.x (`0.5.0``0.6.0`); fixes and other commit types remain PATCH (`0.5.0``0.5.1`). This keeps pre-1.0 release lines meaningful while preserving normal SemVer behavior at 1.0+.
- Consumers pinning `0.x` with caret ranges (`^0.3.1`) get **no automatic updates** in most package managers (npm, for example, treats caret on `0.x` as `>=0.3.1 <0.4.0`), which is exactly the behavior you want for a pre-stable API.
Declare a policy so both humans and automation agree on what a `0.x` bump means:
@@ -50,7 +50,7 @@ Declare a policy so both humans and automation agree on what a `0.x` bump means:
| Policy | Rule | Consequence |
|--------|------|-------------|
| **Strict** | Breaking changes bump MAJOR even in 0.x | Version jumps `0.3.0``1.0.0` early; signals commitment before the API is ready |
| **Deferred** (most common) | Breaking changes bump MINOR until 1.0 | `0.3.0``0.4.0`; 1.0 arrives when the API stabilizes |
| **Deferred** (skill default) | Features and breaking changes bump MINOR until 1.0; fixes and other changes bump PATCH | `0.5.0``0.6.0` for `feat`, `0.5.0``0.5.1` for `fix`; 1.0 arrives when the API stabilizes |
| **Tooling-default** | Whatever your release tool computes from commits | Usually `feat`→MINOR; document that pre-1.0 MINOR may break |
> **Gotcha — The 0.x trap:** A 1.0.0 release is a promise about API stability. If your library has public consumers, treat 1.0.0 as a deliberate commitment — and conversely, do not stay in `0.x` forever because bumping to 1.0 feels risky; consumers already treat `0.x` as unstable either way.
@@ -138,7 +138,7 @@ Consistency matters more than the exact mapping: if `perf` bumps PATCH in one re
Automated bump tooling reads this history: **semantic-release** analyzes commits and performs version + changelog + publish with no human gate; **release-please** generates a release PR (version bump + changelog) that a human merges; **git-cliff** generates the changelog from commits without publishing. For monorepo specifics (per-package vs combined releases), see [monorepo-polyrepo-release.md](./monorepo-polyrepo-release.md).
## Changelogs (Keep a Changelog)
## Changelogs (Keep a Changelog and Release Please)
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) is the de-facto human changelog format, designed for **people, not machines** (machines read commits). Core conventions:
@@ -169,7 +169,7 @@ A minimal conforming structure:
[2.1.0]: https://github.com/acme/app/compare/v2.0.0...v2.1.0
```
The `scripts/changelog_check.py` in this skill validates this shape: required `# Changelog` title, `[Unreleased]` section, strict-SemVer date-stamped version headers, allowed change types, and consistent reference links.
The `scripts/changelog_check.py` in this skill validates this shape with `--format keep-a-changelog` (or safe `--format auto` detection). It also validates Release Please output with linked dated headers such as `## [0.6.0](https://github.com/example/proj/compare/v0.5.0...v0.6.0) (2026-08-03)`, conventional `###` sections such as `Features`, `Bug Fixes`, and `Reverts`, and `*` bullets with inline links. Release Please section labels are configurable. Release Please files do not use an `Unreleased` section; select that format explicitly in CI when auto-detection is not appropriate.
## Artifact Immutability and Promotion
+149 -11
View File
@@ -1,9 +1,21 @@
#!/usr/bin/env python3
"""Validate a CHANGELOG.md against the Keep a Changelog conventions.
"""Validate Keep a Changelog or Release Please CHANGELOG.md files.
Checks performed:
- The first non-empty line is the `# Changelog` title.
- A `## [Unreleased]` section exists.
Keep a Changelog validation requires the first non-empty line to be the
`# Changelog` title, an `## [Unreleased]` section, dated version headers,
allowed change types, and reference links. Release Please validation accepts
linked dated headers such as `## [1.2.0](https://...) (2026-08-03)`, conventional
changelog sections such as `Features`, `Bug Fixes`, and `Reverts`, and star
bullets; it rejects an `Unreleased` section. Release Please section labels are
configurable, so the validator checks that non-empty `###` headings contain the
bullets.
With `--format auto` (the default), a valid Release Please header selects the
Release Please validator; otherwise the strict Keep a Changelog validator is
used. Explicit `--format` selection is available for CI gates.
Keep a Changelog checks:
- Version headers use the form `## [X.Y.Z] - YYYY-MM-DD` with a strict
SemVer version (pre-releases allowed) and a valid ISO-8601 date
(YYYY-MM-DD or YYYY-MM); the optional `[YANKED]` marker is allowed.
@@ -18,7 +30,7 @@ Checks performed:
Each problem is reported with its line number. Exit 0 when the file is
clean, exit 1 when any problem is found.
Arguments: [changelog.md] (default: CHANGELOG.md), --json.
Arguments: [changelog.md] (default: CHANGELOG.md), --format, --json.
Exit codes:
0 changelog is valid
@@ -37,10 +49,15 @@ UNRELEASED_HEADER_RE = re.compile(r"^##\s+\[Unreleased\](\s+\[YANKED\])?\s*$")
VERSION_HEADER_RE = re.compile(
r"^##\s+\[([^\]]+)\]\s*-\s*(\d{4}-\d{2}-\d{2}|\d{4}-\d{2})(\s+\[YANKED\])?\s*$"
)
RELEASE_PLEASE_HEADER_RE = re.compile(
r"^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\((\d{4}-\d{2}-\d{2})\)\s*$"
)
BULLET_RE = re.compile(r"^-\s+(\S+)")
STAR_BULLET_RE = re.compile(r"^\*\s+(\S+)")
LINK_REF_RE = re.compile(r"^\[([^\]]+)\]:\s+(\S+)")
CHANGE_TYPES = ("Added", "Changed", "Deprecated", "Removed", "Fixed", "Security")
FORMATS = ("auto", "keep-a-changelog", "release-please")
SEMVER_RE = re.compile(
r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)"
@@ -55,10 +72,8 @@ def parse_args(argv=None):
parser = argparse.ArgumentParser(
prog="changelog_check.py",
description=(
"Validate a CHANGELOG.md against the Keep a Changelog "
"conventions: title, [Unreleased] section, strict SemVer version "
"headers with valid dates, allowed change-type bullets, and "
"consistent reference links."
"Validate a CHANGELOG.md as Keep a Changelog or Release Please; "
"auto-detect the format unless explicitly selected."
),
epilog=(
"Exit codes: 0 valid, 1 problems found / file unreadable, "
@@ -66,6 +81,7 @@ def parse_args(argv=None):
"Examples:\n"
" changelog_check.py\n"
" changelog_check.py CHANGELOG.md\n"
" changelog_check.py CHANGELOG.md --format release-please\n"
" changelog_check.py CHANGELOG.md --json\n"
),
)
@@ -76,6 +92,16 @@ def parse_args(argv=None):
metavar="CHANGELOG.md",
help="Path to the changelog file (default: CHANGELOG.md).",
)
parser.add_argument(
"--format",
choices=FORMATS,
default="auto",
dest="format",
help=(
"Changelog format: auto (default), keep-a-changelog, or "
"release-please."
),
)
parser.add_argument(
"--json",
action="store_true",
@@ -107,7 +133,15 @@ def valid_date(text):
return False
def check_changelog(text):
def detect_format(text):
"""Detect Release Please only from its unambiguous linked header shape."""
for line in text.splitlines():
if RELEASE_PLEASE_HEADER_RE.match(line.rstrip()):
return "release-please"
return "keep-a-changelog"
def check_keep_a_changelog(text):
"""Validate changelog text; returns (valid, problems).
problems is a list of {"line": int, "message": str} dicts.
@@ -252,6 +286,104 @@ def check_changelog(text):
return len(problems) == 0, problems
def check_release_please(text):
"""Validate the Release Please changelog format."""
problems = []
lines = text.splitlines()
non_empty = [i for i, line in enumerate(lines) if line.strip()]
if not non_empty:
return False, [{"line": 1, "message": "file is empty"}]
if not TITLE_RE.match(lines[non_empty[0]].strip()):
problems.append(
{
"line": non_empty[0] + 1,
"message": "expected '# Changelog' title as the first non-empty line",
}
)
in_section = False
subsection = None
release_count = 0
for idx, raw in enumerate(lines):
line = raw.rstrip()
stripped = line.strip()
lineno = idx + 1
if line.startswith("## "):
in_section = False
subsection = None
if stripped == "## [Unreleased]" or stripped.startswith("## [Unreleased]"):
problems.append(
{"line": lineno, "message": "Release Please files must not contain an '## [Unreleased]' section"}
)
continue
match = RELEASE_PLEASE_HEADER_RE.match(stripped)
if not match:
problems.append(
{
"line": lineno,
"message": "malformed Release Please version header (expected '## [X.Y.Z](<url>) (YYYY-MM-DD)')",
}
)
continue
version, url, date_text = match.groups()
release_count += 1
in_section = True
if not valid_semver(version):
problems.append(
{"line": lineno, "message": "version '{}' is not strict SemVer".format(version)}
)
if not url.startswith(("https://", "http://")):
problems.append(
{"line": lineno, "message": "Release Please header link must be an http(s) URL"}
)
if not valid_date(date_text):
problems.append(
{"line": lineno, "message": "invalid release date '{}' in header".format(date_text)}
)
continue
if not in_section:
continue
if line.startswith("### "):
subsection = stripped[len("### "):].strip()
if not subsection:
problems.append(
{
"line": lineno,
"message": "Release Please subsection headings must not be empty",
}
)
continue
if stripped.startswith("*"):
if not STAR_BULLET_RE.match(stripped):
problems.append(
{"line": lineno, "message": "malformed Release Please bullet (expected '* <change>')"}
)
elif subsection is None:
problems.append(
{"line": lineno, "message": "Release Please bullets must be under a subsection heading"}
)
continue
if stripped.startswith("-"):
problems.append(
{"line": lineno, "message": "Release Please bullets must use '*' rather than '-'"}
)
if release_count == 0:
problems.append({"line": 1, "message": "missing Release Please version section"})
return len(problems) == 0, problems
def check_changelog(text, format="auto"):
"""Validate text using an explicit format or safe auto-detection."""
selected = detect_format(text) if format == "auto" else format
if selected == "release-please":
return check_release_please(text)
return check_keep_a_changelog(text)
def main(argv=None):
"""Entry point."""
args = parse_args(argv)
@@ -262,13 +394,17 @@ def main(argv=None):
print("error: cannot read '{}': {}".format(args.changelog, exc), file=sys.stderr)
return 1
valid, problems = check_changelog(text)
detected_format = detect_format(text)
selected_format = detected_format if args.format == "auto" else args.format
valid, problems = check_changelog(text, selected_format)
if args.json_output:
print(
json.dumps(
{
"file": args.changelog,
"format": selected_format,
"detected_format": detected_format,
"valid": valid,
"problem_count": len(problems),
"problems": problems,
@@ -278,7 +414,9 @@ def main(argv=None):
)
else:
if not problems:
print("valid: {} conforms to Keep a Changelog".format(args.changelog))
print("valid: {} conforms to {} (detected: {})".format(
args.changelog, selected_format, detected_format
))
else:
for problem in problems:
print(
+4 -3
View File
@@ -11,8 +11,9 @@ Bump rules (Conventional Commits 1.0.0):
- BREAKING CHANGE footer, or a `!` after the type/scope -> MAJOR
- feat -> MINOR
- fix and all other types -> PATCH
- 0.x versions (initial development): MAJOR bumps become MINOR,
MINOR bumps become PATCH (the public API is not yet stable).
- 0.x versions (initial development): MAJOR and MINOR bumps both become
MINOR under the documented Release Please-compatible policy, while
PATCH bumps remain PATCH.
Pre-release handling (--pre-release alpha|beta|rc):
- If the current version is already a pre-release with the SAME tag
@@ -194,7 +195,7 @@ def bump_core(current, level):
return (major + 1, 0, 0)
if level == "minor":
if major == 0:
return (major, minor, patch + 1)
return (major, minor + 1, 0)
return (major, minor + 1, 0)
return (major, minor, patch + 1)
@@ -1,7 +1,7 @@
"""Tests for changelog_check.py.
Covers: Keep a Changelog validation (title, [Unreleased], version headers,
dates, change types, reference links), --json output, and exit codes.
Covers: Keep a Changelog and Release Please validation, format selection,
--json output, and exit codes.
Discoverable by both pytest and unittest (unittest.TestCase classes).
"""
@@ -38,6 +38,21 @@ All notable changes to this project will be documented in this file.
[1.1.0]: https://github.com/example/proj/releases/tag/v1.1.0
"""
VALID_RELEASE_PLEASE = """\
# Changelog
## [0.6.0](https://github.com/magnus919/agent-skills/compare/v0.5.0...v0.6.0) (2026-08-03)
### Features
* add a feature ([abc123](https://github.com/example/proj/commit/abc123))
### Bug Fixes
* fix a bug ([def456](https://github.com/example/proj/commit/def456))
### Reverts
* revert an earlier change ([fedcba](https://github.com/example/proj/commit/fedcba))
"""
def run_changelog(args, cwd=None):
"""Run changelog_check.py with given args, return (returncode, stdout, stderr)."""
@@ -144,6 +159,36 @@ class TestChangelogCheckValid(unittest.TestCase):
finally:
os.unlink(path)
def test_release_please_format_valid(self):
"""Release Please's dated linked headers and star bullets pass."""
path = write_changelog(VALID_RELEASE_PLEASE)
try:
rc, out, _ = run_changelog([path])
self.assertEqual(rc, 0)
self.assertIn("release-please", out.lower())
finally:
os.unlink(path)
def test_release_please_explicit_format_valid(self):
"""The Release Please format can be selected explicitly."""
path = write_changelog(VALID_RELEASE_PLEASE)
try:
rc, out, _ = run_changelog([path, "--format", "release-please"])
self.assertEqual(rc, 0)
self.assertIn("release-please", out.lower())
finally:
os.unlink(path)
def test_release_please_custom_section_valid(self):
"""Custom Release Please section names remain valid."""
content = VALID_RELEASE_PLEASE.replace("### Features", "### Documentation")
path = write_changelog(content)
try:
rc, _, _ = run_changelog([path, "--format", "release-please"])
self.assertEqual(rc, 0)
finally:
os.unlink(path)
class TestChangelogCheckProblems(unittest.TestCase):
"""Each Keep a Changelog violation is reported with exit 1."""
@@ -256,6 +301,32 @@ class TestChangelogCheckProblems(unittest.TestCase):
finally:
os.unlink(path)
def test_malformed_release_please_header_exit_1(self):
"""A Release Please header without its compare link is invalid."""
content = VALID_RELEASE_PLEASE.replace(
"## [0.6.0](https://github.com/magnus919/agent-skills/compare/v0.5.0...v0.6.0) (2026-08-03)",
"## [0.6.0] (2026-08-03)",
)
path = write_changelog(content)
try:
rc, out, _ = run_changelog([path, "--format", "release-please"])
self.assertEqual(rc, 1)
self.assertIn("header", out.lower())
finally:
os.unlink(path)
def test_release_please_rejects_unreleased_section(self):
"""Release Please files must not contain Keep a Changelog Unreleased."""
path = write_changelog(VALID_RELEASE_PLEASE.replace(
"# Changelog\n", "# Changelog\n\n## [Unreleased]\n"
))
try:
rc, out, _ = run_changelog([path, "--format", "release-please"])
self.assertEqual(rc, 1)
self.assertIn("unreleased", out.lower())
finally:
os.unlink(path)
class TestChangelogCheckExitCodes(unittest.TestCase):
"""Exit codes for missing files and usage errors."""
@@ -300,6 +371,29 @@ class TestChangelogCheckJsonOutput(unittest.TestCase):
self.assertTrue(data["valid"])
self.assertEqual(data["problem_count"], 0)
self.assertEqual(data["problems"], [])
self.assertEqual(data["format"], "keep-a-changelog")
finally:
os.unlink(path)
def test_json_release_please_reports_format(self):
"""JSON reports the selected and detected Release Please format."""
path = write_changelog(VALID_RELEASE_PLEASE)
try:
rc, out, _ = run_changelog([path, "--json"])
self.assertEqual(rc, 0)
data = json.loads(out)
self.assertEqual(data["format"], "release-please")
self.assertEqual(data["detected_format"], "release-please")
finally:
os.unlink(path)
def test_explicit_keep_format_rejects_release_please(self):
"""Explicit Keep a Changelog validation remains strict."""
path = write_changelog(VALID_RELEASE_PLEASE)
try:
rc, out, _ = run_changelog([path, "--format", "keep-a-changelog"])
self.assertEqual(rc, 1)
self.assertIn("unreleased", out.lower())
finally:
os.unlink(path)
@@ -114,15 +114,15 @@ class TestVersionBumpBumpRules(unittest.TestCase):
finally:
os.unlink(commits)
def test_zero_major_feat_bumps_patch(self):
"""On a 0.x version, feat bumps patch."""
def test_zero_major_feat_bumps_minor(self):
"""On a 0.x version, feat follows Release Please and bumps minor."""
commits = write_temp_file("feat: add helper\n")
try:
rc, out, _ = run_version_bump(
["--current-version", "0.2.0", "--commits-file", commits]
["--current-version", "0.5.0", "--commits-file", commits]
)
self.assertEqual(rc, 0)
self.assertIn("0.2.1", out)
self.assertIn("0.6.0", out)
finally:
os.unlink(commits)