@erclx/canon 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/claude/.claude-plugin/plugin.json +19 -0
- package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
- package/claude/skills/bash-cli-script/SKILL.md +48 -0
- package/claude/skills/bash-cli-script/references/template.md +43 -0
- package/claude/skills/bash-script/REQUIREMENT.md +36 -0
- package/claude/skills/bash-script/SKILL.md +100 -0
- package/claude/skills/bash-script/references/patterns.md +349 -0
- package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
- package/claude/skills/canon-cli/SKILL.md +103 -0
- package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-file/SKILL.md +80 -0
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
- package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
- package/claude/skills/canon-operator/SKILL.md +108 -0
- package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
- package/claude/skills/canon-rollout/SKILL.md +147 -0
- package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
- package/claude/skills/canon-screencast/SKILL.md +167 -0
- package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
- package/claude/skills/canon-slides-draft/SKILL.md +62 -0
- package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
- package/claude/skills/ci-workflow/SKILL.md +65 -0
- package/claude/skills/ci-workflow/references/workflows.md +98 -0
- package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
- package/claude/skills/claude-address-review/SKILL.md +212 -0
- package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
- package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
- package/claude/skills/claude-autoship/SKILL.md +207 -0
- package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
- package/claude/skills/claude-design-extract/SKILL.md +102 -0
- package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
- package/claude/skills/claude-diagram/SKILL.md +177 -0
- package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
- package/claude/skills/claude-docs/SKILL.md +287 -0
- package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
- package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
- package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
- package/claude/skills/claude-feature/SKILL.md +115 -0
- package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
- package/claude/skills/claude-groundwork/SKILL.md +142 -0
- package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
- package/claude/skills/claude-intake/SKILL.md +114 -0
- package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
- package/claude/skills/claude-intake-answer/SKILL.md +90 -0
- package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
- package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
- package/claude/skills/claude-markdown-propose/references/format.md +107 -0
- package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-capture/SKILL.md +101 -0
- package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-review/SKILL.md +210 -0
- package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
- package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
- package/claude/skills/claude-orchestrate/SKILL.md +241 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
- package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
- package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
- package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
- package/claude/skills/claude-pr-review/SKILL.md +295 -0
- package/claude/skills/claude-review/REQUIREMENT.md +39 -0
- package/claude/skills/claude-review/SKILL.md +142 -0
- package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
- package/claude/skills/claude-seed-sync/SKILL.md +156 -0
- package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
- package/claude/skills/claude-standards-audit/SKILL.md +99 -0
- package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
- package/claude/skills/claude-tasks/SKILL.md +161 -0
- package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
- package/claude/skills/claude-teach/SKILL.md +196 -0
- package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
- package/claude/skills/claude-teach/references/pedagogy.md +67 -0
- package/claude/skills/claude-teach/references/promotion.md +54 -0
- package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ui-test/SKILL.md +77 -0
- package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ux-audit/SKILL.md +79 -0
- package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
- package/claude/skills/claude-ux-measure/SKILL.md +122 -0
- package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
- package/claude/skills/claude-worker/SKILL.md +96 -0
- package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
- package/claude/skills/claude-worktree/SKILL.md +136 -0
- package/claude/skills/create-rule/REQUIREMENT.md +45 -0
- package/claude/skills/create-rule/SKILL.md +68 -0
- package/claude/skills/create-skill/REQUIREMENT.md +38 -0
- package/claude/skills/create-skill/SKILL.md +32 -0
- package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
- package/claude/skills/create-snippet/SKILL.md +30 -0
- package/claude/skills/create-standard/REQUIREMENT.md +35 -0
- package/claude/skills/create-standard/SKILL.md +29 -0
- package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
- package/claude/skills/decision-escalate/SKILL.md +79 -0
- package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
- package/claude/skills/docs-sync/SKILL.md +95 -0
- package/claude/skills/git-branch/REQUIREMENT.md +38 -0
- package/claude/skills/git-branch/SKILL.md +60 -0
- package/claude/skills/git-commit/REQUIREMENT.md +36 -0
- package/claude/skills/git-commit/SKILL.md +49 -0
- package/claude/skills/git-followup/REQUIREMENT.md +43 -0
- package/claude/skills/git-followup/SKILL.md +48 -0
- package/claude/skills/git-issue/REQUIREMENT.md +38 -0
- package/claude/skills/git-issue/SKILL.md +65 -0
- package/claude/skills/git-pr/REQUIREMENT.md +50 -0
- package/claude/skills/git-pr/SKILL.md +164 -0
- package/claude/skills/git-pr/references/labels.md +95 -0
- package/claude/skills/git-ship/REQUIREMENT.md +42 -0
- package/claude/skills/git-ship/SKILL.md +55 -0
- package/claude/skills/git-split/REQUIREMENT.md +39 -0
- package/claude/skills/git-split/SKILL.md +162 -0
- package/claude/skills/git-stage/REQUIREMENT.md +39 -0
- package/claude/skills/git-stage/SKILL.md +73 -0
- package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
- package/claude/skills/git-worktree/SKILL.md +130 -0
- package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
- package/claude/skills/migration-claude-md/SKILL.md +76 -0
- package/claude/skills/migration-context/REQUIREMENT.md +36 -0
- package/claude/skills/migration-context/SKILL.md +95 -0
- package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
- package/claude/skills/migration-standards-drop/SKILL.md +113 -0
- package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
- package/claude/skills/migration-superseded/SKILL.md +115 -0
- package/claude/skills/project-commands/REQUIREMENT.md +42 -0
- package/claude/skills/project-commands/SKILL.md +85 -0
- package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
- package/claude/skills/restate-plainly/SKILL.md +39 -0
- package/claude/skills/session-map/REQUIREMENT.md +57 -0
- package/claude/skills/session-map/SKILL.md +70 -0
- package/claude/skills/session-resume/REQUIREMENT.md +49 -0
- package/claude/skills/session-resume/SKILL.md +51 -0
- package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
- package/claude/skills/setup-gov/SKILL.md +77 -0
- package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
- package/claude/skills/setup-indexes/SKILL.md +153 -0
- package/claude/skills/setup-init/REQUIREMENT.md +45 -0
- package/claude/skills/setup-init/SKILL.md +127 -0
- package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
- package/claude/skills/setup-plugins/SKILL.md +81 -0
- package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
- package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
- package/claude/skills/setup-verify/SKILL.md +51 -0
- package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
- package/claude/skills/systematic-debugging/SKILL.md +70 -0
- package/claude/skills/write-human/REQUIREMENT.md +46 -0
- package/claude/skills/write-human/SKILL.md +68 -0
- package/claude/skills/write-human/references/density.md +38 -0
- package/claude/skills/write-human/references/machine-tells.md +107 -0
- package/claude/skills/write-human/references/source-material.md +37 -0
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
- package/claude/skills/youtube-transcripts/SKILL.md +34 -0
- package/docs/agents/audits.md +98 -0
- package/docs/agents/capture.md +37 -0
- package/docs/agents/census.md +23 -0
- package/docs/agents/commands.md +146 -0
- package/docs/agents/comments.md +34 -0
- package/docs/agents/context-audit-checks.md +120 -0
- package/docs/agents/context-audit.md +83 -0
- package/docs/agents/counts.md +76 -0
- package/docs/agents/demo.md +86 -0
- package/docs/agents/docs.md +17 -0
- package/docs/agents/gate.md +84 -0
- package/docs/agents/index.md +47 -0
- package/docs/agents/indexes.md +35 -0
- package/docs/agents/install-and-sync.md +385 -0
- package/docs/agents/intake.md +81 -0
- package/docs/agents/key-changes.md +103 -0
- package/docs/agents/label-coverage.md +73 -0
- package/docs/agents/markdown-audit.md +197 -0
- package/docs/agents/output-shape.md +70 -0
- package/docs/agents/overview.md +26 -0
- package/docs/agents/records.md +170 -0
- package/docs/agents/restated.md +81 -0
- package/docs/agents/review-classification.md +77 -0
- package/docs/agents/routing.md +61 -0
- package/docs/agents/rule-citations.md +98 -0
- package/docs/agents/sandbox.md +71 -0
- package/docs/agents/scripting.md +149 -0
- package/docs/agents/sessions.md +120 -0
- package/docs/agents/skills-audit.md +94 -0
- package/docs/agents/skills-reach.md +64 -0
- package/docs/agents/standards-audit.md +38 -0
- package/docs/agents/state-scoped-risk.md +105 -0
- package/docs/agents/superseded.md +85 -0
- package/docs/agents/targets.md +83 -0
- package/docs/agents/tasks.md +200 -0
- package/docs/agents/teach.md +158 -0
- package/docs/agents/test-order.md +56 -0
- package/docs/agents/worktrees.md +62 -0
- package/docs/ai-workflow.md +317 -0
- package/docs/index.md +23 -0
- package/docs/operating-model.md +223 -0
- package/docs/target-projects.md +258 -0
- package/docs/visual-design-workflow.md +151 -0
- package/docs/zshrc-aliases.md +65 -0
- package/governance/rules/ci/700-ci-workflow.md +44 -0
- package/governance/rules/claude/500-prose.md +15 -0
- package/governance/rules/claude/501-markdown.md +14 -0
- package/governance/rules/claude/510-context.md +28 -0
- package/governance/rules/claude/511-indexes.md +14 -0
- package/governance/rules/claude/520-wireframes.md +12 -0
- package/governance/rules/claude/530-requirements.md +11 -0
- package/governance/rules/claude/540-architecture.md +11 -0
- package/governance/rules/claude/550-design.md +11 -0
- package/governance/rules/claude/555-tasks.md +12 -0
- package/governance/rules/claude/556-groundwork.md +11 -0
- package/governance/rules/claude/557-intake.md +11 -0
- package/governance/rules/claude/558-plan.md +22 -0
- package/governance/rules/claude/559-memory.md +11 -0
- package/governance/rules/claude/560-diagrams.md +18 -0
- package/governance/rules/claude/561-teach.md +13 -0
- package/governance/rules/claude/562-session.md +15 -0
- package/governance/rules/claude/570-skill.md +24 -0
- package/governance/rules/claude/575-hooks.md +17 -0
- package/governance/rules/claude/576-settings.md +14 -0
- package/governance/rules/claude/580-readme.md +11 -0
- package/governance/rules/claude/590-rule-authoring.md +12 -0
- package/governance/rules/claude/591-standard-authoring.md +12 -0
- package/governance/rules/claude/592-claude-md.md +19 -0
- package/governance/rules/core/000-constitution.md +30 -0
- package/governance/rules/core/005-behavior.md +27 -0
- package/governance/rules/core/010-testing.md +35 -0
- package/governance/rules/core/015-output.md +20 -0
- package/governance/rules/core/020-concurrency.md +22 -0
- package/governance/rules/core/025-indexes.md +9 -0
- package/governance/rules/core/030-error-handling.md +31 -0
- package/governance/rules/core/035-tasks.md +13 -0
- package/governance/rules/core/040-performance.md +20 -0
- package/governance/rules/core/045-memory.md +12 -0
- package/governance/rules/core/050-logging.md +20 -0
- package/governance/rules/core/055-scratch.md +9 -0
- package/governance/rules/core/060-naming.md +19 -0
- package/governance/rules/core/065-spelling.md +19 -0
- package/governance/rules/core/070-planning.md +18 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/core/080-config-comments.md +22 -0
- package/governance/rules/core/085-worktrees.md +17 -0
- package/governance/rules/core/087-git.md +11 -0
- package/governance/rules/core/090-code-comments.md +39 -0
- package/governance/rules/framework/200-react.md +51 -0
- package/governance/rules/framework/210-astro.md +41 -0
- package/governance/rules/framework/220-fastapi.md +43 -0
- package/governance/rules/framework/230-nextjs.md +48 -0
- package/governance/rules/framework/250-tailwind.md +32 -0
- package/governance/rules/framework/260-shadcn.md +34 -0
- package/governance/rules/lang/100-typescript.md +40 -0
- package/governance/rules/lang/110-python.md +42 -0
- package/governance/rules/lang/120-bash.md +19 -0
- package/governance/rules/lib/300-testing-ts.md +39 -0
- package/governance/rules/lib/305-e2e-reliability.md +34 -0
- package/governance/rules/lib/306-test-scope.md +25 -0
- package/governance/rules/lib/310-zod.md +25 -0
- package/governance/rules/lib/320-tanstack-query.md +32 -0
- package/governance/rules/lib/330-testing-py.md +44 -0
- package/governance/rules/lib/340-pydantic.md +38 -0
- package/governance/rules/lib/350-security-web.md +32 -0
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/rules/snippets/505-at-references.md +9 -0
- package/governance/rules/ui/400-ui.md +36 -0
- package/governance/rules/ui/410-a11y.md +48 -0
- package/governance/rules/ui/420-forms.md +36 -0
- package/governance/rules/ui/430-ux-completeness.md +65 -0
- package/governance/rules/ui/440-surface-capture.md +34 -0
- package/governance/rules/ui/450-link-behavior.md +19 -0
- package/governance/stacks/astro.toml +2 -0
- package/governance/stacks/base.toml +8 -0
- package/governance/stacks/node-server.toml +2 -0
- package/governance/stacks/node.toml +2 -0
- package/governance/stacks/python-fastapi.toml +2 -0
- package/governance/stacks/python.toml +2 -0
- package/governance/stacks/react.toml +2 -0
- package/package.json +69 -0
- package/scripts/config.sh +11 -0
- package/scripts/core/bootstrap.sh +81 -0
- package/scripts/core/check-color-source.sh +41 -0
- package/scripts/core/check-ignore-parity.sh +162 -0
- package/scripts/core/check-plugin-boundary.sh +45 -0
- package/scripts/core/check-seed-independence.sh +59 -0
- package/scripts/core/check-skill-paths.sh +24 -0
- package/scripts/core/clean.sh +36 -0
- package/scripts/core/install-check.sh +101 -0
- package/scripts/core/list-seed-roots.sh +18 -0
- package/scripts/core/regen-claude-copies.sh +10 -0
- package/scripts/core/regen-hero.sh +217 -0
- package/scripts/core/regen-indexes.sh +10 -0
- package/scripts/core/regen-tooling-paths.sh +61 -0
- package/scripts/core/repair-bare-flag.sh +19 -0
- package/scripts/core/snapshot.sh +134 -0
- package/scripts/core/update.sh +35 -0
- package/scripts/docs/list.sh +165 -0
- package/scripts/lib/frontmatter.sh +30 -0
- package/scripts/lib/gov.sh +14 -0
- package/scripts/lib/sandbox-fixtures.sh +191 -0
- package/scripts/lib/sandbox-git.sh +125 -0
- package/scripts/lib/sandbox-path.sh +206 -0
- package/scripts/lib/tooling.sh +35 -0
- package/scripts/lib/ui.sh +266 -0
- package/scripts/lib/worktree.sh +20 -0
- package/scripts/manage-sandbox.sh +466 -0
- package/scripts/snippets/create.sh +156 -0
- package/scripts/standards/list.sh +115 -0
- package/scripts/tooling/create.sh +109 -0
- package/scripts/tooling/verify.sh +179 -0
- package/snippets/align.md +12 -0
- package/snippets/claude/decision-memo.md +39 -0
- package/snippets/claude/feature-recap.md +19 -0
- package/snippets/claude/figma-steps.md +24 -0
- package/snippets/compact-summary.md +5 -0
- package/snippets/decision-help.md +6 -0
- package/snippets/meta-prompt.md +14 -0
- package/snippets/research-prompt.md +7 -0
- package/snippets/session-notes.md +11 -0
- package/snippets/snippets.toml +5 -0
- package/snippets/step-by-step.md +10 -0
- package/snippets/web-research.md +21 -0
- package/src/audits/baseline.ts +201 -0
- package/src/audits/catalog.ts +876 -0
- package/src/audits/run.ts +204 -0
- package/src/autoship/classify.ts +75 -0
- package/src/autoship/paths.ts +51 -0
- package/src/binary.ts +16 -0
- package/src/browser/engine.ts +40 -0
- package/src/census/count.ts +113 -0
- package/src/claude/cases/all.ts +24 -0
- package/src/claude/cases/authoring.ts +53 -0
- package/src/claude/cases/claude-workflow.ts +158 -0
- package/src/claude/cases/git.ts +44 -0
- package/src/claude/cases/misc.ts +27 -0
- package/src/claude/cases/setup.ts +94 -0
- package/src/claude/gitignore.ts +51 -0
- package/src/claude/routing.ts +283 -0
- package/src/claude/seeds-list.ts +47 -0
- package/src/claude/seeds.ts +150 -0
- package/src/claude/settings.ts +151 -0
- package/src/claude/skills-audit.ts +228 -0
- package/src/claude/skills-drift.ts +156 -0
- package/src/claude/skills-list.ts +99 -0
- package/src/claude/skills-rank.ts +320 -0
- package/src/claude/skills-reach.ts +227 -0
- package/src/cli-run.ts +43 -0
- package/src/cli.ts +200 -0
- package/src/commands/audits.ts +350 -0
- package/src/commands/autoship.ts +129 -0
- package/src/commands/capture.ts +133 -0
- package/src/commands/census.ts +105 -0
- package/src/commands/claude.ts +1286 -0
- package/src/commands/comments.ts +240 -0
- package/src/commands/context.ts +857 -0
- package/src/commands/demo.ts +389 -0
- package/src/commands/deps.ts +173 -0
- package/src/commands/design.ts +36 -0
- package/src/commands/docs.ts +60 -0
- package/src/commands/feedback-format.ts +23 -0
- package/src/commands/feedback.ts +112 -0
- package/src/commands/gate.ts +189 -0
- package/src/commands/gov.ts +1265 -0
- package/src/commands/indexes.ts +184 -0
- package/src/commands/init.ts +113 -0
- package/src/commands/intake.ts +406 -0
- package/src/commands/inventory.ts +256 -0
- package/src/commands/labels.ts +361 -0
- package/src/commands/markdown.ts +544 -0
- package/src/commands/migrate.ts +175 -0
- package/src/commands/pass-through.ts +39 -0
- package/src/commands/pr.ts +411 -0
- package/src/commands/records.ts +728 -0
- package/src/commands/sandbox.ts +468 -0
- package/src/commands/secrets.ts +132 -0
- package/src/commands/serve.ts +159 -0
- package/src/commands/sessions.ts +408 -0
- package/src/commands/slides.ts +126 -0
- package/src/commands/snippets.ts +84 -0
- package/src/commands/standards.ts +247 -0
- package/src/commands/sync.ts +428 -0
- package/src/commands/targets.ts +319 -0
- package/src/commands/tasks.ts +743 -0
- package/src/commands/teach.ts +786 -0
- package/src/commands/tooling.ts +573 -0
- package/src/commands/transcripts.ts +44 -0
- package/src/commands/upgrade.ts +231 -0
- package/src/commands/wiki.ts +100 -0
- package/src/commands/worktrees.ts +191 -0
- package/src/comments/scan.ts +338 -0
- package/src/comments/trend.ts +207 -0
- package/src/comments/vocabulary.ts +85 -0
- package/src/context/architecture.ts +364 -0
- package/src/context/audit.ts +790 -0
- package/src/context/citations.ts +196 -0
- package/src/context/folders.ts +186 -0
- package/src/context/gate.ts +57 -0
- package/src/context/index-drift.ts +64 -0
- package/src/context/narration.ts +99 -0
- package/src/copy.ts +30 -0
- package/src/counts/catalogs.ts +96 -0
- package/src/counts/numbers.ts +79 -0
- package/src/counts/scan.ts +314 -0
- package/src/demo/beats.ts +135 -0
- package/src/demo/compile.ts +326 -0
- package/src/demo/container.ts +63 -0
- package/src/demo/cursors.ts +55 -0
- package/src/demo/drive.ts +357 -0
- package/src/demo/pointer.ts +178 -0
- package/src/demo/theme.ts +112 -0
- package/src/deps/audit.ts +153 -0
- package/src/design/parse.ts +116 -0
- package/src/design/render.ts +249 -0
- package/src/docs/read.ts +77 -0
- package/src/exec.ts +16 -0
- package/src/exempt-marker.ts +43 -0
- package/src/frontmatter.ts +13 -0
- package/src/gate/measures.ts +682 -0
- package/src/gate/sequencer.ts +386 -0
- package/src/gate/stages.ts +412 -0
- package/src/git-env.ts +36 -0
- package/src/git-files.ts +105 -0
- package/src/git-ignore.ts +46 -0
- package/src/github-format.ts +13 -0
- package/src/github.ts +24 -0
- package/src/gov/adapter.ts +103 -0
- package/src/gov/citations.ts +514 -0
- package/src/gov/consumed.ts +129 -0
- package/src/gov/install.ts +132 -0
- package/src/gov/list.ts +106 -0
- package/src/gov/payload.ts +39 -0
- package/src/gov/restated.ts +814 -0
- package/src/gov/stacks.ts +205 -0
- package/src/gov/superseded.ts +415 -0
- package/src/gov/test-order.ts +407 -0
- package/src/indexes/frontmatter.ts +46 -0
- package/src/indexes/regen.ts +84 -0
- package/src/indexes/render.ts +201 -0
- package/src/indexes/walk.ts +83 -0
- package/src/init/flags.ts +60 -0
- package/src/init/plan.ts +114 -0
- package/src/init/run.ts +46 -0
- package/src/init/steps.ts +77 -0
- package/src/intake/folder.ts +320 -0
- package/src/intake/items.ts +174 -0
- package/src/inventory/config.ts +117 -0
- package/src/inventory/group.ts +76 -0
- package/src/inventory/subjects.ts +114 -0
- package/src/inventory/walk.ts +129 -0
- package/src/labels/audit.ts +82 -0
- package/src/labels/coverage.ts +79 -0
- package/src/labels/map.ts +101 -0
- package/src/labels/phase.ts +95 -0
- package/src/markdown/bans.ts +94 -0
- package/src/markdown/files.ts +102 -0
- package/src/markdown/gate.ts +28 -0
- package/src/markdown/scan.ts +295 -0
- package/src/markdown/structure.ts +730 -0
- package/src/migrate/apply.ts +115 -0
- package/src/migrate/plan.ts +103 -0
- package/src/migrate/rename.ts +183 -0
- package/src/pr/bijection.ts +145 -0
- package/src/pr/paths.ts +335 -0
- package/src/process/harness.ts +167 -0
- package/src/project-root.ts +19 -0
- package/src/records/backup.ts +455 -0
- package/src/records/migrate.ts +78 -0
- package/src/records/size.ts +260 -0
- package/src/records/validate.ts +1162 -0
- package/src/sandbox/census.ts +228 -0
- package/src/sandbox/coverage.ts +115 -0
- package/src/sandbox/expect.ts +629 -0
- package/src/sandbox/tree.ts +47 -0
- package/src/secrets/marker.ts +30 -0
- package/src/secrets/patterns.ts +142 -0
- package/src/secrets/scan.ts +123 -0
- package/src/secrets/shipped.ts +111 -0
- package/src/seed-marker.ts +74 -0
- package/src/serve/static.ts +322 -0
- package/src/sessions/claim.ts +85 -0
- package/src/sessions/live.ts +79 -0
- package/src/sessions/registry.ts +137 -0
- package/src/sessions/resolve.ts +333 -0
- package/src/slides/layouts.ts +391 -0
- package/src/slides/open.ts +18 -0
- package/src/slides/parse.ts +84 -0
- package/src/slides/render.ts +88 -0
- package/src/slides/styles.ts +44 -0
- package/src/snippets/categories.ts +66 -0
- package/src/snippets/list.ts +32 -0
- package/src/snippets/presets.ts +50 -0
- package/src/standards/audit.ts +132 -0
- package/src/standards/read.ts +100 -0
- package/src/sync/check.ts +692 -0
- package/src/sync/engine.ts +576 -0
- package/src/sync/git.ts +225 -0
- package/src/sync/history.ts +123 -0
- package/src/sync/layout.ts +140 -0
- package/src/sync/reverse.ts +268 -0
- package/src/sync/seeds-report.ts +126 -0
- package/src/sync/stamp.ts +358 -0
- package/src/sync/target.ts +70 -0
- package/src/sync/workflow.ts +200 -0
- package/src/target.ts +43 -0
- package/src/targets/pulls.ts +250 -0
- package/src/targets/registry.ts +203 -0
- package/src/targets/resolve.ts +145 -0
- package/src/targets/sweep.ts +246 -0
- package/src/tasks/archive.ts +506 -0
- package/src/tasks/record.ts +311 -0
- package/src/tasks/trunk.ts +89 -0
- package/src/tasks/validate.ts +1001 -0
- package/src/teach/lesson.ts +180 -0
- package/src/teach/workspace.ts +842 -0
- package/src/tooling/gitignore.ts +122 -0
- package/src/tooling/inject.ts +193 -0
- package/src/tooling/list.ts +39 -0
- package/src/tooling/manifest.ts +176 -0
- package/src/tooling/package.ts +166 -0
- package/src/tooling/read.ts +65 -0
- package/src/tooling/scan.ts +147 -0
- package/src/tooling/stamp.ts +44 -0
- package/src/transcripts/fetch.ts +156 -0
- package/src/transcripts/metadata.ts +54 -0
- package/src/transcripts/vtt.ts +114 -0
- package/src/ui.ts +266 -0
- package/src/version/compare.ts +53 -0
- package/src/version/installed.ts +40 -0
- package/src/version/manager.ts +67 -0
- package/src/version/skew.ts +192 -0
- package/src/wiki/init.ts +85 -0
- package/src/worktree.ts +143 -0
- package/src/worktrees/reclaim.ts +306 -0
- package/standards/architecture.md +72 -0
- package/standards/branch.md +59 -0
- package/standards/commit.md +72 -0
- package/standards/context.md +151 -0
- package/standards/design.md +93 -0
- package/standards/diagrams.md +152 -0
- package/standards/glossary.md +75 -0
- package/standards/groundwork.md +211 -0
- package/standards/index.md +36 -0
- package/standards/intake.md +192 -0
- package/standards/issue.md +94 -0
- package/standards/markdown.md +137 -0
- package/standards/memory.md +144 -0
- package/standards/plan.md +172 -0
- package/standards/pr.md +139 -0
- package/standards/publish.md +51 -0
- package/standards/readme.md +208 -0
- package/standards/requirements.md +70 -0
- package/standards/rule.md +118 -0
- package/standards/session.md +109 -0
- package/standards/skill.md +300 -0
- package/standards/slug.md +39 -0
- package/standards/snippets.md +76 -0
- package/standards/standard.md +170 -0
- package/standards/tasks.md +254 -0
- package/standards/teach.md +153 -0
- package/standards/versioning.md +71 -0
- package/standards/wireframes.md +113 -0
- package/tooling/astro/configs/astro.config.mjs +31 -0
- package/tooling/astro/configs/eslint.config.js +79 -0
- package/tooling/astro/configs/playwright.config.ts +26 -0
- package/tooling/astro/configs/tsconfig.json +12 -0
- package/tooling/astro/configs/vitest.config.ts +22 -0
- package/tooling/astro/manifest.toml +34 -0
- package/tooling/astro/reference.md +60 -0
- package/tooling/base/configs/.editorconfig +5 -0
- package/tooling/base/configs/.github/pull_request_template.md +18 -0
- package/tooling/base/configs/.github/workflows/verify.yml +35 -0
- package/tooling/base/configs/.husky/commit-msg +1 -0
- package/tooling/base/configs/.husky/post-merge +61 -0
- package/tooling/base/configs/.husky/post-rewrite +21 -0
- package/tooling/base/configs/.husky/pre-commit +1 -0
- package/tooling/base/configs/.husky/pre-push +1 -0
- package/tooling/base/configs/.prettierrc +12 -0
- package/tooling/base/configs/.shellcheckrc +1 -0
- package/tooling/base/configs/.vscode/extensions.json +9 -0
- package/tooling/base/configs/.vscode/settings.json +3 -0
- package/tooling/base/configs/commitlint.config.js +11 -0
- package/tooling/base/configs/scripts/verify.sh +64 -0
- package/tooling/base/manifest.toml +30 -0
- package/tooling/base/reference.md +98 -0
- package/tooling/base/seeds/.claude/context/ci.md +33 -0
- package/tooling/base/seeds/.claude/context/development.md +37 -0
- package/tooling/base/seeds/.claude/context/index.md +11 -0
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/base/seeds/.lintstagedrc +8 -0
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/base/seeds/cspell.json +20 -0
- package/tooling/claude/manifest.toml +14 -0
- package/tooling/claude/reference.md +79 -0
- package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
- package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
- package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
- package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
- package/tooling/claude/seeds/.claude/memory/index.md +8 -0
- package/tooling/claude/seeds/.claude/settings.json +47 -0
- package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
- package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
- package/tooling/claude/seeds/CLAUDE.md +29 -0
- package/tooling/claude/user/settings.template.json +10 -0
- package/tooling/claude/user/statusline-command.sh +53 -0
- package/tooling/python/configs/.coveragerc +14 -0
- package/tooling/python/configs/.python-version +1 -0
- package/tooling/python/configs/mypy.ini +6 -0
- package/tooling/python/configs/pytest.ini +4 -0
- package/tooling/python/configs/ruff.toml +15 -0
- package/tooling/python/configs/scripts/verify.sh +77 -0
- package/tooling/python/manifest.toml +16 -0
- package/tooling/python/reference.md +66 -0
- package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/python/seeds/tests/test_smoke.py +2 -0
- package/tooling/vite-react/configs/playwright.config.ts +26 -0
- package/tooling/vite-react/configs/tsconfig.json +35 -0
- package/tooling/vite-react/configs/vite.config.ts +24 -0
- package/tooling/vite-react/configs/vitest.config.ts +26 -0
- package/tooling/vite-react/manifest.toml +23 -0
- package/tooling/vite-react/reference.md +55 -0
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
- package/tooling/web/configs/.github/workflows/verify.yml +134 -0
- package/tooling/web/configs/.vscode/extensions.json +13 -0
- package/tooling/web/configs/.vscode/settings.json +10 -0
- package/tooling/web/configs/e2e/home.spec.ts +6 -0
- package/tooling/web/configs/e2e/screenshot.ts +53 -0
- package/tooling/web/configs/eslint.config.js +82 -0
- package/tooling/web/configs/scripts/screenshot.sh +28 -0
- package/tooling/web/configs/scripts/verify.sh +80 -0
- package/tooling/web/configs/scripts/worktree-port.sh +74 -0
- package/tooling/web/configs/src/test/setup.ts +8 -0
- package/tooling/web/manifest.toml +58 -0
- package/tooling/web/reference.md +115 -0
- package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Reports worker and pull request transitions as they happen. Reads only.
|
|
3
|
+
#
|
|
4
|
+
# The poll answers "what moved since the last run" on a schedule the session
|
|
5
|
+
# holds. This answers "what just changed" on a loop of its own, and it exists
|
|
6
|
+
# because the two readings a dispatch needs are not one reading: a worker that
|
|
7
|
+
# finishes goes idle and a worker that crashes vanishes, so a watch matching
|
|
8
|
+
# only the pull request list stays silent through the second. A third case is
|
|
9
|
+
# neither: a worker that stops on a question or a prompt neither finishes nor
|
|
10
|
+
# crashes, and sits reading "waiting" beside the two statuses that resolve on
|
|
11
|
+
# their own until something reports it, which is the WORKER-STOPPED line
|
|
12
|
+
# below, or WORKER-UNMEASURABLE for a "waiting" row too old to carry a stamp
|
|
13
|
+
# this reads.
|
|
14
|
+
#
|
|
15
|
+
# `set -e` is deliberately not set. This runs for hours, and one transient `gh`
|
|
16
|
+
# failure aborting the loop is a silent stop rather than a reported one. Every
|
|
17
|
+
# read below states its own failure instead.
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
|
|
20
|
+
# Seconds between passes. A pass costs two cheap reads and the transitions it
|
|
21
|
+
# watches take minutes, so the number trades staleness against little. Raise it
|
|
22
|
+
# in a project whose workers run long.
|
|
23
|
+
INTERVAL=60
|
|
24
|
+
|
|
25
|
+
# Seconds a worker can sit in "waiting" before this reports it as stopped
|
|
26
|
+
# rather than folding it into the ordinary status-change lines below. "busy"
|
|
27
|
+
# and "idle" resolve on their own; "waiting" does not, so a dwell that keeps
|
|
28
|
+
# growing there is a session blocked on something outside itself.
|
|
29
|
+
#
|
|
30
|
+
# Measured against the live session registry: 341 usable records carried a
|
|
31
|
+
# status at all, and exactly one carried "waiting", too sparse a sample to fit
|
|
32
|
+
# a distribution. The number is picked from the two bounds the measurement can
|
|
33
|
+
# still name rather than from a round guess: well above INTERVAL, so a handful
|
|
34
|
+
# of passes confirm the row before it reports rather than one slow tool call
|
|
35
|
+
# tripping it, and well inside the ten-to-thirty-minute span a dispatched build
|
|
36
|
+
# ordinarily runs, so a real stall is caught with most of that window still
|
|
37
|
+
# open to act on it.
|
|
38
|
+
#
|
|
39
|
+
# That one record carried `waitingFor: "approve Bash"`, a permission prompt
|
|
40
|
+
# rather than a question, and the two clear on different schedules: a prompt
|
|
41
|
+
# resolves the moment a person approves it, where a question can sit
|
|
42
|
+
# legitimately while a controller finishes a turn. This number is defensible
|
|
43
|
+
# for the second and generous for the first, and the gap stays open rather
|
|
44
|
+
# than splitting the constant on a sample of one.
|
|
45
|
+
STALL_THRESHOLD_S=300
|
|
46
|
+
|
|
47
|
+
# Resolving the main worktree root rather than this file's folder keeps a watch
|
|
48
|
+
# started from a linked worktree reading the same repository as one started from
|
|
49
|
+
# main. The repository field on a roster row is that root's `.git`.
|
|
50
|
+
MAIN_ROOT="$(git worktree list --porcelain 2>/dev/null | awk '/^worktree /{print $2; exit}')"
|
|
51
|
+
if [ -z "$MAIN_ROOT" ]; then
|
|
52
|
+
echo "watch: not a git repository, so nothing is watched" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
REPOSITORY="$MAIN_ROOT/.git"
|
|
56
|
+
|
|
57
|
+
# The base branch is read rather than assumed, since this ships to projects that
|
|
58
|
+
# do not all call it `main`. It is what separates a worker from the controlling
|
|
59
|
+
# session, which sits on the base branch in the main worktree.
|
|
60
|
+
BASE_REF="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null || true)"
|
|
61
|
+
if [ -z "$BASE_REF" ]; then
|
|
62
|
+
BASE_REF="origin/$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name 2>/dev/null || echo main)"
|
|
63
|
+
fi
|
|
64
|
+
BASE_BRANCH="${BASE_REF#origin/}"
|
|
65
|
+
|
|
66
|
+
# Every session in this repository holding a branch other than the base one is a
|
|
67
|
+
# worker, whoever launched it. The prototype matched the `orchestrator-` prefix
|
|
68
|
+
# instead, which reads a dispatched worker and misses every hand-launched one,
|
|
69
|
+
# and those are the ordinary shape whenever the operator is launching.
|
|
70
|
+
#
|
|
71
|
+
# The row goes out tab-separated and comes back read with IFS set to a tab. A
|
|
72
|
+
# name this client actually writes carries spaces, `Update session markdown
|
|
73
|
+
# and check runnable commands (3)` among them, and splitting on whitespace
|
|
74
|
+
# took that one apart into a wrong name, branch, status, and dwell.
|
|
75
|
+
read_workers() {
|
|
76
|
+
canon sessions list --json 2>/dev/null | tail -1 | jq -r \
|
|
77
|
+
--arg repository "$REPOSITORY" --arg base "$BASE_BRANCH" '
|
|
78
|
+
.sessions[]?
|
|
79
|
+
| select(.repository == $repository)
|
|
80
|
+
| select(.branch != null and .branch != $base)
|
|
81
|
+
| [.name, .branch, .status, (.statusDwellMs // -1 | tostring)]
|
|
82
|
+
| @tsv
|
|
83
|
+
' 2>/dev/null | sort
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
read_pulls() {
|
|
87
|
+
gh pr list --state open --json number,headRefName,title --jq \
|
|
88
|
+
'.[] | "PR-OPEN #\(.number) \(.headRefName) \(.title)"' 2>/dev/null | sort
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# A failed read is reported and the previous baseline kept. Reading an empty
|
|
92
|
+
# result as the current state would report every worker gone and every pull
|
|
93
|
+
# request new on the pass after, which is the one failure that makes a detection
|
|
94
|
+
# tool worth less than no tool.
|
|
95
|
+
#
|
|
96
|
+
# The two sources carry a baseline flag apiece rather than sharing one. A read
|
|
97
|
+
# that fails on the first pass leaves its baseline empty while the other source
|
|
98
|
+
# establishes one, and a single flag would then report that source's whole list
|
|
99
|
+
# as new on the pass after it recovers.
|
|
100
|
+
prev_pulls=""
|
|
101
|
+
prev_workers=""
|
|
102
|
+
prev_names=""
|
|
103
|
+
pulls_seen=0
|
|
104
|
+
workers_seen=0
|
|
105
|
+
|
|
106
|
+
# One row per worker name currently reported, waiting past STALL_THRESHOLD_S
|
|
107
|
+
# or waiting with no stamp to measure, so a reader watching the log is told
|
|
108
|
+
# once rather than on every remaining pass. The prototype for that shape is
|
|
109
|
+
# the WORKER-GONE/WORKER pair above, tracked in the same state a status change
|
|
110
|
+
# is: a name drops out the pass it stops reading "waiting", which lets the
|
|
111
|
+
# same worker report a second stall later in its life rather than being
|
|
112
|
+
# marked forever by its first one.
|
|
113
|
+
declare -A stalled
|
|
114
|
+
|
|
115
|
+
while true; do
|
|
116
|
+
pulls="$(read_pulls)"
|
|
117
|
+
pulls_read=$?
|
|
118
|
+
workers="$(read_workers)"
|
|
119
|
+
workers_read=$?
|
|
120
|
+
|
|
121
|
+
if [ "$pulls_read" -ne 0 ]; then
|
|
122
|
+
echo "watch: the open pull request list failed to load, so none is classified this pass"
|
|
123
|
+
fi
|
|
124
|
+
if [ "$workers_read" -ne 0 ]; then
|
|
125
|
+
echo "watch: the session roster failed to load, so no worker is classified this pass"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
names="$(printf '%s\n' "$workers" | awk -F'\t' 'NF {print $1}' | sort -u)"
|
|
129
|
+
|
|
130
|
+
if [ "$pulls_seen" -eq 1 ] && [ "$pulls_read" -eq 0 ]; then
|
|
131
|
+
comm -13 <(printf '%s\n' "$prev_pulls") <(printf '%s\n' "$pulls") | grep . || true
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
if [ "$workers_seen" -eq 1 ] && [ "$workers_read" -eq 0 ]; then
|
|
135
|
+
comm -13 <(printf '%s\n' "$prev_workers") <(printf '%s\n' "$workers") |
|
|
136
|
+
grep . | sed 's/^/WORKER /' || true
|
|
137
|
+
comm -23 <(printf '%s\n' "$prev_names") <(printf '%s\n' "$names") |
|
|
138
|
+
grep . | sed 's/^/WORKER-GONE /' || true
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
if [ "$workers_read" -eq 0 ]; then
|
|
142
|
+
while IFS=$'\t' read -r w_name w_branch w_status w_dwell_ms; do
|
|
143
|
+
[ -z "$w_name" ] && continue
|
|
144
|
+
|
|
145
|
+
if [ "$w_status" != "waiting" ]; then
|
|
146
|
+
unset "stalled[$w_name]"
|
|
147
|
+
continue
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
if [ "$w_dwell_ms" = "-1" ]; then
|
|
151
|
+
if [ -z "${stalled[$w_name]:-}" ]; then
|
|
152
|
+
echo "WORKER-UNMEASURABLE $w_name $w_branch"
|
|
153
|
+
stalled[$w_name]=1
|
|
154
|
+
fi
|
|
155
|
+
continue
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
w_dwell_s=$((w_dwell_ms / 1000))
|
|
159
|
+
if [ "$w_dwell_s" -ge "$STALL_THRESHOLD_S" ]; then
|
|
160
|
+
if [ -z "${stalled[$w_name]:-}" ]; then
|
|
161
|
+
echo "WORKER-STOPPED $w_name $w_branch ${w_dwell_s}s"
|
|
162
|
+
stalled[$w_name]=1
|
|
163
|
+
fi
|
|
164
|
+
else
|
|
165
|
+
unset "stalled[$w_name]"
|
|
166
|
+
fi
|
|
167
|
+
done <<<"$workers"
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
if [ "$pulls_read" -eq 0 ]; then
|
|
171
|
+
prev_pulls="$pulls"
|
|
172
|
+
pulls_seen=1
|
|
173
|
+
fi
|
|
174
|
+
if [ "$workers_read" -eq 0 ]; then
|
|
175
|
+
prev_workers="$workers"
|
|
176
|
+
prev_names="$names"
|
|
177
|
+
workers_seen=1
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
sleep "$INTERVAL"
|
|
181
|
+
done
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: claude-pr-review
|
|
3
|
+
description: What the independent pull request review is for, the gaps it closes, and why it posts until nothing is open
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Claude PR review requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a pull request is reviewed only by the session that wrote it, which cannot see the board's order or a sibling branch in flight. Findings land in chat, where they are read once and leave the thread with no record. A review that opens and never closes is worse than none, since a reader scanning the thread cannot tell an unanswered review from a confirmed one, and the author's claim that findings are fixed is the only evidence they are.
|
|
11
|
+
|
|
12
|
+
A finding also stops being true by argument rather than by a fix. A worker naming the plan question that already declined it, or a constraint the pass could not see, settles it in the exchange that carried the answer, and the pass that accepts the argument drops the finding from its next body. A reader then sees a finding raised once and never mentioned again, which is indistinguishable from one everyone forgot.
|
|
13
|
+
|
|
14
|
+
A request written under `## For the reviewer` also reached no reader. The authoring standard names it as what the reviewing session should confirm, and nothing on this side read the section by that name, so a branch author's question sat in the body until this skill answered it.
|
|
15
|
+
|
|
16
|
+
## Must
|
|
17
|
+
|
|
18
|
+
- Post until the review closes. A first pass opens against the whole change, and each later pass checks whether the prior findings landed.
|
|
19
|
+
- Set the heading from the finding count rather than the pass number, so the most recent review comment's heading reports whether anything is open
|
|
20
|
+
- Detect the pass from the thread rather than taking it from the caller, matching the heading for equality so a neighboring comment cannot be read as a prior pass
|
|
21
|
+
- Scope a later pass to the commits added since the prior one, once that commit is confirmed to still reach the head
|
|
22
|
+
- Apply the integration, contract, and consumer lenses a self-review structurally cannot
|
|
23
|
+
- Post the closing pass even with nothing to report, since a review left unanswered reads as one nobody closed
|
|
24
|
+
- State a withdrawal or a regrade on the thread with the fact that settled it, since a finding dropped in silence reads the same as one nobody answered
|
|
25
|
+
- Key the body file on the pull request number and the head commit, and on the response it answers once the head repeats, so no two passes overwrite each other
|
|
26
|
+
- Scan the comment for banned characters and internal phase labels before posting, since a finding phrased against a phase label reaches a reader with no task board
|
|
27
|
+
- Answer a `## For the reviewer` bullet in the body, bounded to the section itself rather than the Summary or the Technical Context around it, so the independent vantage stays clear of the author's framing
|
|
28
|
+
|
|
29
|
+
## Must not
|
|
30
|
+
|
|
31
|
+
- Merge. Review and post, and leave the gate to the human.
|
|
32
|
+
- Publish a claim the skill did not check. A failed fetch and a rebase both strand the prior commit, and only one of them is a rebase.
|
|
33
|
+
- Invent a heading beyond the two it posts and the response heading `claude-address-review` owns, or append a number GitHub already renders
|
|
34
|
+
- Review local uncommitted changes
|
|
35
|
+
- Lecture on process. The lenses land as findings, not as asides.
|
|
36
|
+
|
|
37
|
+
## Guards
|
|
38
|
+
|
|
39
|
+
- No open pull request for the target branch: stop and route to the local review skill
|
|
40
|
+
- The fetch of the pull request head fails: stop rather than falling through to a full pass
|
|
41
|
+
- The head repeats with no response since the prior pass: stop rather than posting a body restating one the folder holds
|
|
42
|
+
|
|
43
|
+
## Out of scope
|
|
44
|
+
|
|
45
|
+
- Fixing what it finds, which `claude-address-review` owns. The split is by side of the channel: this one posts findings from an independent session and that one consumes them.
|
|
46
|
+
- Reviewing local uncommitted work, which `claude-review` owns. That one writes to disk for the session that wrote the code, and this one posts to a pull request it did not write.
|
|
47
|
+
- Merging, which stays the human's decision
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: claude-pr-review
|
|
3
|
+
description: Reviews an open pull request from an independent session and posts findings as a review comment on the PR. Posts a first pass against the whole change and every later pass against only the commits added since, under `## Review` while any finding is open and `## Review closed` once a pass carries none. Reads project docs and the task board for cross-feature context a self-review lacks. Use when asked to "review the PR", "review this feature's PR", "post a PR review", "re-review the PR", "close out the review", "confirm the findings are fixed", or acting as the orchestrator reviewing a worker's PR. Do NOT use to review local uncommitted changes. That is `claude-review`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Claude PR review
|
|
7
|
+
|
|
8
|
+
This is the orchestrator's independent review, distinct from `claude-review`.
|
|
9
|
+
`claude-review` reviews local changes for the session that wrote them and writes
|
|
10
|
+
to disk. This one reviews an open PR the session did not write and posts the
|
|
11
|
+
findings to the PR, so the vantage is independent and the output is durable.
|
|
12
|
+
|
|
13
|
+
It posts at least twice over a pull request's life. A first pass opens the
|
|
14
|
+
review against the whole change, and every later pass reads only the commits
|
|
15
|
+
added since. The heading reports state rather than pass number: a pass carrying
|
|
16
|
+
anything owed takes `## Review`, and `## Review closed` covers a pass carrying
|
|
17
|
+
none, so the most recent comment's heading reports whether any work is owed.
|
|
18
|
+
Owed is a finding at any severity, a Testing question, or a reviewer request nobody has answered, defined once at Step 4. Every pass is this skill, and which one it is gets detected from
|
|
19
|
+
the thread rather than named by the caller.
|
|
20
|
+
|
|
21
|
+
One live verdict stands at a time. A pass that would repeat a standing
|
|
22
|
+
close-out rewrites that comment in place rather than posting beside it, so a
|
|
23
|
+
reader scanning the thread finds the current verdict where the last one sat.
|
|
24
|
+
|
|
25
|
+
## Guards
|
|
26
|
+
|
|
27
|
+
- If no open PR resolves for the target branch via `gh pr view`, stop: `❌ No open PR to review. Open one first, or use /claude-review for local changes.`
|
|
28
|
+
- Review and post. Do not merge. Merging is the human's gate.
|
|
29
|
+
|
|
30
|
+
## Step 1: resolve the PR and read context
|
|
31
|
+
|
|
32
|
+
Resolve the PR: `gh pr view --json number,headRefName,headRefOid,title,body` for the current branch, or use a PR number the user names. The first seven characters of `headRefOid` are `<short-sha>`, which names the body file in Step 4.
|
|
33
|
+
|
|
34
|
+
Read these in parallel from the project root, skipping any that do not exist:
|
|
35
|
+
|
|
36
|
+
- `CLAUDE.md`: project type, conventions, and commands
|
|
37
|
+
- `.claude/REQUIREMENTS.md`: feature scope and non-goals
|
|
38
|
+
- `.claude/ARCHITECTURE.md`: technical design decisions
|
|
39
|
+
- `.claude/tasks/priority.md`: where this feature sits on the board and what each neighboring row waits on. Resolve this one at the main worktree root per Worktrees in `CLAUDE.md`, since the board is gitignored and a linked worktree holds no copy of it
|
|
40
|
+
- `.claude/plans/feature-<slug>.md` for the branch, when present: the intent the PR should satisfy
|
|
41
|
+
|
|
42
|
+
Coding standards from `.claude/rules/` are auto-loaded by Claude Code.
|
|
43
|
+
|
|
44
|
+
## Step 2: scope the read
|
|
45
|
+
|
|
46
|
+
Find the commit the last pass covered and the verdict it posted:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
gh pr view <number> --json reviews --jq '[.reviews[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review" or . == "## Review closed")] | last | select(. != null) | ((.commit.oid // "") + "\t" + (.body | split("\n")[0] | rtrimstr("\r")))'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The two fields are `<prior-oid>` and `<prior-heading>`. The commit scopes the read below and the heading feeds the repeat guard at the end of this step, so one query answers both rather than two reads of the same review. Keep the `select(. != null)` guard, since the string concatenation aborts jq on the null an empty selection returns, and an aborted command reaches the session as an error rather than as the empty result the first-pass branch reads.
|
|
53
|
+
|
|
54
|
+
Match the first line for equality against the two headings this skill posts. A prefix test also matches `## Review response` and any heading merely starting with those words, which would scope the pass to whatever commit that comment carried. The `\r` trim covers a body composed in the GitHub web editor, which stores CRLF.
|
|
55
|
+
|
|
56
|
+
An empty result is a first pass. Read the whole change:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
gh pr diff <number>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
gh pr diff <number> --name-only
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
A commit is a later pass. Fetch the pull request head so both commits are local:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git fetch -q origin pull/<number>/head
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A failed fetch stops the skill: `❌ Could not fetch the PR head. Retry once the remote is reachable.` Do not fall through to the full pass. A fetch failure and a rebase both leave the prior commit unreachable, and the fallback below states a rebase as fact on the pull request, so conflating the two publishes a claim the skill never checked.
|
|
73
|
+
|
|
74
|
+
Then test that the prior commit still reaches the head:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git merge-base --is-ancestor <prior-oid> <headRefOid>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
On exit zero, review `<prior-oid>..<headRefOid>` and nothing else. `git diff` and `git log --oneline` over that range are the whole read, because the first pass already covered everything behind it. A non-zero exit means the branch was rebased or force-pushed, so the delta is undefined rather than empty. Fall back to the full pass above and say so in the body.
|
|
81
|
+
|
|
82
|
+
A commit is its own ancestor, so an unchanged head passes that test too, with an empty range. When `<prior-oid>` equals `<headRefOid>`, decide whether this pass has anything to add before reading anything else, since the empty range itself cannot answer that:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
gh pr view <number> --json reviews,comments --jq '([.reviews[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review" or . == "## Review closed")] | last | .submittedAt) as $prior | [.comments[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review response" or . == "## Rebase" or . == "## Post-review findings") | select(.createdAt > $prior)] | last | .url // empty | split("-") | last'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Scope the replies to those newer than the prior pass, never to every reply the thread carries. A pass answering the newest reply and a pass answering an older one derive the same third segment (Step 4), so an unscoped read hands a re-run after a close-out the name its own prior pass already wrote. That is the collision this case exists to prevent, reached without a rebase or an error.
|
|
89
|
+
|
|
90
|
+
Read the number off `.url`. The `id` field carries a GraphQL node id, which the thread never displays. Keep the `// empty` guard, since `split` aborts jq on the null an empty selection returns, and an aborted command reaches the session as an error rather than as the empty result the stop below reads.
|
|
91
|
+
|
|
92
|
+
An empty result means no reply arrived since the prior pass, so the head is unchanged and this pass has nothing new to add. Stop here, before Step 3 or Step 4 run: `❌ The head is unchanged since the prior pass on <short-sha>. Nothing new to review.` This is the earliest point every path crosses, which is why the check sits here rather than inside Step 4's filename derivation. A path that decides there is nothing to add never reaches a step reached only when composing a body, so a stop written there is a stop a shortcut path can route around.
|
|
93
|
+
|
|
94
|
+
A non-empty result carries the comment id Step 4 needs for the third filename segment. A `## Review response` or a `## Rebase` reply answers a finding already argued or reports a stale branch resolved without one, so read it for what the worker changed or accepted, treat an accepted finding as closed rather than restating it, and skip the diff and file reads below. This is the entire read on a repeated head for either heading, since the empty range above has nothing in it to say whether a prior finding landed and neither reply needs anything more to answer that.
|
|
95
|
+
|
|
96
|
+
A `## Post-review findings` reply carries no argued finding behind it, since it asserts a new defect rather than answering one, and this pass is its first independent reader. Restating it as a finding without opening anything is repeating the worker's claim rather than checking it. Read the file the comment names at `<headRefOid>`, the same `git show <headRefOid>:<path>` read Step 3 already runs to confirm a ticked box, and confirm the defect before it becomes a finding of this pass's own.
|
|
97
|
+
|
|
98
|
+
A moved head has its own way to add nothing, which the ancestor test cannot see. When `<prior-heading>` reads `## Review closed`, the standing verdict already reports the branch clear, so a pass over the new commits that raises nothing posts a comment saying what the one above it said. Two close-outs landed on `#1201` that way on 2026-08-28, and the operator caught the pair rather than any check.
|
|
99
|
+
|
|
100
|
+
The producing shape is narrow. A prior pass tells the author a change is their own call, the author makes it, and the delta reaching the next pass has nothing left to say by construction.
|
|
101
|
+
|
|
102
|
+
Carry `<prior-heading>` into Step 4 and run Step 3 unchanged. This guard cannot stop the pass the way the unchanged-head stop above does, because that stop reads an empty range and this one turns on what the pass carries, which is Step 3's output. Deciding ahead of the review would swallow the pass that does find something, and that is the costlier error, so the rule is stated beside its sibling and executed where the heading is picked.
|
|
103
|
+
|
|
104
|
+
Read each changed file in scope. Skip deleted files. Run reads in parallel.
|
|
105
|
+
|
|
106
|
+
## Step 3: review
|
|
107
|
+
|
|
108
|
+
Review the diff and files for the same axes as `claude-review` (bugs, edge cases, error handling, logic flaws, security, rule violations), then add the three lenses a self-review structurally cannot apply:
|
|
109
|
+
|
|
110
|
+
- Integration: does this fit the board's order, the shared wiring seam, and any sibling PR in flight?
|
|
111
|
+
- Contract: does a contract downstream features depend on land correctly, and should the plan itself be questioned?
|
|
112
|
+
- Consumers: when the change touches a resource with more than one consumer, enumerate them and check the rule against each. A rule written for the consumer the change targets can be wrong for a sibling that writes.
|
|
113
|
+
|
|
114
|
+
Then read the description's `## Testing` section, which is the one part of a pull request body this session is positioned to falsify. The branch author cannot see what a sibling branch drove the same day, and the arm list is what settles the claim rather than the diff.
|
|
115
|
+
|
|
116
|
+
Test every unchecked box against the testing discipline in `${CLAUDE_SKILL_DIR}/../../standards/pr.md`, which reserves an unchecked box for a capability the agent lacks. Raise the box when it names no human at all, when the human it names is a live agent session, or when it names a person for a step the repository ships a harness for, `scripts/sandbox/run.sh` and `scripts/eval/run.sh` being the two. Cost alone is not an answer, since authorizing a spend is the operator's and performing the run is not. A refusal the author actually met is an answer, and it names which one.
|
|
117
|
+
|
|
118
|
+
Test every ticked box too, bounded to one naming a file or a command. Confirm what it names still exists at `<headRefOid>`, `git show <headRefOid>:<path>` for a file or `git grep <command> <headRefOid>` for a command, rather than re-running what it claims. A box naming neither stays untested, since nothing here can confirm a claim carrying no artifact. A box ticked before a later commit removed or replaced what it names is a `should-fix` finding on the body itself, filed under a `**PR body**` block ahead of the file blocks, since what it corrupts is the merge record rather than a file in the diff.
|
|
119
|
+
|
|
120
|
+
Test what `## Key Changes` claims against the diff it describes, with `canon pr key-changes <number> --json`. This repository squash-merges, so that section becomes the commit message and the record on the trunk once the branch is gone, which is the same thing a stale ticked box corrupts. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero.
|
|
121
|
+
|
|
122
|
+
Read `unmet` as a `should-fix` finding under the same `**PR body**` block the stale box takes, one entry per path, quoting the bullet the record carries on `preview` and naming the `head` the comparison ran at. Read the bullet before filing it, since one class survives the reader: a bullet citing where something is defined while claiming an edit elsewhere, which puts a real path in the claim region and points the change at a locative the path does not name. Report that as the class rather than as a stale claim. A body is edited between pushes, so the reading is true at that commit and can be false a minute later. Read `unnamed` as a question rather than a finding, since the class covers a real omission and equally a lockfile, a generated asset, or a regenerated index that earns no bullet, and raise it only where a reader would want the bullet. Report `unresolved` nowhere: a path written partially was judged in neither direction and says nothing about the body.
|
|
123
|
+
|
|
124
|
+
A `reason` of `no-claims` means the reader resolved no path out of a section that exists, which is the extractor failing over prose rather than the body being wrong. Say so and raise nothing. `no-section` is the body carrying no such heading, which is a finding only where the pull request template asks for one.
|
|
125
|
+
|
|
126
|
+
Compose this on the body read Step 4 already performs rather than opening a second one. That step scans the title and body for a leaked phase label, and both reads answer from the same text at the same head.
|
|
127
|
+
|
|
128
|
+
Ask rather than grade. Whether a human is genuinely required is a reading the branch author may hold a reason this session cannot see, so the question carries no severity and enters no count. What it does carry is the heading and the dispatch, on the rule Step 4 states, because a question the author never receives corrects nothing and the author is the only party who can answer it. Answering it closes it, and the answer may be that the requirement holds.
|
|
129
|
+
|
|
130
|
+
Read `## For the reviewer` the same way, bounded to the bullets under that heading rather than the Summary or the Technical Context around it. Those two carry the author's argument for the change, and reading them while judging it is most of what an independent pass exists to avoid, so the read stops at the section itself.
|
|
131
|
+
|
|
132
|
+
Answer each bullet in the body, on the same terms as a Testing question: no severity, no count. A request nobody can answer stays owed under the heading and dispatch Step 4 states, keeping the thread open exactly as an unanswered Testing box does. One the pass does answer carries no further weight, since the answer is discharged in the same comment that carries it.
|
|
133
|
+
|
|
134
|
+
Apply the high-signal filter: flag only what will cause incorrect behavior, break a documented rule, or mislead a downstream feature. If uncertain, do not flag.
|
|
135
|
+
|
|
136
|
+
A later pass applies the same axes to the delta, and adds one check the first pass cannot make: did each prior finding land, and did the fix regress anything it touched. Findings of its own are normal findings, stated at the same severity and counted the same way. That count is one of the two things Step 4 reads to pick the heading, so a pass raising a finding of its own is not a close-out at any severity.
|
|
137
|
+
|
|
138
|
+
A prior finding can also be settled by argument rather than by a fix. A reply naming the plan question that already declined it, or a constraint this session could not see, withdraws the finding or moves its grade. State that outcome in the body under the finding it changes, naming the fact that produced it, whether the argument arrived on the thread or through the channel that carried the dispatch. Dropping the finding from this body instead leaves a reader unable to tell a withdrawal from an oversight, and the reasoning goes with the session that heard it. A withdrawal removes the finding from the count, so a pass that withdrew every finding it carried is a close-out. Write the withdrawal and its cause into that body rather than taking the short close-out line Step 4 supplies, which reports prior findings addressed and would credit a fix nobody made.
|
|
139
|
+
|
|
140
|
+
Use severity: `critical` (blocks merge), `should-fix` (fix before merge), `minor` (blocks nothing). The ladder ranks a finding and decides nothing about who acts on it, since every grade takes the open heading and owes a dispatch under the threshold Step 4 states.
|
|
141
|
+
|
|
142
|
+
## Step 4: post to the PR
|
|
143
|
+
|
|
144
|
+
Write the comment to `.claude/.tmp/pr-review/body-<number>-<short-sha>.md`, which the rest of this step calls `<body-file>`. The PR number stops two sessions reviewing different pull requests from overwriting each other between the write and the post. The head commit stops a second pass overwriting the first one's body, and leaves the folder a record of which commit each review covered.
|
|
145
|
+
|
|
146
|
+
Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
|
|
147
|
+
|
|
148
|
+
When `<prior-oid>` from Step 2 equals `headRefOid`, the head repeats and the folder already holds `body-<number>-<short-sha>.md`. Add a third segment taking the id of the reply Step 2 resolved, giving `body-<number>-<short-sha>-r<comment-id>.md`, which is `<body-file>` on that path. That satisfies both prohibitions above rather than carving an exception into either. Step 2 already stopped the pass when that resolution came back empty, so reaching this line means the comment id is in hand.
|
|
149
|
+
|
|
150
|
+
The comment is a rendered-for-human GitHub surface, so load the `write-human` skill for voice and follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for the banned words: cut editorializing, and keep every sentence load-bearing. Match this shape on a first pass:
|
|
151
|
+
|
|
152
|
+
```markdown
|
|
153
|
+
## Review
|
|
154
|
+
|
|
155
|
+
X critical, Y should-fix, Z minor. Reviewed against project docs and the board.
|
|
156
|
+
|
|
157
|
+
**`path/to/file.ext`**
|
|
158
|
+
|
|
159
|
+
- **should-fix**: what breaks and the fix, in two or three sentences.
|
|
160
|
+
- **minor**: finding.
|
|
161
|
+
|
|
162
|
+
**What is right**
|
|
163
|
+
|
|
164
|
+
- bounded confirmation.
|
|
165
|
+
|
|
166
|
+
🤖 Reviewed by Claude Code
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
A stale ticked box goes in a `**PR body**` block, in place of a `**`path/to/file.ext`**` block and ahead of every one of those, since it precedes the code the diff carries rather than sitting inside it.
|
|
170
|
+
|
|
171
|
+
Run `canon labels scan --title "<title>" --body "<body>" --head <headRefName>` against the PR under review, since Step 1 already holds all three and this pass is the last human-shaped gate before merge. A hit lands in the same `**PR body**` block, `should-fix`, naming each token the scan returns. This reads the pull request being reviewed, distinct from the comment this pass is about to post, which the scan later in this step still covers.
|
|
172
|
+
|
|
173
|
+
A later pass carrying findings keeps that shape and changes only the summary line:
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
## Review
|
|
177
|
+
|
|
178
|
+
Re-reviewed `<short-sha>`, N commits since the prior pass. X critical, Y should-fix, Z minor.
|
|
179
|
+
|
|
180
|
+
**`path/to/file.ext`**
|
|
181
|
+
|
|
182
|
+
- **should-fix**: what breaks and the fix, in two or three sentences.
|
|
183
|
+
|
|
184
|
+
🤖 Reviewed by Claude Code
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
A Testing box the Step 3 check raised goes in a `**Testing**` block placed after the file blocks, one bullet per box, each quoting the box and naming what would drive it. It carries no severity and enters no count, and it is still something owed, so a pass carrying one takes `## Review` and the full body rather than either ✅ line. Say so on the summary line as `plus N testing question(s)`, since the three counts read as zero and would otherwise report the pass as silent.
|
|
188
|
+
|
|
189
|
+
```markdown
|
|
190
|
+
**Testing**
|
|
191
|
+
|
|
192
|
+
- `- [ ] <the box as written>` names no capability the agent lacks. `scripts/sandbox/run.sh <arm>` drives it. Was there a reason to leave it?
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Keep it to the boxes the check raised. Restating a box whose stated requirement holds teaches the branch author to skip the block.
|
|
196
|
+
|
|
197
|
+
Every `## For the reviewer` bullet Step 3 read goes in a `**For the reviewer**` block placed after the Testing block, one bullet per request, each followed by its answer or, where the pass could not answer it, by what would settle it. It carries no severity and enters no count.
|
|
198
|
+
|
|
199
|
+
An unanswered bullet is owed the same way an unanswered Testing box is, so a pass carrying one takes `## Review` and the full body rather than either ✅ line. A bullet the pass answered is not owed, since the answer is discharged in the same comment that carries it. A pass still posting a numeric summary line, because a finding, a Testing question, or an unanswered bullet already forces one, says so there as `plus N reviewer request(s)`. The all-answered close-out below carries the block in place of that line and needs no addition to it.
|
|
200
|
+
|
|
201
|
+
```markdown
|
|
202
|
+
**For the reviewer**
|
|
203
|
+
|
|
204
|
+
- Confirm the 401 and 403 split reads correctly for the public API. Confirmed — `AuthService.authenticate()` returns 401 for an expired token and 403 for a missing scope, and both paths are covered under `## Testing`.
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The threshold is stated here and nowhere else, and every other surface acting on it cites this skill rather than restating the grades. One rule governs both the heading and the dispatch: a pass carrying anything owed takes `## Review` and owes a dispatch to the session holding the branch, and a pass carrying nothing at all takes `## Review closed` and owes none. Owed covers a finding at any severity, a Testing question, and a reviewer request nobody has answered alike, which is what keeps the two halves from separating. Sending that dispatch is `claude-orchestrate`'s step rather than this one, which posts and stops. Post the open heading whether it is the first pass or the fourth. A pull request thread then reads as `## Review`, the worker's answer under `## Review response` from `claude-address-review`, another `## Review` while anything stays open, and `## Review closed` when nothing does.
|
|
208
|
+
|
|
209
|
+
Keying either half on the grade was measured wrong: across 8 findings on one archived pass, 3 were posted as minor and 2 of those were defects a worker fixed rather than recorded, so a floor at should-fix loses real fixes to a grade that runs low. Splitting the two halves so the dispatch fired lower than the heading was the other candidate, and it left a thread reading closed while work was owed on it. The Testing question was first written to sit outside both, which is that same split reached from the other side, and it left the one party who could answer the question with no route to it.
|
|
210
|
+
|
|
211
|
+
The cost is that the merge decision no longer reads off the heading alone, since an open heading covers a minor as well as a critical. Take it from the counts on the summary line, which is where they already sit. No summary line reports the merge as unblocked under either heading, since a thread reading open cannot also report that nothing blocks it.
|
|
212
|
+
|
|
213
|
+
A minor the dispatched worker declines is what needs a surface that survives the merge, rather than every minor, since one that gets fixed on the branch needs no durable record. Write a declined minor into the `## Findings` section of the task the branch closes, which is where the queue-refill sweep already routes a finding that changes another task. A declined finding left on the thread alone is lost the moment the pull request merges.
|
|
214
|
+
|
|
215
|
+
Read the state off the most recent review comment rather than off the presence of a closed one. A close-out does not close the pull request, so a commit pushed after it gets its own pass, and that pass reopens the review under `## Review` when it raises a finding of any grade.
|
|
216
|
+
|
|
217
|
+
Both of this skill's headings anchor as a section distinct from human threads, and neither invents beyond what the whole set already states. That set is five headings across two families, stated here once so `claude-orchestrate`'s poll and every reply-posting skill cite it rather than carry a copy. The review family, `## Review` and `## Review closed`, belongs to this skill alone, and the reply family, `## Review response`, `## Rebase`, and `## Post-review findings`, belongs to `claude-address-review`.
|
|
218
|
+
|
|
219
|
+
The first reply heading answers a finding this skill posted, the second reports a stale branch resolved without one, and the third carries a finding a worker produces after a close-out rather than in answer to one already on the thread, since a finding produced late is still a finding. A comment posted under a heading outside these five reaches the poll as unclassified rather than as silence, so an invented sixth heading is a gap the next run reports instead of one it repeats. Do not append the PR number, which GitHub already renders above the comment.
|
|
220
|
+
|
|
221
|
+
Name the scope in every summary line after the first pass, since a reader cannot otherwise tell a narrow read from a full one. When the fallback in Step 2 fired, replace the commit count with `Re-reviewed the full change, the prior pass's commit is no longer on the branch`.
|
|
222
|
+
|
|
223
|
+
Budget the body. State each finding as the failure and the fix in two or three sentences, not a paragraph of reasoning.
|
|
224
|
+
|
|
225
|
+
Omit files with no findings. Do not lecture on process. The integration, contract, and consumer lenses stay, but as findings, not asides.
|
|
226
|
+
|
|
227
|
+
The `What is right` section is optional, capped at three bullets, and included only when it changes the merge decision. Drop it otherwise and let the summary line carry the approval.
|
|
228
|
+
|
|
229
|
+
Close the body with `🤖 Reviewed by Claude Code` on its own line so the review reads as an independent machine pass, not a human sign-off.
|
|
230
|
+
|
|
231
|
+
Before posting, run the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against the body. The hook skips `.claude/.tmp/`, so this scan is the only gate on the published comment. A finding phrased against an internal phase label is what the label half of the scan catches here.
|
|
232
|
+
|
|
233
|
+
Do not run the command below when `<prior-heading>` from Step 2 reads `## Review closed` and this pass carries nothing owed. That pass replaces the standing comment rather than adding one, under `### A close-out that repeats the standing one` at the end of this step. Posting first and reaching that section afterward leaves two close-outs both naming the new head, which is worse than the pair the guard exists against.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
gh pr review <number> --comment --body-file .claude/.tmp/pr-review/body-<number>-<short-sha>.md
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
A pass carrying nothing at all takes `## Review closed` and a short body, with the footer line included either way. On a first pass, post `✅ No findings. Reviewed against project docs and the board.` On a later pass, post `✅ Prior findings addressed. Re-reviewed <short-sha>, N commits since the prior pass.`
|
|
240
|
+
|
|
241
|
+
A pass carrying only minors is an ordinary finding-carrying pass, so it takes the open heading and the full shape rather than either short line, since the minors have to be readable and neither line reports them. A pass carrying only Testing questions, or only an unanswered reviewer request, takes the same route for the same reason. Keep whichever scope sentence the pass owes on the summary line:
|
|
242
|
+
|
|
243
|
+
```markdown
|
|
244
|
+
## Review
|
|
245
|
+
|
|
246
|
+
0 critical, 0 should-fix, Z minor. Reviewed against project docs and the board.
|
|
247
|
+
|
|
248
|
+
**`path/to/file.ext`**
|
|
249
|
+
|
|
250
|
+
- **minor**: finding, and the fix it wants.
|
|
251
|
+
|
|
252
|
+
🤖 Reviewed by Claude Code
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
A pass that closed by withdrawing a finding rather than by reading its fix takes neither ✅ line, per the withdrawal rule in Step 3. Both claim a fix landed, and the second names it, so posting either over a withdrawal credits work nobody did on the one comment a reader treats as the verdict. Write the withdrawal and the fact that settled it in place of the canned line, keeping the heading and the footer.
|
|
256
|
+
|
|
257
|
+
A pass whose only content is a `## For the reviewer` block with every bullet answered, and that owes nothing else, takes the same shape: `## Review closed`, the block in place of the canned line, and the footer. The heading reports what the branch author still owes rather than what the pass did, and an answer discharged in the same comment owes nothing back.
|
|
258
|
+
|
|
259
|
+
Post a close-out even when there is nothing to report. A review left with no closing comment reads as one nobody answered.
|
|
260
|
+
|
|
261
|
+
### A close-out that repeats the standing one
|
|
262
|
+
|
|
263
|
+
When `<prior-heading>` from Step 2 reads `## Review closed` and this pass carries nothing owed, the thread already holds this verdict. Replace the standing close-out rather than posting a second one beside it.
|
|
264
|
+
|
|
265
|
+
Resolve its numeric id. `gh pr view --json reviews` carries a GraphQL node id under `id`, which no REST route accepts, so read the id off the REST listing instead:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
gh api repos/{owner}/{repo}/pulls/<number>/reviews --jq '[.[] | select((.body // "") | split("\n")[0] | rtrimstr("\r") == "## Review closed")] | last | .id'
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Write the replacement body to `<body-file>`, the name Step 4 already derived at the top of this step, keeping the heading and the footer and naming what this pass covered on the scope line in place of what the old one covered. Derive that name the same way whichever path reached here, since the guard reads `<prior-heading>` alone and a repeated head resolves the third segment as usual. The folder then gains a record of every covered head rather than losing the one the standing comment named. Then replace the comment:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
gh api -X PUT repos/{owner}/{repo}/pulls/<number>/reviews/<review-id> -F body=@<body-file>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
`PUT` keeps the comment's timestamp and its position in the thread, so the verdict stays where a reader already found it and the thread gains no second entry. A submitted review cannot be deleted, which is why this rewrites the standing comment rather than posting a fresh one.
|
|
278
|
+
|
|
279
|
+
The guard fires on `## Review closed` alone. Two open passes carry different findings and both are worth reading, so a repeated `## Review` posts normally. A pass carrying anything owed posts normally too, under `## Review`, which is what keeps a finding raised after a close-out from being swallowed by the guard that exists for a silent one.
|
|
280
|
+
|
|
281
|
+
What the rewrite costs is the review's `commit.oid`, which `PUT` leaves at the commit the standing close-out was first submitted against. Step 2's `<prior-oid>` and the prior commit `poll.sh` derives both read that field, so the next pass reads a range wider than its delta and its commit count spans back to the pinned commit rather than covering the delta.
|
|
282
|
+
|
|
283
|
+
The poll's `SEEN` branch is the sharper half. It fires on `prior` equalling the head, which a pinned `commit.oid` never reaches, so an out-of-band pass over this pull request reports as `MOVED` for the rest of its life and never as already covered. That is one wasted dispatch per head move rather than a repeating one, since the poll gates its report on the head it wrote to its own baseline and not on `prior`. Each cost errs toward more reading, so neither is repaired here.
|
|
284
|
+
|
|
285
|
+
## Step 5: output
|
|
286
|
+
|
|
287
|
+
```plaintext
|
|
288
|
+
X critical, Y should-fix, Z minor. Posted to PR #<number>.
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Add `N Testing question(s) raised.` to that line when the Step 3 check raised any. The counts cover findings alone, so a pass whose only output was a question otherwise reports as silent to the session that drove it. That session is not who the question is addressed to, which is what the dispatch covers.
|
|
292
|
+
|
|
293
|
+
Add `N reviewer request(s) answered.` to that line when the PR body carried a `## For the reviewer` section. The counts and the Testing question line both cover something else, so a pass that only answered a request otherwise reports as silent too.
|
|
294
|
+
|
|
295
|
+
Report the merge decision as a plain recommendation in chat (merge, or address findings first). Do not merge.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: claude-review
|
|
3
|
+
description: What local review is for, the gaps it closes, and why it reports without fixing
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Claude review requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a branch ships on the confidence of the session that wrote it. Review happens in chat and evaporates, so the ship step has no receipt to gate on. What review does happen mixes style opinion with real defects at one severity, and a reader cannot tell which blocks the merge. Worst, a diff that resolves empty against a stale base reports a clean branch instead of admitting the skill could not see the work.
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- Read the project's own context before the diff, so a decision already settled is not reported as a defect
|
|
15
|
+
- Resolve the base ref once, preferring the remote over local `main`, and reuse it in the guard and the read
|
|
16
|
+
- Say when the baseline is unusable and name the narrowed scope, rather than letting a clean summary read as a clean branch
|
|
17
|
+
- Flag only what will cause incorrect behavior or break a documented rule
|
|
18
|
+
- Grade every finding, since the caller gates on the counts rather than on the prose
|
|
19
|
+
- Write the report to disk under a branch-derived slug, so what the ship step reads outlives the session
|
|
20
|
+
|
|
21
|
+
## Must not
|
|
22
|
+
|
|
23
|
+
- Fix, rewrite, or suggest a refactor outside a finding. Reporting is the whole job.
|
|
24
|
+
- Flag style, linter territory, or anything resting on unverified state. A false positive erodes trust in the pass.
|
|
25
|
+
- Substitute the whole tree for a missing baseline
|
|
26
|
+
- Repeat the full report in chat. The file is the report and a chat copy of it goes stale immediately.
|
|
27
|
+
- Stage or commit the receipt, which is gitignored scratch
|
|
28
|
+
- Auto-trigger on a vague signal. Require an explicit request or a pipeline invocation.
|
|
29
|
+
|
|
30
|
+
## Guards
|
|
31
|
+
|
|
32
|
+
- The staged set, the branch set, and the working set are all empty: stop with a pass
|
|
33
|
+
- Baseline unusable: continue on the uncommitted set and lead the report with the warning
|
|
34
|
+
|
|
35
|
+
## Out of scope
|
|
36
|
+
|
|
37
|
+
- Reviewing an open pull request, which `claude-pr-review` owns. The split is by vantage: this one reviews local work for the session that wrote it and writes to disk.
|
|
38
|
+
- Deciding whether the findings block the ship. This skill grades and the caller gates.
|
|
39
|
+
- Fixing anything it found, which `claude-address-review` owns once the work is on a pull request
|