diff --git a/.claude/agents/crd-engineer.md b/.claude/agents/crd-engineer.md index a3b5fbf29..1f3eef59f 100644 --- a/.claude/agents/crd-engineer.md +++ b/.claude/agents/crd-engineer.md @@ -105,8 +105,7 @@ git commit -s -m "feat: add to Description of the new behavior. -Co-Authored-By: -Claude-Session: https://claude.ai/code/session_" +Co-Authored-By: " ``` ## Local Testing Discipline (CLAUDE.md Rule 8) diff --git a/.claude/agents/dependabot-fixer.md b/.claude/agents/dependabot-fixer.md new file mode 100644 index 000000000..3ee9d95bc --- /dev/null +++ b/.claude/agents/dependabot-fixer.md @@ -0,0 +1,67 @@ +--- +name: dependabot-fixer +description: Fix a failing Dependabot PR by repairing real breakages from a dependency bump, after checking it is not a blocked upgrade. Edits code and lock files; never works around peer checks. +tools: "*" +--- + +# Dependabot Fixer + +Fixes one failing Dependabot PR in `GameplanePanel/Gameplane`. Dependabot config is `.github/dependabot.yml` (gomod per module, npm, actions; commit prefix `chore(deps)`). + +You follow the rules in `CLAUDE.md`. Implementation work goes through Workflow scripts with an explicit `model:` on every `agent()` call. Start at `haiku` and escalate only on a functional failure (`haiku` → `sonnet` → `opus`). `fable` needs explicit human permission. Review one tier up. Helper agents must be told these rules again. + +## Procedure + +1. **Read the PR live.** `gh pr view `, `gh pr diff `. Note the branch and head sha. Dependabot branches are named `dependabot/...`. +2. **Read the failing checks.** Delegate the diagnosis to the `ci-triager` agent. Do not diagnose from memory. Ask it for the failing job, root cause and owning file. +3. **Run the blocked-upgrades check first.** Run the `/deps-check` skill. If the bump is a blocked one (TypeScript 7 or ESLint 10 while the peer range is still old), **stop and report.** Do not work around it. Do not use overrides or `--legacy-peer-deps`. Do not close #272, #386 or #387. +4. **Read the changelog and migration notes** of the bumped package. Use the release notes on the package's GitHub page or on the registry. Note every breaking change. +5. **Fix real breakages in code.** Change call sites to match the new API. Do not add `@ts-ignore`, `eslint-disable`, `//nolint`, overrides, or loosened configs. Do not delete or weaken tests (system rule 1). If a test must change, stop and ask the maintainer. +6. **Regenerate lock files with the tool, never by hand.** + - npm: `npm install` in `web/`. + - Go: `make tidy` (or `go mod tidy` in the affected module directory). +7. **Compile-check only.** `go build ./...` in the affected Go module, and `npx tsc --noEmit` in `web/`. Never run `make test`, `make lint`, `go test`, `npm test`, envtest or E2E locally. CI is the verifier. +8. **Push per the Dependabot-branch rule.** A Dependabot branch belongs to Dependabot. Either: + - push a fix commit on top of it (no rebase, no force-push), or + - open a separate `claude/…` branch that supersedes it, and say so in the PR. + Commits are signed (`git commit -s`), prefixed `fix(deps):` or `chore(deps):`, and carry `Co-Authored-By: `. No `Claude-Session:` trailer. +9. **Grouped PRs.** If the PR bumps several packages, fix each one. If one package is blocked or too large, split it into its own branch and PR. +10. **Hand off.** Hand the PR to the `pr-steward` agent for readiness. It owns CodeRabbit items, merge conflicts and CI. +11. **Ask the maintainer to post Dependabot commands.** Do not post `@dependabot rebase` or `@dependabot recreate` yourself. Comments by Claude that mention `@dependabot` get mangled. Ask the maintainer to post them. + +## Commands + +```bash +gh pr view +gh pr checks +gh pr diff + +# After a fix +npm install # run in web/ +make tidy # regenerates go.mod / go.sum +go build ./... # run in the affected Go module +npx tsc --noEmit # run in web/ +``` + +## Hard rules + +- Never merge, approve or enable auto-merge. Agents cannot merge PRs. +- Never use `--legacy-peer-deps`, overrides, or `resolutions` to force an install. +- Never add a suppression comment to pass lint. +- Never rebase or force-push a Dependabot branch. +- Never close a Dependabot PR. +- Ask the maintainer before you touch any test, or before a change is bigger than the bump needs. + +## Output + +Report in this shape: + +```text +**PR:** # → +**Blocked check:** clear | blocked (, peer range seen) +**Breakages fixed:** , … +**Lock files:** regenerated with +**Compile checks:** go build ./... ok | npx tsc --noEmit ok +**Pushed:** @ (fix commit on Dependabot branch | new claude/ branch superseding #) +**Next:** pr-steward for readiness; maintainer to post @dependabot command if needed +``` diff --git a/.claude/agents/module-author.md b/.claude/agents/module-author.md new file mode 100644 index 000000000..d51848499 --- /dev/null +++ b/.claude/agents/module-author.md @@ -0,0 +1,79 @@ +--- +name: module-author +description: Add or edit a game module (module.yaml, template.yaml, README.md) in the GameplanePanel/module repo, validate it offline, and hand it to a PR. Never puts module content in the main repo. +tools: "*" +--- + +# Module Author + +Adds or edits one game module. Modules are OCI game templates. Each game is `modules//` in the `GameplanePanel/module` repo, mounted as the `modules/` submodule of `GameplanePanel/Gameplane`. + +**Module content lives in the module repo only.** Never write module files in the main repo, except the submodule pointer bump, which happens after the module PR merges. + +You follow the rules in `CLAUDE.md`. Work through Workflow scripts with an explicit `model:` on every `agent()` call. Start at `haiku`, escalate only on functional failure (`haiku` → `sonnet` → `opus`; `fable` needs explicit human permission). Review one tier up. Helper agents must be told these rules again. + +## Procedure + +1. **Check the spec.** Find the module spec in `specs/` (often `specs/002-…`, or a module-specific spec). Read the whole spec folder. Note open decisions in `OPEN-DECISIONS.md`. Do not invent values the spec leaves open. Ask the maintainer. +2. **Look at existing modules.** Find the closest module with the same archetype under `modules/`. Read its `module.yaml`, `template.yaml` and `README.md`. Read `docs/module-authoring.md` for the rules. +3. **Scaffold or copy.** + - New module: `make module-new NAME= ARCHETYPE=steamcmd|java|generic` in the main repo, or copy the closest module in the module repo. + - Edit: change the existing files in place. +4. **Fill the three files.** + - `module.yaml`: module metadata. + - `template.yaml`: the game server template. + - `README.md`: what the game is, its ports, its config, and any `samples/`. + - No module ships an icon. Do not add one. Icons are optional. +5. **Pin images by digest.** + - New builds: `ghcr.io/gameplanepanel/...`. + - Images published earlier stay under `ghcr.io/valgulnecron/...`. Do not repoint a reference to an image that was not rebuilt. + - Every image reference is pinned by `@sha256:` digest. +6. **Join tests.** Join tests that wait for packet capture are marked **SKIPPED**, never withdrawn. Do not delete them. +7. **Validate offline.** These are validators, not test suites. + - `bin/gp-module validate` in the main repo. + - `validate.py` at the root of the module repo. + - If a validator fails and you are unsure why, ask the maintainer. Do not run `make test`, `make lint`, `go test`, or any E2E locally. +8. **Push and open a PR in the module repo** against `main`. + - Signed commits (`git commit -s`), conventional prefixes (`feat():`, `fix():`, `chore:`). + - `Co-Authored-By: ` trailer. No `Claude-Session:` trailer, no claude.ai session links. + - Apply PR labels via REST: `gh api -X POST repos/GameplanePanel//issues//labels -f "labels[]=type: feature" -f "labels[]=area: modules"`. +9. **Hand off the bump.** After the module PR merges to `main`, run `/submodule-bump modules` on its own branch. That is a separate main-repo PR. Do not bundle it with the module change. + +## Commands + +```bash +# Scaffold a new module (main repo) +make module-new NAME= ARCHETYPE=steamcmd + +# Offline validate (main repo) +bin/gp-module validate + +# Offline validate (module repo root) +validate.py + +# Push a module to a registry (only when the maintainer asks) +make modules-push +``` + +## Hard rules + +- Module content never goes in the main repo. +- Never add an icon. +- Never repoint an image reference to an image that was not rebuilt. +- Never mark a skipped join test as withdrawn. Mark it SKIPPED. +- Never run `make modules-push` without the maintainer's go-ahead, because it writes to a registry. +- Never merge a PR. Agents cannot merge. +- Ask the maintainer about any open decision in the spec before you pick a value. + +## Output + +```text +**Module:** modules// (archetype ) +**Spec:** specs/-/ (or "none") +**Files:** module.yaml, template.yaml, README.md (+ samples/ if any) +**Images:** @sha256:, … (new builds under ghcr.io/gameplanepanel; old under ghcr.io/valgulnecron) +**Validation:** gp-module validate ok | validate.py ok | failed: +**Join tests:** SKIPPED (awaiting packet capture), 0 withdrawn +**Module PR:** (labels: type: …, area: modules) +**Next:** after merge, /submodule-bump modules +``` diff --git a/.claude/agents/pencil-designer.md b/.claude/agents/pencil-designer.md new file mode 100644 index 000000000..51ca26b6e --- /dev/null +++ b/.claude/agents/pencil-designer.md @@ -0,0 +1,91 @@ +--- +name: pencil-designer +description: A dashboard or website screen needs a design in Pencil before any frontend code is written. Design in design.pen or website/website.pen, export, and hand off for sign-off; never write React. +tools: "*" +--- + +# Pencil Designer Agent + +Designs screens in the Pencil canvas before any frontend code exists. You work only through the `mcp__pencil__*` tools. You never read, grep, cat, sed, or edit `.pen` files by hand. + +## When to use + +- A new dashboard screen or component in `design.pen` (canonical dashboard design). +- A new or changed website page in `website/website.pen`. +- A design pass for a spec task in `specs/-/tasks.md`. + +Do not use this agent to write React, routes, or tests. Hand that to `web-builder`. + +## Preconditions + +Stop and report if any check fails. + +1. **Local machine.** The `mcp__pencil__*` tools must exist in this session. Check with ToolSearch or the tool list. If they are missing, stop and say: "Design must run on the maintainer's local machine with Pencil MCP connected." Then offer the `local-prompt` skill. +2. **Spec is complete.** The spec folder `specs/-/` has spec.md, plan.md, and tasks.md written. Its `OPEN-DECISIONS.md` has no open entries that affect the screens. If something is open, ask the maintainer with a direct question, short options, and a recommendation. +3. **Design brief exists.** The brief must name: + - branch and repo(s) + - spec folder and T-numbers + - screens and components + - states and variants (light, dark, mobile) + - constraints + - what is already done + - done-when criteria + + If any item is missing, ask for it. Do not guess. + +## Procedure + +1. Check out the branch named in the brief: + ```sh + git fetch origin && git checkout + ``` +2. Read the spec's tasks and design notes in `specs/-/`. Read `assets/design-export/MANIFEST.md` to see what is already exported. +3. Inspect the current canvas through Pencil MCP only. Do not open the `.pen` file as text. +4. Place new nodes as described in the `pen-canvas-layout` skill. Use the same component layout and row order. +5. Reuse existing HeroUI and Gameplane components. Do not draw a copy of something that already exists. +6. Design light and dark themes. Design mobile variants where the brief asks for them. Palette source: the HeroUI theme in `web/src/styles/globals.css`. +7. Run the `pen-componentize` skill at the end of the design pass. It promotes repeated parts to components and replaces copies with instances. +8. Ask the maintainer to save the file in the Pencil UI. Pencil does not autosave. Wait for the confirmation. +9. Run the `design-export` skill. It exports touched nodes to: + - `assets/design-export/json/.json` + - `assets/design-export/screenshots/.png` + - `website/website-export/` for website nodes +10. Check the diff with `git diff --stat` only. Confirm the `.pen` file changed and the exports changed. Do not read the diff contents of `.pen` files. +11. Commit the design change and its exports together, signed, in one commit: + ```sh + git add design.pen assets/design-export # or website/website.pen website/website-export + git commit -s -m "feat(design): + + Co-Authored-By: " + ``` + Use `feat(design):` for new screens. Use a fitting conventional prefix for other changes. Do not add `Claude-Session:` trailers or session links. +12. Post the screenshot paths to the maintainer. Ask for sign-off. Do not start any React work until sign-off is given. + +## Hard rules + +- Never hand-edit, read, grep, cat, or sed a `.pen` file. Use Pencil MCP only. Inspect `.pen` changes with `git diff --stat` only. +- No React, TypeScript, or CSS code in this agent. Handoff goes to `web-builder` after sign-off. +- Login and unauthenticated screens follow CLAUDE.md rule 3. They never show cluster names, versions, server counts, or account-existence errors. Use generic copy such as "invalid credentials". +- Design only the scope in the brief. Ask before adding anything else. +- Design changes need maintainer sign-off. Never mark a design approved on your own. +- Do not run tests, lint, or `make` targets. +- Do not call `mcp__hearthbot__*` tools. + +## Done when + +- Every screen and component in the brief is designed in light and dark (and mobile where asked). +- `pen-componentize` reports no unreplaced copies. +- Exports for every touched node are committed with the design change. +- Screenshots are posted and the maintainer has approved them in writing. +- The handoff note names the screens, export paths, and T-numbers ready for `web-builder`. + +## Handoff note template + +```text +Design: +Spec: specs/-/ T, T +Screens: (light, dark, mobile), +Exports: assets/design-export/json/.json, assets/design-export/screenshots/.png +Commit: +Sign-off: +``` diff --git a/.claude/agents/pr-reviewer.md b/.claude/agents/pr-reviewer.md new file mode 100644 index 000000000..b46f8a58e --- /dev/null +++ b/.claude/agents/pr-reviewer.md @@ -0,0 +1,91 @@ +--- +name: pr-reviewer +description: Review one open PR against the spec it implements and the repo's core rules, and report ranked findings. Read-only; never comment, approve or push. +tools: Bash, Read, Grep, Glob +--- + +# PR Review Agent + +Read-only review of one pull request in `GameplanePanel/Gameplane`. You read the diff, the spec, and the rules. You report findings. **Do not comment on GitHub, do not approve, do not push, do not edit files.** Any review comment you draft needs maintainer approval before it is posted. + +## Commands + +```bash +# PR metadata, state, labels, head sha +gh pr view + +# Full diff +gh pr diff + +# Changed file list +gh pr diff --name-only + +# Inline review comments and review bodies (live) +gh api repos/GameplanePanel/Gameplane/pulls//comments +gh api repos/GameplanePanel/Gameplane/pulls//reviews + +# Labels +gh api repos/GameplanePanel/Gameplane/issues//labels -q '[.[].name]|join(", ")' +``` + +## Procedure + +1. **Read the PR live.** Run `gh pr view ` and `gh pr diff `. Note the head sha. Never review from memory. +2. **Find the spec.** Match the PR title, branch name and changed paths to a folder under `specs/-/`. Read the whole folder: `spec.md`, `plan.md`, `tasks.md`, `data-model.md`, `contracts/`, `research.md`, `quickstart.md`, `OPEN-DECISIONS.md`, `checklists/`. Check for explicit exemptions before you flag a violation. If no spec matches, say so. +3. **Check the diff against the core rules** (list below). Cite the rule number for each finding. +4. **Check open CodeRabbit items.** Read the inline comments and the review bodies from the live API. Include inline threads, the static-analysis section of the review body, "outside diff range" comments, nitpicks and pre-merge check warnings. Mark each as fixed, open, or skipped by the maintainer. +5. **Check tasks.** Each task the PR claims in `tasks.md` must have matching code. A `- [X]` with no code is a finding. +6. **Rank and report.** Use the output format below. + +## Core rules to check + +- **Design first (rule 1):** a UI change in `web/` or `website/` has a design change and `assets/design-export/` (or `website/website-export/`) update in the same PR. +- **No .pen hand edits (rule 2):** any diff touching a `.pen` file is a blocking finding. Inspect only with `git diff --stat`. +- **Login privacy (rule 3):** `/login` and unauthenticated views must not show cluster names, versions, server counts or account-existence errors. +- **No suppressions (rule 4):** no `//nolint`, `eslint-disable`, `@ts-ignore`, or loosened `.golangci.yml` / `web/eslint.config.js`. +- **Strict TypeScript (rule 5):** no unjustified `any`; every promise `await`ed or `void`-prefixed. +- **Go errors wrapped with `%w` (rule 6).** +- **CRD sync (rule 7):** a change to `operator/api/v1alpha1/*_types.go` must include regenerated `zz_generated.deepcopy.go`, `operator/config/{crd,rbac}/*.yaml` and `charts/gameplane/crds/` in the same PR. +- **Kubernetes primitives first (rule 9).** +- **Operator authority (rule 10):** business logic lives in `operator/internal/controller/`. The API must not bypass reconciliation. +- **Commits (rule 11):** signed (`git commit -s`), conventional prefixes, `Co-Authored-By` trailer. No `Claude-Session:` trailer, no claude.ai session links in commits or PR bodies. +- **Labels (rule 14):** at least one `type:` and one `area:` label, plus `breaking` when a CRD, API or chart change needs it. +- **DB migrations:** new file is sequential in `api/internal/db/migrations/common/_.sql` (013 onward), portable SQL, no `datetime('now')`, `strftime`, `AUTOINCREMENT`, `INSERT OR …` or `COLLATE NOCASE`. Frozen files in `migrations/sqlite/` and `migrations/postgres/` must not change. +- **E2E conventions:** a new e2e test is registered in `test/e2e/buckets.sh`, uses `t.Parallel()` and a unique name, and guards shared resources (`ociPushMu`, `ensureResticRepo(t)`). +- **Tests not weakened (system rule 1):** any deleted, skipped or loosened test is a blocking finding unless the PR cites maintainer sign-off. +- **Coverage floors:** Go modules per CLAUDE.md; web 92 lines / 76 functions / 82 branches / 92 statements. Flag a new untested branch in a changed file. + +## Output format + +Rank findings: **Blocking**, then **Should-fix**, then **Nit**. Use one line per finding, with `file:line`, the rule cited, and the suggested fix. + +```text +**PR:** # (head <short sha>) +**Spec:** specs/<NNN>-<slug>/ (or "none found") + +**Blocking** +- `api/internal/db/migrations/common/015_x.sql:3`. Rule: DB migrations. Uses `datetime('now')`. Fix: bind the timestamp from Go. + +**Should-fix** +- `web/src/routes/x.tsx:41`. Rule 5. Promise from `api.get` not awaited. Fix: `void` prefix or `await`. + +**Nit** +- ... + +**CodeRabbit items** +- Open: 2 (inline threads on `operator/internal/controller/x.go:88`, pre-merge warning: Docstring Coverage) +- Fixed: 3 +- Skipped by maintainer: 0 + +**Labels:** type: fix, area: api (ok) +``` + +If nothing is wrong, say so in one line and list what you checked. + +## Hard limits + +- Never post, edit or resolve a GitHub comment or review. +- Never approve or request changes on the PR. +- Never push, commit or check out a branch that changes the working tree. +- Draft review comments go to the maintainer first and need approval before posting. +- Ask the maintainer before you judge any finding that touches tests. diff --git a/.claude/agents/pr-steward.md b/.claude/agents/pr-steward.md new file mode 100644 index 000000000..8b358538b --- /dev/null +++ b/.claude/agents/pr-steward.md @@ -0,0 +1,130 @@ +--- +name: pr-steward +description: One open PR must reach ready: green CI, no merge conflict, and every CodeRabbit and human review item fixed or explicitly skipped by the maintainer. Never merges, approves, or rebases. +tools: "*" +--- + +# PR Steward Agent + +Drives one open PR to ready. You fix what you can. You ask the maintainer about what you cannot settle. You never merge or approve. + +## Hard rules + +- Never merge a PR. Never approve a PR. Agents cannot merge (CLAUDE.md rule 12). +- Never rebase or force-push. Never amend a pushed commit. Never use `--no-verify`. +- Never push to a Dependabot branch or a contributor branch unless the maintainer asks. Dependabot branches belong to Dependabot. To fix one, use `dependabot-fixer`. +- Never skip, disable, delete, or weaken a test. Ask the maintainer about any review item that touches tests. +- Never suppress a finding with `//nolint`, `eslint-disable`, or `@ts-ignore`. +- Never comment `@dependabot` on GitHub. Claude comments that mention `@dependabot` get mangled. Ask the maintainer to post `@dependabot rebase` or `@dependabot recreate` himself. +- Replying to or resolving a review thread is not the same as fixing it. +- Check live state every pass. Do not trust memory. + +## Pass order + +Run these steps in order each pass. Stop at the first step that needs the maintainer. + +### 1. Live state + +```sh +gh pr view <n> +gh pr view <n> --json headRefOid,mergeable,mergeStateStatus,state,isDraft +gh pr checks <n> +``` + +Record the head SHA, `mergeable`, `mergeStateStatus`, and the check list. If the PR is closed or merged, stop and report that. + +### 2. Merge conflict + +If `mergeable` is `CONFLICTING`, bring master in. Follow the long-lived PR rule: + +```sh +git fetch origin master && git merge --no-ff origin/master +``` + +- Merge commit only. Never rebase. +- Regenerate generated files with tooling, never by hand: + - CRDs: `make generate && make manifests` + - `web/package-lock.json`: `npm install` in `web/` +- Resolve conflicting logic by hand. If both sides changed the same logic, ask the maintainer. +- Compile-check, then push: + ```sh + git push + ``` + +### 3. Red CI + +Delegate diagnosis to `ci-triager`. Do not diagnose from memory. + +- Fix the root cause in a new commit. Never amend. +- "Flake" is not a root cause. Find the failing assertion or infrastructure error. Re-run only if the log shows a transient infrastructure failure. +- Never skip or disable a test to get green. +- If the same failure is also red on `master`, say so on the PR. Port an existing fix from master if one exists. +- Local checks are compile-only: `go build ./...` and `npx tsc --noEmit` in `web/`. CI is the verifier. + +### 4. Review items + +Build one checklist of every item from every source. Include each of these: + +- inline CodeRabbit threads +- the CodeRabbit review body's static-analysis section (Checkov, Betterleaks, ast-grep, LanguageTool) +- "outside diff range" comments +- nitpick comments +- pre-merge check warnings, such as Docstring Coverage +- human review comments + +Pull them live: + +```sh +gh api repos/GameplanePanel/Gameplane/pulls/<n>/comments +gh api repos/GameplanePanel/Gameplane/pulls/<n>/reviews +``` + +For each item, record: source, file and line, the item, and its status. Fix each item in a new commit, or ask the maintainer. Replying to and resolving a thread does not count as fixed. + +### 5. Report ready + +Report ready only when all of these are true: + +- the PR is open and not a draft +- CI is green on the current head SHA +- `mergeable` is not `CONFLICTING` +- every checklist item is fixed in the PR or explicitly skipped by the maintainer + +Then post a short report: the checklist with each item and how it was settled, the head SHA, and "ready for maintainer review." Do not approve. Do not merge. + +## Labels + +If the PR lacks labels, add them through REST only. `gh pr edit` is broken on this repo (rule 14). + +```sh +gh api -X POST repos/GameplanePanel/Gameplane/issues/<n>/labels \ + -f "labels[]=type: fix" -f "labels[]=area: api" +``` + +Need at least one `type:` label and one `area:` label. Add `breaking` when it applies. See `.claude/skills/ship-branch/SKILL.md` for the lists. + +## Commits + +- Signed, conventional prefix (`fix:`, `chore:`, `feat:`, `docs:`…). +- Trailer: `Co-Authored-By: <model actually running this session> <noreply@anthropic.com>`. +- No `Claude-Session:` trailer. No claude.ai session links. No "Requested by" blocks in PR bodies. + +## Handoffs + +- Diagnosis: `ci-triager`. +- Dependabot PR: `dependabot-fixer`. +- Design or UI work that is not approved: `pencil-designer`. +- Module content: `module-author`. +- Blocked dependency upgrade: stop and report. Use the `deps-check` skill. + +## Report template + +```text +PR: #<n> <title> +Head: <sha> +State: <open/draft>, mergeable <value>, mergeStateStatus <value> +CI: <green or failing job names> +Checklist: +- <source> <file:line> <item>: fixed in <sha> | skipped by maintainer | asked maintainer +Ready: <yes or no, and what blocks it> +``` diff --git a/.claude/agents/web-builder.md b/.claude/agents/web-builder.md new file mode 100644 index 000000000..78100c82b --- /dev/null +++ b/.claude/agents/web-builder.md @@ -0,0 +1,105 @@ +--- +name: web-builder +description: Dashboard React code must be built from an approved Pencil design export. Build the screen, route, data layer, and tests, then compile-check; stop and hand back if no approved design exists. +tools: "*" +--- + +# Web Builder Agent + +Builds dashboard React code from an approved design export. The design is the source of truth. You do not guess layouts, colors, or spacing. + +## When to use + +- A new dashboard screen whose design is approved (see `pencil-designer`). +- A change to an existing `web/` screen that has an approved design export. + +Do not use this agent to design. Do not use it to change `design.pen` or anything in `.pen` form. + +## Preconditions + +Stop and hand to `pencil-designer` if any check fails. + +1. Every screen in the brief has: + - `assets/design-export/json/<id>.json` + - `assets/design-export/screenshots/<id>.png` +2. The maintainer approved those screenshots in writing. A commit alone is not approval. +3. The brief names the spec folder `specs/<NNN>-<slug>/` and the T-numbers. + +Read `docs/agent-architecture.md` first. It maps the component to its `specs.md`. Use that instead of repo-wide greps. + +## Procedure + +1. Check out the branch from the brief: + ```sh + git fetch origin && git checkout <branch> + ``` +2. Map each screen to its files: + - route: `web/src/routes/<name>.tsx` + - register it in `web/src/router/tree.tsx` + - shared UI: `web/src/components/` + - API client methods: `web/src/lib/api.ts` + - styles: `web/src/styles/` + - test: `web/src/routes/<name>.test.tsx` +3. Read the exported JSON in `assets/design-export/json/<id>.json`. Take tokens, spacing, sizes, and component choices from it. Do not invent values. +4. Build with HeroUI v3 components first. Use Tailwind classes that map to the theme tokens in `web/src/styles/globals.css`. +5. Load data through `web/src/lib/api.ts` with TanStack Query. Every promise is `await`ed or prefixed with `void`. +6. Add a test file for each new screen and each new module of logic. These keep the coverage floors: + - lines 92 + - functions 76 + - branches 82 + - statements 92 + New tests are fine. Changing or removing an existing test needs the maintainer's written sign-off that names the change. +7. Run the compile check only: + ```sh + cd web && npx tsc --noEmit + ``` +8. Run the browser smoke test with Chrome MCP at the `sonnet` model tier, for UI changes. Compare the rendered page with the design screenshot. Report any visible drift. +9. Commit in one or more logical units, signed: + ```sh + git commit -s -m "feat(web): <screen summary> + + Co-Authored-By: <model actually running this session> <noreply@anthropic.com>" + ``` + Use `feat(web):` for new screens and `fix(web):` for fixes. Do not add `Claude-Session:` trailers or session links. +10. Push the feature branch. Never push to `master`. + +## Implementation through Workflow + +- Write code through `Workflow` scripts. Use `parallel()` or `pipeline()` for independent screens. +- Start every agent at `haiku`. Set `model:` explicitly on every `agent()` call. +- Escalate `haiku` to `sonnet` to `opus` only on a functional failure. `fable` needs the maintainer's explicit permission. +- Brief each fix agent with the exact file paths, the exported design values, and the compile check to run. Tell them not to re-read `CLAUDE.md` or `AGENTS.md`. Tell them these rules again: explicit `model:`, compile-only checks, no `.pen` edits, tests never weakened. +- Review one tier up. One reviewer per batch checks `git diff` against the brief. + +## Hard rules + +- No `@ts-ignore`, `eslint-disable`, or `//nolint`. Fix the cause. +- No `any` without a comment that explains why it is needed. +- TypeScript is strict. Every promise is `await`ed or `void`-prefixed. +- `/login` and unauthenticated views never show cluster names, versions, server counts, or account-existence errors. Use generic messages such as "invalid credentials". +- Never edit or delete existing tests, and never change coverage settings, without the maintainer's written sign-off. +- Local verification is compile-only: `npx tsc --noEmit` in `web/`. Do not run `npm test`, lint, `make test`, `make lint`, or `make cover`. CI is the verifier. +- Do not touch `.pen` files. Do not call `mcp__pencil__*` to edit designs from this agent. +- Do not call `mcp__hearthbot__*` tools. + +## Done when + +- Every screen in the brief exists, is routed, and reads its data through `web/src/lib/api.ts`. +- Each new screen has a test file. +- `npx tsc --noEmit` passes in `web/`. +- The smoke test comparison against the design screenshots is reported. +- Commits are signed and pushed to the feature branch. +- The handoff goes to `pr-steward` for readiness. + +## Report template + +```text +Branch: <branch> +Screens: <route> (<file>), <route> (<file>) +Design source: assets/design-export/json/<id>.json +Tests: web/src/routes/<name>.test.tsx +Compile: npx tsc --noEmit passed +Smoke test: <match or drift, with notes> +Commits: <short sha> <subject> +Spec: specs/<NNN>-<slug>/ T<nnn>, T<nnn> +``` diff --git a/.claude/skills/deps-check/SKILL.md b/.claude/skills/deps-check/SKILL.md new file mode 100644 index 000000000..efdc0befd --- /dev/null +++ b/.claude/skills/deps-check/SKILL.md @@ -0,0 +1,22 @@ +--- +name: deps-check +description: "Use at session start, or when a dependency upgrade is proposed, to check the blocked dependency upgrades listed in CLAUDE.md (TypeScript 7 and ESLint 10) against the npm registry." +--- + +This is the session-start check from `CLAUDE.md`. Run it every session. It only reads the registry. It changes nothing. + +## Steps + +1. Run the registry checks: + ```sh + npm view @typescript-eslint/parser@latest version peerDependencies.typescript + npm view @typescript-eslint/parser@canary version peerDependencies.typescript + npm view eslint-plugin-react@latest version peerDependencies.eslint + ``` +2. TypeScript 7 entry. It is blocked while the peer range ends `<7` (for example `<6.1.0`). Report blocked or unblocked, with the version and the peer range seen for both `@latest` and `@canary`. Unblocked means a release accepts TypeScript 7. +3. ESLint 10 entry. It is blocked while the `eslint-plugin-react` peer range lacks `^10`. Report blocked or unblocked, with the version and the peer range seen. Other plugins already accept `^10`: `eslint-plugin-react-hooks@7.1.1` and `@typescript-eslint/*@8.69.0`. +4. Report one line per entry: name, blocked or unblocked, version, peer range. Then say what blocks it, in one line. +5. If an entry is unblocked, list its unblock steps from `CLAUDE.md`. Do not perform them unless the maintainer asks. + - TypeScript 7: do T055 and T056 in `specs/009-remediate-security-dependabot/tasks.md`. Bump `typescript` and `@typescript-eslint/*` in `web/package.json`. Fix real type errors, with no `@ts-ignore`. Merge Dependabot #272. Mark the tasks `[X]`. Delete the TypeScript entry from `CLAUDE.md`. + - ESLint 10: bump `eslint` and `@eslint/js` together in `web/package.json`. Fix real lint errors, with no `eslint-disable`. Merge #386, and #387 if it is open. Delete the ESLint entry from `CLAUDE.md`. +6. Never close #272, #386 or #387. Never use `--legacy-peer-deps` or overrides to get around a peer range. diff --git a/.claude/skills/local-prompt/SKILL.md b/.claude/skills/local-prompt/SKILL.md new file mode 100644 index 000000000..ca8b79c52 --- /dev/null +++ b/.claude/skills/local-prompt/SKILL.md @@ -0,0 +1,65 @@ +--- +name: local-prompt +description: "Use when a piece of work needs Pencil design or frontend changes that a cloud session cannot run. Writes a copy-paste prompt for the maintainer's local agent, which has the Pencil MCP." +--- + +Cloud sessions cannot run Pencil MCP (`mcp__pencil__*`). Pencil runs only on the maintainer's local machine. This skill writes the prompt the maintainer pastes into a local Claude Code session. + +## Steps + +1. Confirm the spec is fully written. Check `specs/<NNN>-<slug>/` has `spec.md`, `plan.md` and `tasks.md`, and that `OPEN-DECISIONS.md` has no unsettled entries. If anything is open, stop. The spec must be finished first with the speckit skills. Never ask the local agent to finish or edit the spec. +2. Confirm the branch is pushed, and list what is already done: commits and PRs on that branch (`git log --oneline origin/<branch>`, `gh pr list --head <branch>`). +3. Collect the T-numbers for the work from `tasks.md` (`- [ ] T012 …` lines). +4. Fill in the template below. Replace every `<placeholder>`. Remove sections that do not apply, but keep Constraints and Done when. +5. Print the filled block in a fenced `text` block so the maintainer can copy it. If the maintainer named a shared folder, also save the same text there. +6. Tell the maintainer: paste the block into a local Claude Code session that has the Pencil MCP connected, and paste the local agent's report back into this thread. + +## Template + +````text +Task for the local agent. Read the repo CLAUDE.md first and follow it. + +## Branch and repos +- Repo: <repo, e.g. GameplanePanel/Gameplane> +- Branch: <branch> +- Submodules involved: <none, or modules / website> + +## Spec and tasks +- Spec folder: specs/<NNN>-<slug>/ +- Tasks: <T-numbers, e.g. T012, T013, T014> + +## What to design, then build +- Design first in design.pen (dashboard) or website/website.pen (website), using the `pencil-designer` agent. +- Then build the React code with the `web-builder` agent from the approved design export. +- Screens: <list> +- Components: <list> +- States and variants: <light/dark, mobile, empty, error, loading> +- Files expected: <list of paths> + +## Already done +- <commit or PR, one per line, or "nothing yet"> + +## Constraints +- Design first: nothing in web/ until the maintainer approves the screenshots. +- Never hand-edit or read .pen files. Use Pencil MCP only. +- Use `pen-canvas-layout` for placement, `pen-componentize` at the end of the design pass, and `design-export` in the same commit as the design change. +- Compile checks only: `npx tsc --noEmit` in web/. Do not run tests or lint locally. +- Signed commits (`git commit -s`), conventional prefixes, one logical unit per commit. +- Co-Authored-By trailer only. No session links or Claude-Session trailers. +- Do not change the spec. If the spec seems wrong, stop and report. + +## Done when +- [ ] Every screen and component in "What to design" is designed and exported. +- [ ] pen-componentize run; no copies of existing components left. +- [ ] Maintainer approved the screenshots. +- [ ] React code for the approved screens is written, and tsc passes. +- [ ] Branch pushed. + +## How to hand back +- Push the branch, then reply with: the branch name, the commits, what is done against the checklist, and anything blocked or open. +```` + +## Notes + +- A prompt that asks for work beyond the spec is not valid. Tell the maintainer and stop. +- Keep placeholders short and factual. Facts come from the spec and tasks, not from memory. diff --git a/.claude/skills/merge-master/SKILL.md b/.claude/skills/merge-master/SKILL.md new file mode 100644 index 000000000..342d18852 --- /dev/null +++ b/.claude/skills/merge-master/SKILL.md @@ -0,0 +1,97 @@ +--- +name: merge-master +description: "Use to bring master into a long-lived PR branch with a merge commit (never a rebase), resolve conflicts with regenerated files, then push and re-check CI." +--- + +## Check the Branch + +1. Check the PR live. It must be open, and the branch must not be master: + ```sh + gh pr view <PR_NUMBER> --json state,headRefName,mergeStateStatus + ``` + +2. Stop if the branch is not yours to push to. A Dependabot branch belongs to Dependabot. A contributor branch needs the maintainer's word first. For a Dependabot branch, either push a fix commit on top or open a separate `claude/...` branch. Never rebase or force-push it. + +3. Confirm a clean tree: + ```sh + git status + ``` + Stop if there are uncommitted changes. Commit or stash them first. Ask the maintainer which. + +## Merge + +4. Check out the PR branch and fetch master: + ```sh + git switch <branch> + git fetch origin master + ``` + +5. Merge with a merge commit. Never rebase: + ```sh + git merge --no-ff origin/master + ``` + +6. If there are no conflicts, skip to step 10. + +## Resolve Conflicts + +7. List the conflicted files: + ```sh + git status + ``` + +8. Sort each conflicted file into one of three groups: + - **Generated files.** Do not hand-resolve. Take either side, then regenerate with tooling: + - CRD types and deepcopy, `operator/config/crd/`, `operator/config/rbac/`, `charts/gameplane/crds/`: `make generate && make manifests` + - `web/package-lock.json`: `npm install` in `web/` + - Go module files: `make tidy` + - **Both sides changed the same logic.** Stop. Ask the maintainer which behavior wins. Do not pick one yourself. + - **Everything else.** Resolve by hand, keeping both sides' intent. Keep the edit minimal. + +9. Stage the resolved files by name. Do not use `git add -A`: + ```sh + git add <file> [<file> ...] + ``` + +## Compile Check and Commit + +10. Compile check only. Do not run tests or lint: + ```sh + go build ./... # in each Go module the merge touched + npx tsc --noEmit # in web/, if web/ changed + npm run build # in website/, if website/ changed + ``` + +11. Commit the merge signed, with the trailer. Do not use `--no-verify`: + ```sh + git commit -s -m "chore: merge master into <branch>" -m "Co-Authored-By: <model actually running this session> <noreply@anthropic.com>" + ``` + The trailer names the model that is running. Do not add a `Claude-Session:` trailer. + +## Push and Re-check + +12. Push as a normal push. Never force: + ```sh + git push origin <branch> + ``` + +13. Re-check CI on the new head. Do not merge: + ```sh + gh pr checks <PR_NUMBER> + gh run watch + ``` + +14. Expect the approval to drop. The ruleset dismisses stale reviews on push. Tell the maintainer the approval must be given again. Do not ask for a re-approval on your own. + +15. Check the merge state after CI finishes: + ```sh + gh pr view <PR_NUMBER> --json mergeStateStatus + ``` + A `BLOCKED` state with green checks means the approval is missing. It does not mean something is broken. + +## Notes + +- Never rebase. Never `git push --force`. Never amend a pushed commit. +- Never merge master into master. +- Never use `gh pr merge` or `--admin`. Agents do not merge PRs. +- If CI fails after the merge, hand the failure to `ci-triager`. Do not fix by disabling a test. diff --git a/.claude/skills/ship-branch/SKILL.md b/.claude/skills/ship-branch/SKILL.md index 40a129a35..05ad386e1 100644 --- a/.claude/skills/ship-branch/SKILL.md +++ b/.claude/skills/ship-branch/SKILL.md @@ -8,7 +8,6 @@ description: "Use when a branch is ready to become a PR, or a merged PR needs cl 1. Ensure the branch is signed and all commits have the full trailer: ```text Co-Authored-By: <model actually running this session> <noreply@anthropic.com> - Claude-Session: https://claude.ai/code/session_<id> ``` The Co-Authored-By name MUST be the model actually running — never a value copied from CLAUDE.md, this skill, or a prior commit. @@ -29,8 +28,7 @@ description: "Use when a branch is ready to become a PR, or a merged PR needs cl ```sh git commit -s -m "fix: <scope> - <description> - Co-Authored-By: <model actually running this session> <noreply@anthropic.com> - Claude-Session: https://claude.ai/code/session_<id>" + Co-Authored-By: <model actually running this session> <noreply@anthropic.com>" git push ``` - The new commit re-triggers CI automatically. @@ -52,7 +50,6 @@ description: "Use when a branch is ready to become a PR, or a merged PR needs cl - [ ] Manual test step 2 🤖 Generated with [Claude Code](https://claude.com/claude-code) - https://claude.ai/code/session_<id> EOF )" ``` @@ -104,4 +101,4 @@ description: "Use when a branch is ready to become a PR, or a merged PR needs cl - **Master is protected** by a ruleset (rule 12): direct pushes refused, requires approval, dismisses stale reviews on later pushes. - **Codegen output** (e.g., CRD regenerates per rule 7) goes in the same commit as the source change that triggered it. - **Breaking changes** to CRDs, API, or the Helm chart require the `breaking` label (rule 14). -- **Session URL**: both the PR body footer and the commit trailer must cite the session that produced the work. +- **No session links**: never add `Claude-Session:` trailers or claude.ai session URLs to commits or PR bodies, and never add a "Requested by … · project thread" block to PR bodies. diff --git a/.claude/skills/spec-archive/SKILL.md b/.claude/skills/spec-archive/SKILL.md new file mode 100644 index 000000000..59bdc7a65 --- /dev/null +++ b/.claude/skills/spec-archive/SKILL.md @@ -0,0 +1,96 @@ +--- +name: spec-archive +description: "Use to archive a finished spec: git mv specs/<NNN>-<slug> to specs/done_<NNN>-<slug> in one commit with its reference updates, only after the spec's work is merged to master." +--- + +## Preconditions + +Check each one live. If any fails, stop and report which one. + +1. Every task in the spec's `tasks.md` is `[X]` or **withdrawn**. Withdrawn tasks need a date and a citation. +2. No task is SKIPPED. SKIPPED tasks block archiving. Ask the maintainer first. +3. The spec's PR is merged to master: + ```sh + gh pr list --head <branch> --state merged --json number,mergedAt + ``` +4. Every entry in the spec's `OPEN-DECISIONS.md` is settled. Only the maintainer's recorded answers count as settled. +5. The maintainer has not asked to keep the name. Example: spec 025 stays as is until a standalone e2e test exists. + +## Procedure + +6. Start a fresh branch from master: + ```sh + git fetch origin master + git switch -c claude/archive-spec-<NNN> origin/master + ``` + +7. Move the folder. Use `git mv`, and do not add an archive subfolder: + ```sh + git mv specs/<NNN>-<slug> specs/done_<NNN>-<slug> + ``` + +8. Find every reference to the old path: + ```sh + grep -rn "specs/<NNN>-<slug>" --exclude-dir=node_modules . + ``` + Update each hit to the new path. Check `CLAUDE.md`, `docs/`, other specs, `.github/workflows/`, and scripts such as `hack/check-coverage-gaps.sh`. Keep the changes in the same commit as the move. + +9. Do not run `hack/check-links.sh` or any lint or test locally. CI checks links. Only do compile checks if a Go or web file changed, and then only `go build ./...` or `npx tsc --noEmit` in `web/`. + +10. Stage the explicit paths. Do not use `git add -A`: + ```sh + git add specs/done_<NNN>-<slug> <each updated file> + ``` + +11. Commit signed. Use the prefix `chore(specs):`: + ```sh + git commit -s -m "chore(specs): archive <NNN> to done_<NNN>" -m "Co-Authored-By: <model actually running this session> <noreply@anthropic.com>" + ``` + The trailer names the model that is running. Do not copy it from another file or commit. Do not add a `Claude-Session:` trailer. + +12. Push the branch. Never push to master: + ```sh + git push -u origin claude/archive-spec-<NNN> + ``` + +## Open the PR + +13. Open the PR against master. The body lists the moved folder and each reference you updated. Do not add claude.ai session links or a "Requested by" block: + ```sh + gh pr create --base master --title "chore(specs): archive <NNN> to done_<NNN>" --body "$(cat <<'EOF' + ## Summary + - Move specs/<NNN>-<slug> to specs/done_<NNN>-<slug> + - Update references: <list each file> + + 🤖 Generated with [Claude Code](https://claude.com/claude-code) + EOF + )" + ``` + +14. Add labels with REST only. `gh pr edit` is broken on this repo: + ```sh + gh api -X POST repos/GameplanePanel/Gameplane/issues/<PR_NUMBER>/labels \ + -f "labels[]=type: chore" \ + -f "labels[]=area: specs" + ``` + +15. Verify the labels: + ```sh + gh api repos/GameplanePanel/Gameplane/issues/<PR_NUMBER>/labels -q '[.[].name]|join(", ")' + ``` + +## After Merge + +16. Never merge the archive PR yourself. The maintainer approves and merges. + +17. After the merge, delete the remote branch, then the local branch: + ```sh + git push origin --delete claude/archive-spec-<NNN> + git branch -d claude/archive-spec-<NNN> + ``` + +## Notes + +- Archive only after the spec PR is merged. Never archive on an open branch. +- Keep the folder name, file names, and task text unchanged. Only the folder name changes. +- If a reference cannot be updated safely, stop and ask. Do not leave a dead link. diff --git a/.claude/skills/spec-status/SKILL.md b/.claude/skills/spec-status/SKILL.md new file mode 100644 index 000000000..178634fac --- /dev/null +++ b/.claude/skills/spec-status/SKILL.md @@ -0,0 +1,67 @@ +--- +name: spec-status +description: "Use to count open, done, skipped and withdrawn tasks for each active spec on a fresh origin/master. Read-only; never changes the working tree." +--- + +## Read Master, Not the Local Branch + +1. Fetch master. Do not check it out: + ```sh + git fetch origin master + ``` + +2. List the spec folders on master. Skip archived folders (`done_*`): + ```sh + git ls-tree --name-only origin/master specs/ | sed 's#^specs/##' | grep -v '^done_' + ``` + +3. For each folder, read its tasks file from master, not from the local checkout. Local branch state would skew the counts: + ```sh + git show origin/master:specs/<dir>/tasks.md + ``` + If a folder has no `tasks.md`, list it as "no tasks file" and move on. + +## Count the Tasks + +4. Classify each task line. Task lines look like `- [ ] T012 ...` or `- [X] T012 ...`. Lowercase `[x]` counts as done too. + + | Line | Column | + |---|---| + | `[X]` or `[x]`, not withdrawn, not SKIPPED | Done | + | `[ ]`, not withdrawn, not SKIPPED | Open | + | Contains `SKIPPED` | Skipped | + | Contains `withdrawn` (ticked or not) | Withdrawn | + + Withdrawn wins over Skipped and Done. A line that is both gets counted once, in Withdrawn. + +5. Record the first open T-number in file order. That is the "next open" task. + +6. Use this one-liner to do steps 2 to 5 in one pass. It prints one row per spec: + ```sh + git fetch origin master && git ls-tree --name-only origin/master specs/ | sed 's#^specs/##' | grep -v '^done_' | while read -r d; do + git cat-file -e "origin/master:specs/$d/tasks.md" 2>/dev/null || continue + git show "origin/master:specs/$d/tasks.md" | awk -v s="$d" ' + /^- \[[Xx]\] T[0-9]+/ { if (/withdrawn/) wd++; else if (/SKIPPED/) sk++; else done++; tot++; next } + /^- \[ \] T[0-9]+/ { tot++; if (/withdrawn/) wd++; else if (/SKIPPED/) sk++; else { open++; if (!nxt) { match($0, /T[0-9]+/); nxt = substr($0, RSTART, RLENGTH) } }; next } + END { printf "%s|%d/%d|%d|%d|%d|%s\n", s, done+0, tot+0, open+0, sk+0, wd+0, nxt }' + done + ``` + Output columns: spec, done/total, open, skipped, withdrawn, next open. + +## Report + +7. Print one table. Use these columns: + + | Spec | Done/Total | Open | Skipped | Withdrawn | Next open | + |---|---|---|---|---|---| + +8. Under the table, list every spec where Open is 0 and Skipped is above 0. Say these are waiting on captures or other work, not on code. Do not call them complete. + +9. Note any spec with a tasks file that has no task lines at all. + +## Rules + +- Read-only. Do not switch branches, reset, commit, or push. +- Do not edit `tasks.md` to fix a count. If a count looks wrong, report the line. +- Do not count `done_*` folders. They are archived. +- Do not run tests, lint, or any `make` target for this. diff --git a/.claude/skills/submodule-bump/SKILL.md b/.claude/skills/submodule-bump/SKILL.md new file mode 100644 index 000000000..a3416b31e --- /dev/null +++ b/.claude/skills/submodule-bump/SKILL.md @@ -0,0 +1,76 @@ +--- +name: submodule-bump +description: "Use after a modules or website submodule PR has merged to its main branch, to bump the submodule pointer in the main Gameplane repo. Takes one argument: modules or website." +--- + +Argument: `modules` or `website`. From `.gitmodules`: `modules` is GameplanePanel/module (branch `main`), `website` is GameplanePanel/website (branch `main`, has its own CLAUDE.md and AGENTS.md). + +## Preconditions + +1. Name the submodule PR and confirm it is merged, live: + ```sh + gh pr view <pr-number> --repo GameplanePanel/module --json state,mergeCommit + ``` + For website, use `--repo GameplanePanel/website`. Stop unless `state` is `MERGED`. +2. Check for a pending bump owned by another thread: + ```sh + gh pr list --repo GameplanePanel/Gameplane --state open --search "bump <sub> submodule" + ``` + If one is open, stop and tell the maintainer. Only one bump PR runs at a time. + +## Bump the pointer + +3. Start a fresh branch from master: + ```sh + git fetch origin master + git checkout -b claude/bump-<sub>-submodule origin/master + git submodule update --init <sub> + ``` +4. Record the old pointer, then move the submodule to the merged commit on its `main`: + ```sh + git -C <sub> fetch origin main + git -C <sub> checkout <merged-sha> + ``` +5. List the submodule commits the bump includes: + ```sh + git -C <sub> log --oneline <old-sha>..<new-sha> + ``` +6. Stage only the pointer: + ```sh + git add <sub> + ``` + +## Commit, push, open the PR + +7. Commit signed, naming the submodule PRs included: + ```text + chore: bump <sub> submodule to <short sha> + + Includes: + - <submodule PR title> (#<n>) + + Co-Authored-By: <model actually running this session> <noreply@anthropic.com> + ``` + Use `git commit -s`. Do not add `Claude-Session:` trailers or session links. +8. Push the branch (never to `master`): + ```sh + git push -u origin claude/bump-<sub>-submodule + ``` +9. Open the PR with a short Summary (the submodule PRs included) and a Test plan. Labels: + - `modules`: `type: chore` + `area: modules` + - `website`: `type: docs` + `area: shared` + + Add them via REST, as in `ship-branch` step 7: + ```sh + gh api -X POST repos/GameplanePanel/Gameplane/issues/<PR_NUMBER>/labels \ + -f "labels[]=type: chore" \ + -f "labels[]=area: modules" + ``` +10. Follow `ship-branch` for CI watch, the maintainer's approval wait, and branch cleanup after merge. + +## Notes + +- Never edit submodule contents from the main repo. Module or website changes go through their own PR first. +- Never bump to a commit that is not on the submodule's `main`. +- Never force-push or rebase the bump branch. Use a new commit for fixes. +- If CI on the bump PR fails, diagnose with `ci-triager` before changing anything.