Guardian
Check ADR health, drift, stale decisions, and lint. Use for ADR guardian, health sweep, stale ADRs, or an [adr-guardian] DUE notice.From its SKILL.md
npx -y skills add rvdbreemen/adr-kit --skill guardianAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
10.0 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it
adr-kit guardian
Use $ARGUMENTS as cheap, llm, or all; default to the due tier when it
is empty. Never start paid or cloud judgment without explicit permission.
You are running the ADR-set health sweep. Your job is to run whichever tier(s) are due (or were requested), surface findings using the mix-by-finding-type responses below, and stamp the state file when done.
Before you start
Resolve the plugin bin path (same resolver used in /adr-kit:judge and /adr-kit:init):
ADR_KIT=$(ls -d ~/.claude/plugins/cache/rvdbreemen-adr-kit/adr-kit/*/ 2>/dev/null | sort -V | tail -1)
If ADR_KIT is empty (plugin not installed), fall back to a local checkout:
# try local checkout
ADR_KIT=$(git rev-parse --show-toplevel 2>/dev/null)/
Verify the guardian bin exists:
ls "$ADR_KIT/bin/adr-guardian" 2>/dev/null || echo "guardian not found"
Step 1 — Determine which tier(s) to run
If invoked with an explicit argument (cheap, llm, or all), honour it.
Otherwise, read the current state to determine due tiers:
"$ADR_KIT/bin/adr-guardian" state
Compute which tier is due based on cheap_tier.last_run vs guardian.drift_stale_days and llm_tier.last_run vs guardian.llm_stale_days (defaults: 1d cheap, 14d LLM). If neither is due, report "Both tiers are current — nothing to sweep" and stop.
Read docs/adr/.adr-kit.json if it exists to get any custom guardian.* config.
Step 2 — Cheap tier (drift + stale + lint)
Run only when cheap tier is due or explicitly requested.
2a. Drift check (declarative, adr-judge)
git diff HEAD~5 HEAD --unified=0 | "$ADR_KIT/bin/adr-judge" \
--diff - \
--adr-dir docs/adr/ \
--repo-root "$(git rev-parse --show-toplevel)" \
--snapshot worktree \
--json > /tmp/guardian-drift.json 2>&1
DRIFT_EXIT=$?
Read /tmp/guardian-drift.json. Count violations and advisories.
Response (mix-by-finding-type: Drift): Surface prominently. List each violation with file:line + ADR id. Offer to (a) fix the code, (b) write a new ADR covering the new pattern, or (c) supersede the violated ADR. Highest-priority finding type.
2b. Stale ADR detection (adr-retire)
"$ADR_KIT/bin/adr-retire" \
docs/adr/ \
--format json > /tmp/guardian-retire.json 2>&1
Read /tmp/guardian-retire.json. Collect the candidate set: extract the list of ADR ids flagged for retirement (candidates).
Change-based filtering: Read retire_seen from the state file (adr-guardian state). Compare the fresh candidate set against retire_seen. Only surface candidates that are new (present in fresh set but not in retire_seen). This avoids daily nagging about the same stale ADRs. If all candidates are already in retire_seen, skip the retire response silently for this sweep.
Response (mix-by-finding-type: Stale ADR): For each new retire candidate, draft a retirement/supersession skeleton for human review — never auto-apply. Show:
- The ADR id and title.
- The retirement signal (tech removed / superseded target missing / policy drift / age threshold).
- A draft Status flip:
Deprecated, <today>orSuperseded by ADR-NNN, <today>(if a superseding ADR exists). - Ask the user to confirm or skip each.
2c. Health lint (adr-lint / adr-status)
"$ADR_KIT/bin/adr-lint" docs/adr/ 2>&1 | tail -20
"$ADR_KIT/bin/adr-status" --adr-dir docs/adr/ 2>&1 | tail -5
Response (mix-by-finding-type: Health): Emit a PASS/ADVISORY/FAIL summary. For FAILs: list the gate name and ADR, offer to fix via /adr-kit:adr (re-run the adr-generator subagent on that ADR).
Also read the Enforcement coverage percent for the trend history:
"$ADR_KIT/bin/adr-status" --adr-dir docs/adr/ --format json > /tmp/guardian-status.json 2>&1
Extract summary.coverage_pct from /tmp/guardian-status.json. You will pass it
to the stamp call below so the trend log records coverage per sweep.
2d. Stamp cheap tier
After completing 2a–2c, record the sweep. The --retire-seen argument must contain
the full fresh candidate set (all ids, not just the new ones). The detector uses
the stored set for the next session's change comparison. --coverage records the
Enforcement coverage percent (from 2c) in the append-only trend log.
"$ADR_KIT/bin/adr-guardian" stamp cheap \
--violations <N_drift_violations> \
--retire <N_retire_candidates> \
--lint "<F>F/<A>A" \
--coverage <coverage_pct_from_adr_status> \
--retire-seen '<json_array_of_ALL_retire_candidate_ids>'
Step 3 — LLM tier (suggest + audit) — ALWAYS confirm cost first
MANDATORY cost confirmation gate. Before running this tier, read docs/adr/.adr-kit.json:
-
If
guardian.llm_autorunisfalse(default), print:[adr-guardian] LLM tier: adr-suggest + full audit will invoke claude-sonnet-4-6. Estimated cost: ~$0.10–0.30. Run now? (y/N)And wait for an explicit
y/yes. If the user says no (or presses Enter on the default), skip the LLM tier and stop at Step 4. -
If
guardian.llm_autorunistrue, proceed without asking (user opted in explicitly in config).
Run only when llm tier is due or explicitly requested (and user has confirmed cost).
3a. Missing-ADR detection (adr-suggest)
git diff HEAD~10 HEAD --unified=0 | "$ADR_KIT/bin/adr-suggest" \
--diff - \
--adr-dir docs/adr/ \
--json > /tmp/guardian-suggest.json 2>&1
Read /tmp/guardian-suggest.json.
Response (mix-by-finding-type: Missing ADR): Passive. List candidates where needs_adr=true with confidence >= medium. Offer to author selected ones via the adr-generator subagent. User picks; never auto-create.
3b. Full audit (adr-judge with LLM pass)
git diff HEAD~10 HEAD --unified=0 | "$ADR_KIT/bin/adr-judge" \
--diff - \
--adr-dir docs/adr/ \
--repo-root "$(git rev-parse --show-toplevel)" \
--snapshot worktree \
--llm \
--json > /tmp/guardian-audit.json 2>&1
Read /tmp/guardian-audit.json. Same response as Step 2a drift, but covering semantic violations not expressible as regex.
3c. Stamp LLM tier
If the cheap tier did not run in this sweep, read summary.coverage_pct from
"$ADR_KIT/bin/adr-status" --adr-dir docs/adr/ --format json and pass it via
--coverage (when omitted, the trend entry carries the last known coverage).
"$ADR_KIT/bin/adr-guardian" stamp llm \
--suggest <N_suggest_hits> \
--audit <N_audit_findings> \
--coverage <coverage_pct_from_adr_status>
Step 4 — Wrap-up
Refresh the disposable Proposed decision queue after the deterministic sweep, outside SessionStart:
"$ADR_KIT/bin/adr-guardian" refresh-readiness \
--project-root "$(git rev-parse --show-toplevel)" --diff
Then report at most the first three cached actions. The queue ranks active
implementation links, shipped-but-Proposed records, ready-for-confirmation
records, open human questions, age, and lowest quality in that order. Each
action must use /adr-kit:grill ADR-NNN. The cache is derived, expiring,
gitignored, safe to delete, and never authoritative for acceptance.
Print a summary:
[adr-guardian] sweep complete
cheap tier: <X> drift violations · <R> retire candidates · <lint_summary>
llm tier: <S> missing-ADR suggestions · <A> audit findings (or: skipped)
→ use /adr-kit:adr to author new ADRs, /adr-kit:judge for detailed resolution
Constraints
- Never auto-apply ADR edits. All stale/retire changes are drafts for human review.
- Never auto-create ADRs. Missing-ADR suggestions are presented; user picks.
- Never skip the cost-confirm gate when
llm_autorun: false. - Always stamp after each tier completes so the next session's cooldown is correct.
- Model can self-call. This skill is NOT
disable-model-invocation. When the session model sees an[adr-guardian] ... DUEblock injected at SessionStart, it should proactively offer to run the due tier via/adr-kit:guardian.
Team mode
The guardian has two complementary triggers; use both on team projects:
- SessionStart nudge (per developer). The local hook plus this skill gives each developer a freshness signal on their own machine. The state file (
docs/adr/.adr-kit-state.json) is gitignored, per-machine, advisory data: atomic writes keep it safe across parallel Claude Code sessions, and last-writer-wins is the accepted semantics. - CI-cron sweep (shared team visibility). A weekly GitHub Actions workflow (
.github/workflows/adr-guardian-audit.yml; downstream copy-paste variant intemplates/github-workflows/adr-guardian-audit.yml) runs the cheap tier only (lint + retire + status) and maintains a single "ADR guardian audit" tracking issue. Report-only: it never fails the build, never runs an LLM (ADR-001 posture), and needs no secrets beyondGITHUB_TOKEN.
Both can coexist: the CI sweep does not read or write the local state file, and the local nudge cadence is unaffected by CI runs. The LLM tier remains local and opt-in only.
SessionStart block handling (for in-session model)
When the in-session model reads an additionalContext block starting with [adr-guardian]:
When at least two sweeps have been stamped, the block also carries a one-line
delta vs the previous sweep, e.g. trend: drift 2 -> 0, retire 1 -> 2, coverage 40% -> 45%. Use it to call out improving or degrading KPIs when
offering the sweep.
- Check which tier(s) are marked
DUE. - For the cheap tier: offer immediately: "ADR drift/health check is due — run
/adr-kit:guardian cheapto sweep (free, ~30s)?" - For the llm tier: offer: "ADR semantic check is due (bi-weekly) — run
/adr-kit:guardian llm? This will confirm cost (~$0.10–0.30) before spending." - If the user accepts either, invoke this skill with the appropriate argument.
- Apply the mix-by-finding-type responses as documented above.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.