check-pr
無料Check an externally created PR for coding rule violations against memory/INDEX.md atoms and docs/architecture/code-review-rules.md.
日本語の概要は準備中です。原文の説明を表示しています。
Refresh drift-prone documentation against current code. Reads docs/architecture/freshness-catalog.yml, diffs against the last sweep's upstream/main anchor, regenerates mechanical entries, processes editorial markers, and opens one PR per sweep with a report file.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
See docs/superpowers/specs/2026-04-25-freshness-sweep-design.md for full design.
| Flag | Behavior |
|---|---|
| (none) | diff mode, batch |
--full | skip anchor resolution; every entry is dirty |
--interactive | stop at each question; default accumulates in report |
--since <ref> | override anchor (debugging) |
--scope <glob> | only mechanical entries whose id matches; editorial unaffected |
REPO_ROOT=$(git rev-parse --show-toplevel) — save for Phase 8 teardown.
git fetch upstream main. Missing remote → error: git remote add upstream https://github.com/nobodies-collective/Humans.git.--since <ref>: previous-anchor = git rev-parse <ref>. Skip 3-5.--full: previous-anchor = none; new anchor = upstream/main HEAD → Phase 2.git log upstream/main --grep='\(upstream@' --extended-regexp --format=%H -n 1 → git log -1 <hash> --format=%B → extract (upstream@<sha>) token. Grep on the anchor token (not "freshness sweep") to avoid false positives from revert commits.none, behave as --full.Per always-use-worktree — a worktree locally, the repo root in a cloud run. $WORKTREE is the sweep's workspace either way; the rest of the skill doesn't care which it is.
Fetch origin/main first, and branch off its fresh HEAD — not a stale local ref. The worktree base is the code the mechanical regens read; if you cut from a stale local main that already lags origin/main, the regens read stale source and the merge-base the PR diffs against is wrong. This bit sweep #819: the branch was cut at 35ce66de8 while origin/main was already at cdd850bde, and the surface report flagged a removed ITicketingBudgetRepository as "new". The fix is to capture the current origin/main as the base, at the start. This is a start-of-run freshness capture, nothing more — once captured the base is frozen (see Scope is frozen here below); fetching fresh now is the point, re-fetching or reconciling later is not.
git fetch origin main
TS=$(date -u +%Y-%m-%dT%H%M%SZ)
if [ "$CLAUDE_CODE_REMOTE" = "true" ]; then # ephemeral single-session container — no worktree
git checkout -b freshness-sweep/$TS origin/main
WORKTREE=$REPO_ROOT
else
git worktree add $REPO_ROOT/.claude/worktrees/freshness-sweep-$TS -b freshness-sweep/$TS origin/main
WORKTREE=$REPO_ROOT/.claude/worktrees/freshness-sweep-$TS # EnterWorktree here; all commands run inside
fi
Scope is frozen here. The diff anchor (upstream/main HEAD) and the worktree base (origin/main HEAD) are captured once, now, at the start of the run, and are immutable for the rest of the sweep. Do NOT re-fetch, re-resolve, or reconcile against origin/main / upstream/main if they move while the sweep runs — a parallel session merging a PR mid-run is expected and irrelevant. The PR diffs against merge-base (the frozen base), so a later fast-forward of origin/main cannot affect this sweep's diff; chasing it only wastes time and is a distraction. Anything that lands after the frozen anchors is the next sweep's input, full stop. (If git merge-base --is-ancestor upstream/main origin/main is false at start — they've crossed, usually right after a prod promotion — note it once in the report and proceed; still never reconcile mid-run.)
Path/branch collision: error; instruct git worktree list / git worktree remove.
docs/architecture/freshness-catalog.yml. Validate: version=1; mechanical, editorial_trees, ignore are lists; every mechanical entry has id, target, triggers[], and either update: script+script or update: prompt+prompt/prompt-file; id and target unique within mechanical. Warn (don't fail) on trigger glob matching no files.editorial_trees: paths ending in / → glob **/*.md; single paths included directly. Filter by ignore globs..md:
<!-- freshness:triggers ...globs... --> (one per doc, before # H1)<!-- freshness:auto id="..." prompt="..." --> … <!-- /freshness:auto --> (closing tag required; id unique per doc; prompt/prompt-file mutually exclusive)<!-- freshness:flag-on-change … reason … --> (multi-line comment)editorial_trees with no markers are "unmarked editorial" candidates.Abort on validation failure → Phase 8.
Runs BEFORE Phase 4 computes the dirty list, so a glob repaired this run also
fires as dirty in this same run — nobodies-collective/Humans#1021. A dead
freshness:triggers entry (a glob or literal path that no longer resolves to
any file) is silent by construction: it makes its doc look clean
instead of unchecked, so the doc drops out of the dirty list before Phase 4
ever runs and nobody notices. Two sweeps (2026-08-08, 2026-08-10) found large
batches of these ad hoc, with a throwaway verifier, after the dirty list had
already been computed from the broken globs — this phase exists so the sweep
catches and repairs its own dead triggers as a matter of course, not as
someone remembering to go look.
bash docs/scripts/freshness-checks/verify-triggers.sh
This walks every .md under the catalog's editorial_trees (honoring
ignore:), expands every freshness:triggers entry as a real glob
(**/*-aware — never a literal test -e per line, which under-reports:
the 2026-08-08 sweep's throwaway verifier compared globs literally and
missed the last 5 of 64 dead paths, caught only in PR review) as well as
every literal path, and for each dead one:
find hit by basename, which is also how a section-project move
resolves (a section's uniquely-named file or directory has exactly one
hit under its new src/Sections/Humans.<Section>/** home, no
section-specific logic needed). Emits REPAIRED <doc> | <old> -> <new>.find hits — never guessed). Emits
UNRESOLVED <doc> | <old> and FORCE-DIRTY <doc>.REPAIRED line — those
are real content changes and ride in the sweep's own PR like any other
regen (memory/process/freshness-sweep-owns-its-verifier.md). Nothing
further to do for them.UNRESOLVED list and the FORCE-DIRTY doc list forward:
FORCE-DIRTY docs into the dirty list,
regardless of whether anything in the diff window matches them — an
unresolved dead trigger means the doc needs a human-legible review this
run, not silent skipping.--full/fallback: every candidate dirty.git diff --name-only <previous-anchor>..upstream/main → glob-match against each entry's triggers.--scope <glob>: filter to mechanical entries whose id matches.FORCE-DIRTY set (editorial docs with an unresolved dead trigger) — always dirty this run regardless of diff match.| Entry type | Slot | Action |
|---|---|---|
Mechanical update: script | none | Run via Bash; warn if files touched outside target |
Mechanical update: prompt | 1 | Dispatch subagent |
Editorial freshness:auto | 1 | Dispatch subagent; regenerate each block per inline prompt; leave content outside markers untouched |
Editorial freshness:flag-on-change | 1 | Dispatch a drift-fix subagent (see below) — MANDATORY every sweep, not optional. Read the doc against the specific changed files its triggers matched; fix every concrete factual contradiction in place; escalate only genuine judgment calls. A passive "flagged for review" list is a process failure. |
| Unmarked editorial | none | No triggers → reviewing against all of src/** is noise. Add to flag list ("Unmarked editorial; add freshness:triggers: <files>") so a future sweep can scope it; do not full-review. |
Editorial drift-fix is the core of the sweep — DO IT, don't punt it. docs/sections/, src/Sections/*/Docs/, docs/features/global/, and docs/guide/ are Claude-authored; the sweep owns keeping them true. Emitting a "flagged for human review" list of triggered docs instead of fixing them is the single most common way this skill has failed in practice. The default is fix, not flag.
Procedure — for each triggered freshness:flag-on-change doc, dispatch a tightly-scoped subagent (≤3 concurrent; cluster docs that share the same changed files into one subagent) with:
src/);cd <worktree> first (its own Bash call), then per changed file view git diff <prev-anchor> HEAD -- <file> AND read the current source, then fix in place every place the doc's prose is factually contradicted (renamed/removed/added symbol, route, field, enum, behavior, auth rule, default), preserving voice/structure/freshness-markers, surgical edits only;<90% sure it's real drift → don't edit, ask.Guide docs are end-user facing: fix only user-visible behavior drift, not internal-implementation wording. Reserve a flag (no fix) strictly for subjective "does this still read right" prose that no code fact contradicts.
Subagent prompt: worktree path, target file, trigger paths fired, entry's prompt content. Must NOT commit. Return JSON:
{
"id": "<entry id>",
"updated": true,
"files_changed": ["<paths>"],
"summary": "<one-line; required when updated>",
"flags": [{ "file": "<path>", "reason": "<why>", "suggested_follow_up": "<optional>" }],
"questions": ["<text>"]
}
After each batch accumulate results. --interactive: stop on non-empty questions, ask Peter, continue.
Goal: every sweep shrinks the historical-doc pile by ~5% (soft target, ~7% soft reviewability budget — see Orchestration for how the budget interacts with fully-mined husks) without losing durable signal. Whole-file deletion is the LAST step, never the first. The earliest sweep that tried to delete first lost ADR rationale, vendor-selection trade-offs, and decorator-integrity gotchas — those have to be extracted into living docs before the husk is removed.
AskUserQuestion tool per project rule). Do not queue it in a "Proposed for review" list for a future pass. Queuing an uncertain item for later is the anti-pattern this step exists to kill — the whole point of the sweep is to resolve, not to generate a human to-do backlog.docs/sections/*.md — section invariants only, no rationale narrative (per SECTION-TEMPLATE.md)docs/architecture/design-rules.md — architecture-level decisions that extend the constitutiondocs/architecture/conventions.md — pattern definitions (when to use X, naming, etc.)memory/ atoms during a sweep. memory/ is for atomic task-fires rules, not for narrative-history-of-decisions, and design docs carry weight that needs Peter's review. If verified-true wheat genuinely fits none of the three allowed destinations, ASK Peter inline where it should live (don't invent a destination, and don't silently drop durable signal). Asking is fine; queuing for "next pass" is not.<!-- wheat: <source path> §<section> --> provenance comment. Preserve original prose voice..md files. For each ref:
docs/superpowers/**, other historical docs): rewrite as (historical) — current invariants live in <destination>. The archive remains historical; the link points forward.| Source tree | Action |
|---|---|
docs/plans/** older than 30 days (files and dated subfolders) | Wheat-extract → migrate → retarget refs → delete |
docs/superpowers/plans/** older than 30 days | Same |
docs/superpowers/specs/** older than 60 days | Same |
docs/architecture/tech-debt-*.md where all items are [DONE] | Same (wheat may be [DONE] summaries worth keeping in maintenance-log) |
| Orphan refs in living docs to already-deleted files | Edit out or retarget |
Age is measured by the YYYY-MM-DD prefix in the filename — NOT the last-commit date or mtime. A husk's topic date is when its work happened; that's its true age. Last-commit date is the wrong signal: a doc sweep, a link retarget, or any minor edit touches a husk without making it less legacy, and gating on last-commit would let those incidental edits silently reset the clock and keep a husk alive forever. The section docs (docs/sections/*.md) are the canonical, living record — the repo; these plans/specs are contextual legacy that must age out on schedule regardless of how recently something brushed against them. So docs/plans/2026-05-14-foo.md is "older than 30 days" once the calendar is past 2026-06-13, full stop — even if its last commit was yesterday's freshness sweep. A dated subfolder (docs/plans/2026-08-03-g0-first-audit/) ages as one unit by its own prefix and is pruned whole. (Files lacking a date prefix: fall back to mtime, and flag them in the report as candidates to rename with a date prefix.)
docs/docs/architecture/freshness-catalog.ymldocs/sections/, src/Sections/*/Docs/, docs/features/global/, docs/guide/ as deletion targets (these are migration destinations, never sources)docs/architecture/{design-rules,code-review-rules,coding-rules,conventions}.md as deletion targets (same — these are destinations)docs/freshness/last-report.mdfreshness:auto block in code-analysis.md (Phase 5 owns it)shopt -s globstar # REQUIRED — without this, ** doesn't recurse and total_lines is wildly undercounted
total_doc_lines=$(find docs -name '*.md' -print0 | xargs -0 wc -l | tail -1 | awk '{print $1}')
target_lines=$((total_doc_lines * 5 / 100))
hard_cap=$((total_doc_lines * 7 / 100))
Use find (above) rather than relying on shell globbing — it's safe whether globstar is set or not.
Dispatch up to 3 subagents in parallel (one per logical source group: e.g., shifts-related, auth-related, infra-related). Each agent:
Orchestrator reviews each manifest, applies migrations as Edit calls, retargets inbound refs, then deletes husks. The 7% figure is a soft reviewability budget (keep one PR's deletions skimmable), not a correctness limit. Apply it like this:
applied_lines + this_doc_lines > hard_cap.{
"batch": "<logical group name>",
"migrations": [
{
"source_doc": "<path being mined>",
"target_doc": "<destination living doc>",
"insertion_anchor": "<exact existing line in target>",
"text_to_insert": "<markdown block including <!-- wheat: ... --> comment>",
"lines_inserted": <int>,
"wheat_summary": "<one-line: what survived and why it's durable>"
}
],
"drop_entirely": [
{ "source_doc": "<path>", "reason": "<all chaff: data-model now in code, task lists, etc.>" }
],
"inbound_refs": [
{ "source_doc": "<path>", "ref_from": "<path>", "ref_line": <int>, "proposed_action": "retarget to <dest>" | "rewrite as historical" | "remove" }
],
"questions": []
}
The sweep report's "Pruned" section lists:
<source> → <target> + the one-line wheat summaryA prune-analysis subagent's manifest may surface medium-confidence wheat (the agent isn't sure it's still durable). The orchestrator does not pass that uncertainty through to a "Proposed for review" backlog — it resolves it per step 3a: verify against code, then migrate (if true), drop (if dead), or ask Peter inline (if genuinely a judgment call). The report's "Proposed for review" section should normally read "None — all candidates resolved this sweep"; it carries content only when Peter was asked a question this sweep and the answer is pending.
Overwrite docs/freshness/last-report.md: timestamp header; anchor/mode/counts summary; "Updated automatically" bullets (id — summary); "Dead trigger globs" section from Phase 3.5 — a Repaired sub-list (doc — old → new, one per REPAIRED line) and an Unresolved sub-list (doc — old, one per UNRESOLVED line, each noting it was force-included in this run's dirty list); "Pruned" section (file, lines removed, evidence) from Phase 5.5, including a "Wheat migrated" sub-list (source §section → destination, with the code symbol that verified it); "Flagged for human review" (file, triggers, reason — subjective prose only, never concrete broken facts, which are fixed inline); "Proposed for review" ("None — all candidates resolved this sweep" unless a question to Peter is pending); "Questions" (anything you asked Peter inline this sweep); "Skipped (errors)". Previous-anchor = none on first run or --full. No files changed → "Nothing to update." → Phase 8. Otherwise stage all changes + report.
Unresolved dead triggers are a record, not a delivery — like every other item needing Peter's judgment they also go through Phase 7.5 inline, phrased as a one-line decision each (e.g. "1. Auth.md's Authorization/Requirements/** trigger is dead — Requirement classes now live per-section under each Authorization/; retarget to src/Sections/*/Authorization/**Requirement.cs, or drop the trigger?").
The report is the durable RECORD, not the delivery channel. Every item that needs Peter's judgment — flagged drift that is a genuine judgment call, open questions, uncertain prune wheat — is delivered to him inline in Phase 7.5, not parked in the report for him to find later. Assume he never opens the report. Writing a review item only into the report and ending the run is a process failure.
Do not reconcile a moved base. The base was frozen in Phase 2 and stays frozen. Do NOT re-fetch or merge origin/main, even if it fast-forwarded while the sweep ran — the PR diffs against merge-base (the frozen base), so a moved origin/main is invisible to this sweep's diff and to the merge-base-scored surface report. Commit and PR directly against the frozen base. Anything that landed after it is the next sweep's input; investigating it now is a distraction, not diligence.
Commit title MUST be docs: freshness sweep — N entries (upstream@<new-anchor-sha>). The (upstream@<sha>) token is parsed by the next sweep to locate the prior anchor.
git commit -m "$(cat <<'EOF'
docs: freshness sweep — N entries (upstream@<sha>)
Updated:
- <entry-id>
Flagged for review (see docs/freshness/last-report.md):
- <file>
Mode: diff
Previous anchor: <sha-or-none>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
)"
Closing EOF must be at column 0.
git push -u origin freshness-sweep/$TS
gh pr create --repo peterdrier/Humans --base main \
--title "docs: freshness sweep — N entries (upstream@<sha>)" \
--body "$(cat <<'EOF'
## Summary
<bullets from report>
## Report
See `docs/freshness/last-report.md` (committed in this PR).
## Test plan
- [ ] Skim diff, read report, verify flagged items, merge if happy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
Print the PR URL.
After the PR is open and before teardown, present every item that needs Peter's judgment INLINE in the chat — as a terse, numbered, actionable list, one line each: every "Flagged for human review" judgment call, every open "Question", every uncertain prune-wheat item. This is the delivery of the review; the report is only the record. Peter reviews here, now, inline — he does not read the report, so a sweep that ends with unresolved items sitting in the report has failed.
AskUserQuestion tool (project rule). Don't pad with paragraph-long options.git add the touched files and make a new git commit (the Phase 7 commit already happened — uncommitted working-tree edits will not push), update the report's Flagged / Questions / Proposed sections to record each resolution, and git push to update the PR. A bare git push without that follow-up commit sends nothing.If there are genuinely zero judgment calls (everything was a concrete fix already applied, nothing subjective), say so in one line and proceed — don't manufacture questions.
Only after Phase 7.5 is resolved. cd $REPO_ROOT && git worktree remove $WORKTREE (add --force if Phase 7 errored). Never rm -rf. Branch stays on origin until PR closes. Nothing to tear down in a cloud run — there is no worktree, and the container is reclaimed anyway.
| Failure | Behavior |
|---|---|
No upstream remote | Error in Phase 1 |
| Catalog YAML parse error | Error in Phase 3 → Phase 8 |
| Marker validation error | That doc → "Skipped (errors)"; others continue |
| Subagent fails | That entry skipped; recorded in "Skipped (errors)" |
| Duplicate target in catalog | Schema validation rejects at parse time |
| Mechanical trigger glob matches nothing | Warning only (Phase 3) |
| Editorial trigger glob/literal matches nothing | Repaired or force-dirtied by Phase 3.5, never silently skipped |
| Push / PR creation fails | Worktree retained; fix manually |
Freshness sweep (diff) (or (full)) row in docs/architecture/maintenance-log.md — Last Run = today, Next Due = today + cadence, plus a one-line Notes entry — in the sweep's own commit, per maintenance-log-update. Everything else in that file stays hand-maintained; touch only the sweep's row.design-rules.md, code-review-rules.md, section invariants, feature specs). It only deletes shipped/historical plans and specs with cited evidence.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Check an externally created PR for coding rule violations against memory/INDEX.md atoms and docs/architecture/code-review-rules.md.
日本語の概要は準備中です。原文の説明を表示しています。
Two-phase memory hygiene. Phase 1: scan external Claude Code memory (~/.claude/projects/<slug>/memory/) for durable rules to migrate into the repo and entries already duplicated by repo atoms. Phase 2: audit in-repo memory/, CLAUDE.md, docs/architecture/, and docs/sections/ for dead links, duplication, drift, and bloat.
日本語の概要は準備中です。原文の説明を表示しています。
Review, repair and steward the nightly Codex debt-sweep PR (branch codex/daily-debt/<date>). Judges every commit GOOD / REPAIR / REVERT, triages the bot review findings through /fix, lands one round-1 commit, files follow-up issues, then stewards the PR itself with a 3-round ceiling. Run by the 08:00 UTC cloud routine; also '/debt-review', '/debt-review 1789'.
日本語の概要は準備中です。原文の説明を表示しています。
Autonomous themed tech-debt cleanup. Reads docs/architecture/debt-ledger.yml, rotates to the least-recently-served debt theme, works it for a time budget (default 2h) or until drained, opens one PR, and asks judgment questions inline at the end. Use for daily debt burndown without Peter pointing at a target: grandfathered analyzer rules, architecture-test baselines, obsolete-field reads, cross-section stitching.
日本語の概要は準備中です。原文の説明を表示しています。
Scrap and regenerate the in-flight EF migrations on the current branch as one consolidated migration. Use when migrations have accumulated mid-development cruft (added/removed columns, stacked add-column-to-existing-table fixes, hand-edited SQL that needs to come out, schema changes that should have been one migration but ended up as five), or when the branch has merged main and its migrations are now stuck mid-chain so `dotnet ef migrations remove` is unsafe. Triggers on phrases like 'regen the migrations', 'redo these migrations', 'scrap and regen migrations', 'consolidate the in-flight migrations', 'redo the migration stack', or any time an agent hits the mid-chain situation in `memory/architecture/migration-regen-after-rebase.md`.
日本語の概要は準備中です。原文の説明を表示しています。
Use when a sprint tracking issue (label `sprint`) on peterdrier/Humans needs working — routine-fired cloud runs, or any unattended session told to execute the sprint queue.
日本語の概要は準備中です。原文の説明を表示しています。