JSON 63 lines
{
"name": "doc-drift",
"description": "Compare a documented version record (a changelog) against the source-of-truth git tags and report any drift. Reads and reports only — never edits the document, never creates, moves, or deletes a tag.",
"intent": {
"guarantee": "This skill only reads the changelog and the tag list and reports drift — it never edits the document or touches any tag",
"forbidden": [
"git tag",
"git push",
"git commit",
"git add",
"edit the changelog",
"create or move any tag"
]
},
"capabilities": [
{ "kind": "tool", "name": "Read" },
{ "kind": "tool", "name": "Grep" },
{ "kind": "tool", "name": "Glob" },
{ "kind": "tool", "name": "AskUserQuestion" },
{ "kind": "bash", "verb": "git for-each-ref", "scope": "refs/tags*" },
{ "kind": "bash", "verb": "git log", "scope": "*" },
{ "kind": "bash", "verb": "git describe", "scope": "*" },
{ "kind": "bash", "verb": "git status", "scope": "*" }
],
"params": [
{ "name": "doc", "description": "the documented version record to check", "default": "CHANGELOG.md" },
{ "name": "tag_glob", "description": "the tag pattern that is the source of truth", "default": "v*.*.*" }
],
"steps": [
{
"index": 0,
"title": "Read the documented versions",
"body": "Read the doc param (default CHANGELOG.md) and extract the set of versions it records — the section headings of the form `## [x.y.z]` or equivalent. Keep them in document order. Do not edit the file."
},
{
"index": 1,
"title": "List the source-of-truth tags",
"body": "List the release tags with the read-only command below — `git for-each-ref`, never `git tag` (which can create a tag). Filter to the tag_glob pattern (default v*.*.*). This set is the source of truth for what was actually released.",
"runs": [
"git for-each-ref --sort=-version:refname --format '%(refname:short)' refs/tags",
"git describe --tags --always"
]
},
{
"index": 2,
"title": "Diff the two sets",
"body": "Compute the symmetric difference: tags with no changelog section (released but undocumented) and changelog sections with no tag (documented but unreleased, e.g. a stale or premature entry). Normalize the `v` prefix so `v1.2.3` and `1.2.3` match."
},
{
"index": 3,
"title": "Classify each drift",
"body": "For each mismatch, classify it: missing-changelog-entry (a tag with no section — the more serious, a shipped release with no record), or unreleased-section (a section with no tag — usually an in-progress or premature entry). Note an Unreleased/building section separately; it is expected, not drift."
},
{
"index": 4,
"title": "Report, never reconcile",
"body": "Print a table of the drift with its classification, plus a one-line summary (clean, or N drifts). Recommend the fix in prose (add a section, cut a tag) but never apply it: do not edit the changelog and do not create, move, or delete a tag. The operator reconciles."
}
],
"output_format": "Print a drift table (version, classification, note) and a one-line summary. State explicitly that nothing was edited and no tag was touched.",
"maps_to_workflow": "doc-drift"
}