/docs-drift
Documentation-drift audit for the plugin monorepo. Audits either each scoped plugin's unreleased changelog claims or its latest shipped release from the previous reachable plugin-name--v* tag, then checks whether the matching plugin README, docs/, CLAUDE.md or AGENTS.md files,
Claude Code
$ npx -y skills add gtapps/hermitd --skill docs-drift --agent claude-code
Codex
$ npx skills add gtapps/hermitd --skill docs-drift -a codex -y
Cursor
$ npx skills add gtapps/hermitd --skill docs-drift -a cursor -y
Gemini CLI
$ npx skills add gtapps/hermitd --skill docs-drift -a gemini-cli -y
GitHub Copilot
$ npx skills add gtapps/hermitd --skill docs-drift -a github-copilot -y
OpenCode
$ npx skills add gtapps/hermitd --skill docs-drift -a opencode -y
Windsurf
$ npx skills add gtapps/hermitd --skill docs-drift -a windsurf -y
SKILL.md
docs-drift.SKILL.mdname: docs-drift
description: Documentation-drift audit for the plugin monorepo. Audits either each scoped plugin's unreleased changelog claims or its latest shipped release from the previous reachable plugin-name--v* tag, then checks whether the matching plugin README, docs/, CLAUDE.md or AGENTS.md files, and root documentation still tell the truth. Reports meaningful drift with concrete proposed edits and asks before applying anything. Use when preparing or verifying a release, when asked to check the latest version, or when the operator says "docs drift", "check the docs", "are the docs up to date", "docs audit", "did the docs keep up", "check documentation before release", or whether documentation matches released or unreleased changes. Complements /pre-release-review, which checks changelog claims against code; this skill checks changelog claims against docs.
Docs Drift
The third leg of the release check. `/release-status` shows what is queued, `/pre-release-review` verifies that the changelog tells the truth about the code, and this skill verifies that the docs tell the truth after the change.
**Read-only until the operator approves.** The audit never edits, commits, tags, pushes, publishes, or releases. Apply only the findings the operator selects in Step 5.
Usage
- `/docs-drift` or `/docs-drift unreleased` — audit every plugin with a
non-empty `[Unreleased]` section.
- `/docs-drift <plugin-slug>` — audit that plugin's unreleased changes.
- `/docs-drift latest` — audit the latest reachable release of every tagged
plugin.
- `/docs-drift latest <plugin-slug>` — audit only that plugin's latest release.
Default to unreleased mode. Treat "latest version", "latest release", or equivalent wording as latest-release mode.
Natural ordering before a ship:
`/release-status` → `/pre-release-review` → `/docs-drift` → `/release <slug>`
Step 1 — Scope plugins and snapshots
Never mix released and unreleased windows in one claim set.
Unreleased mode
Identify plugins whose `[Unreleased]` section contains non-blank content:
for p in plugins/*/CHANGELOG.md; do
slug=$(basename "$(dirname "$p")")
awk '/^## \[Unreleased\]/{f=1; next} /^## \[/{f=0} f && NF' "$p" | rg -q '.' \
&& echo "$slug"
doneIf the operator named a plugin, limit scope to that slug after verifying it exists and has unreleased content. If nothing is in scope, stop with:
`No unreleased changes in any plugin — nothing to drift-check.`
Use the working tree as the documentation snapshot. Keep incidentally noticed older drift separate as pre-existing debt.
Latest-release mode
Start from all `plugins/*/CHANGELOG.md` slugs, or only the operator-named slug. Resolve each plugin's refs independently:
EMPTY_TREE=$(git hash-object -t tree /dev/null)
for p in plugins/*/CHANGELOG.md; do
slug=$(basename "$(dirname "$p")")
latest=$(git describe --tags --abbrev=0 --match "${slug}--v*" HEAD 2>/dev/null || true)
if [ -z "$latest" ]; then
printf '%s\n' "$slug: skipped (no reachable release tag)"
continue
fi
previous=$(git describe --tags --abbrev=0 --match "${slug}--v*" "${latest}^" 2>/dev/null || true)
printf '%s\n' "$slug latest=$latest previous=${previous:-<empty-tree>}"
doneUse only reachable `<slug>--v*` tags. Do not select an unreachable tag merely because its version sorts later. If a plugin has only one reachable tag, use the empty tree as its previous snapshot. If every scoped plugin lacks a tag, stop with:
`No reachable plugin release tags — nothing to latest-release drift-check.`
For each plugin, record:
- claim window: `<previous-tag>..<latest-tag>`, or empty tree to latest tag;
- changelog claims: the exact `## [<latest-version>]` section at the latest tag;
- documentation snapshot: the repository exactly at that plugin's latest tag.
Later commits and working-tree changes are not release claims in this mode. Different plugins may have different latest-tag snapshots; preserve the plugin-to-tag mapping throughout the audit.
Step 2 — Extract doc-checkable claims
In unreleased mode, read only each scoped plugin's working-tree `[Unreleased]` section.
In latest-release mode, derive the version from `<slug>--v<version>` and read the matching changelog section from the tagged snapshot:
version=${latest##*--v}
git show "$latest:plugins/$slug/CHANGELOG.md" | awk -v ver="$version" '
index($0, "## [" ver "]") == 1 {f=1; next}
/^## \[/ && f {exit}
f
'Also inspect the plugin-scoped release diff to catch doc-checkable operator-visible changes that a changelog bullet may group:
release_diff_base=${previous:-$EMPTY_TREE}
git diff "$release_diff_base" "$latest" -- "plugins/$slug/"Use that diff only in latest-release mode and only for claim discovery. This skill does not replace changelog-versus-code review.
Turn each bullet or diff-derived behavior into zero or more claims:
- **Removal or rename** — a skill, command, script, hook, config key, doc file,
or CLI changed identity.
- **New operator-visible surface** — a new skill, slash command, config block,
hook, CLI, or channel behavior should appear where siblings are enumerated.
- **Changed default or behavior** — docs may still state the previous default
or behavior. Treat this as the highest-severity class.
- **Count or version claim** — a hand-written number or version marker may
still contain the old value.
- **Promised documentation** — a cited file or anchor must exist and cover what
the changelog promises.
Mark pure internal fixes, refactors, and test-only changes as `no doc surface`. Do not manufacture a finding for every bullet.
Step 3 — Sweep the matching documentation
For each scoped plugin, consider the files that exist in its selected snapshot:
- `plugins/<slug>/README.md`
- `plugins/<slug>/docs/*.md`
- `plugins/<slug>/CLAUDE.md`
- `plugins/<slug>/AGENTS.md`
- top-level plugin extras such as `SAFETY.md`, `DOCKER.md`, or
`CONTRIBU
Read more
name: docs-drift description: Documentation-drift audit for the plugin monorepo. Audits either each scoped plugin's unreleased changelog claims or its latest shipped release from the previous reachable plugin-name--v* tag, then checks whether the matching plugin README, docs/, CLAUDE.md or AGENTS.md files, and root documentation still tell the truth. Reports meaningful drift with concrete proposed edits and asks before applying anything. Use when preparing or verifying a release, when asked to check the latest version, or when the operator says "docs drift", "check the docs", "are the docs up to date", "docs audit", "did the docs keep up", "check documentation before release", or whether documentation matches released or unreleased changes. Complements /pre-release-review, which checks changelog claims against code; this skill checks changelog claims against docs.
Docs Drift
The third leg of the release check. `/release-status` shows what is queued, `/pre-release-review` verifies that the changelog tells the truth about the code, and this skill verifies that the docs tell the truth after the change.
**Read-only until the operator approves.** The audit never edits, commits, tags, pushes, publishes, or releases. Apply only the findings the operator selects in Step 5.
Usage
- `/docs-drift` or `/docs-drift unreleased` — audit every plugin with a
non-empty `[Unreleased]` section.
- `/docs-drift <plugin-slug>` — audit that plugin's unreleased changes.
- `/docs-drift latest` — audit the latest reachable release of every tagged
plugin.
- `/docs-drift latest <plugin-slug>` — audit only that plugin's latest release.
Default to unreleased mode. Treat "latest version", "latest release", or equivalent wording as latest-release mode.
Natural ordering before a ship:
`/release-status` → `/pre-release-review` → `/docs-drift` → `/release <slug>`
Step 1 — Scope plugins and snapshots
Never mix released and unreleased windows in one claim set.
Unreleased mode
Identify plugins whose `[Unreleased]` section contains non-blank content:
for p in plugins/*/CHANGELOG.md; do
slug=$(basename "$(dirname "$p")")
awk '/^## \[Unreleased\]/{f=1; next} /^## \[/{f=0} f && NF' "$p" | rg -q '.' \
&& echo "$slug"
doneIf the operator named a plugin, limit scope to that slug after verifying it exists and has unreleased content. If nothing is in scope, stop with:
`No unreleased changes in any plugin — nothing to drift-check.`
Use the working tree as the documentation snapshot. Keep incidentally noticed older drift separate as pre-existing debt.
Latest-release mode
Start from all `plugins/*/CHANGELOG.md` slugs, or only the operator-named slug. Resolve each plugin's refs independently:
EMPTY_TREE=$(git hash-object -t tree /dev/null)
for p in plugins/*/CHANGELOG.md; do
slug=$(basename "$(dirname "$p")")
latest=$(git describe --tags --abbrev=0 --match "${slug}--v*" HEAD 2>/dev/null || true)
if [ -z "$latest" ]; then
printf '%s\n' "$slug: skipped (no reachable release tag)"
continue
fi
previous=$(git describe --tags --abbrev=0 --match "${slug}--v*" "${latest}^" 2>/dev/null || true)
printf '%s\n' "$slug latest=$latest previous=${previous:-<empty-tree>}"
doneUse only reachable `<slug>--v*` tags. Do not select an unreachable tag merely because its version sorts later. If a plugin has only one reachable tag, use the empty tree as its previous snapshot. If every scoped plugin lacks a tag, stop with:
`No reachable plugin release tags — nothing to latest-release drift-check.`
For each plugin, record:
- claim window: `<previous-tag>..<latest-tag>`, or empty tree to latest tag;
- changelog claims: the exact `## [<latest-version>]` section at the latest tag;
- documentation snapshot: the repository exactly at that plugin's latest tag.
Later commits and working-tree changes are not release claims in this mode. Different plugins may have different latest-tag snapshots; preserve the plugin-to-tag mapping throughout the audit.
Step 2 — Extract doc-checkable claims
In unreleased mode, read only each scoped plugin's working-tree `[Unreleased]` section.
In latest-release mode, derive the version from `<slug>--v<version>` and read the matching changelog section from the tagged snapshot:
version=${latest##*--v}
git show "$latest:plugins/$slug/CHANGELOG.md" | awk -v ver="$version" '
index($0, "## [" ver "]") == 1 {f=1; next}
/^## \[/ && f {exit}
f
'Also inspect the plugin-scoped release diff to catch doc-checkable operator-visible changes that a changelog bullet may group:
release_diff_base=${previous:-$EMPTY_TREE}
git diff "$release_diff_base" "$latest" -- "plugins/$slug/"Use that diff only in latest-release mode and only for claim discovery. This skill does not replace changelog-versus-code review.
Turn each bullet or diff-derived behavior into zero or more claims:
- **Removal or rename** — a skill, command, script, hook, config key, doc file,
or CLI changed identity.
- **New operator-visible surface** — a new skill, slash command, config block,
hook, CLI, or channel behavior should appear where siblings are enumerated.
- **Changed default or behavior** — docs may still state the previous default
or behavior. Treat this as the highest-severity class.
- **Count or version claim** — a hand-written number or version marker may
still contain the old value.
- **Promised documentation** — a cited file or anchor must exist and cover what
the changelog promises.
Mark pure internal fixes, refactors, and test-only changes as `no doc surface`. Do not manufacture a finding for every bullet.
Step 3 — Sweep the matching documentation
For each scoped plugin, consider the files that exist in its selected snapshot:
- `plugins/<slug>/README.md`
- `plugins/<slug>/docs/*.md`
- `plugins/<slug>/CLAUDE.md`
- `plugins/<slug>/AGENTS.md`
- top-level plugin extras such as `SAFETY.md`, `DOCKER.md`, or
`CONTRIBU
Run an always-on Claude Code agent on your own machine, for you or your team. Start and orchestrate sessions from chat in any project it can reach. Take over the same session in the Claude app or the CLI.
Other skills on hermitd.
More skills from other plugins.
browser-use
Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…
agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling…
Questions about docs-drift.
- Which coding agents can use docs-drift?
- docs-drift installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

