ajhahn.de
← eeco
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"
}