This repo has an agentic workflow built around Claude Code. Any contributor (human or agent) can ship a GitHub issue end-to-end following the loop documented here. The goal: issues become draft PRs without stepping on any of the invariants in CLAUDE.md.
Read this alongside:
CLAUDE.md(repo root) — architecture, invariants, the contract an agent obeysdocs/AGENT_GUIDE.md— deeper reference (data flow, SIWS, testing patterns, deployment)
Do these once per machine (or once per fresh clone):
-
Install the GitHub CLI and authenticate.
brew install gh gh auth login # pick GitHub.com → HTTPS → login via browserThe workflow uses
ghfor issue and PR operations. -
Install the UI tester's browser.
bash .claude/skills/stadium-tester/setup.sh
Installs
@playwright/testintoclient/node_modulesand downloads Chromium (~150MB). Idempotent — safe to run again. -
Restart Claude Code in this project. Skills under
.claude/skills/are loaded at startup. A fresh session picks them up. -
Verify the tester is wired up. In Claude Code:
/verify-testerIt checks Node + Playwright, tests that the production-URL guard works, and offers a live smoke test.
-
Confirm the Vercel preview env var is set. Vercel dashboard → Project settings → Environment Variables →
VITE_USE_MOCK_DATA = true, Environment = Preview, Branch = All Preview Branches. Production leaves it unset. This makes every branch's preview run on fixtures (client/src/lib/mockWinners.ts) rather than hitting production data.
In GitHub, open a new issue using the Feature request or Bug report template. Every section is load-bearing, but the most important one for agents is:
## Test scenarios
- [ ] On <route>, <action> → <expected state>
- [ ] On <route>, <action> → <expected state>
The stadium-tester Skill verifies each bullet in a real browser. Without scenarios, /ship-issue refuses to open a PR. Write scenarios as observable facts about the UI, not vague acceptance ("admin panel works" is useless; "on /admin, filter by M2 → Plata Mia row shows + M2 grant badge" is good).
In Claude Code, run:
/ship-issue <issue-number>
- Reads the issue (
gh issue view). - Maps affected files via the
stadium-explorersubagent. - Posts a written plan to the conversation.
- Stops and waits. Do not write code until you approve.
Approvals: "ship it", "approved", "looks good", "proceed". Anything else = no code.
- Creates a feature branch off
origin/develop. - Hands the plan to the
stadium-implementersubagent. - Commits reference the issue (
Closes #N).
/pre-pr-check— runscd server && npm test,cd client && npm run build,cd client && npm run lint./stadium-tester— drives a real headless Chromium against the local dev server or the Vercel preview, walks each## Test scenario, produces a pass/fail markdown report.
If either gate fails, the agent returns to the implementer, fixes, re-runs. No PR opens on a failing gate.
- Target:
develop. Always draft. - Body includes: summary, test plan, tester report, preview URL placeholder, backlog items, invariants checklist.
- Click the Vercel preview URL (the Vercel bot posts it on the PR within ~1–3 minutes of push).
- Read the
stadium-testerreport in the PR body. - Visual/UX check with your own eyes on the preview.
- Skim the diff.
If you leave review comments, run:
/address-review <pr-number>
The agent:
- Fetches PR-level and inline comments via
gh. - Classifies each as CODE (needs code change), REPLY (needs only an explanation), or REJECT (disagree, with reason).
- Pauses and waits for you to approve the classification.
- Makes changes in a batch, runs
/pre-pr-check, pushes. - Replies to each thread and posts a rollup summary comment.
- Does not flip the PR from draft to ready-for-review. That's your call.
- You flip draft → ready-for-review.
- You merge (rebase, squash, or merge — your call).
- The agent never merges. The agent is never in CODEOWNERS. See
.github/CODEOWNERS.
When the change touches user-visible surface, four things change:
Write ## Test scenarios as observable facts the browser can verify:
- ✅
On /admin, filter by M2 → at least 4 rows visible - ✅
On /, scroll to "Recently shipped" → Plata Mia card visible - ✅
On /winners, filter by "Main Track" → row count matches header - ❌
Admin panel works - ❌
Payments look correct
Each bullet becomes one Playwright test() block. Vague bullets produce vague (or false) passes.
Vercel Preview has VITE_USE_MOCK_DATA=true. Reads come from client/src/lib/mockWinners.ts (159 sanitized prod projects, regenerated periodically). Writes simulate to localStorage and in-memory.
If your feature needs a field that isn't in the fixture, either:
- Extend
mockWinners.tsas part of the PR (preferred — adds regression coverage), or - Note the gap in the scenario and mark that scenario SKIPPED.
stadium-tester catches:
- ✅ Element presence, text content, DOM structure
- ✅ Click → state change → assertion
- ✅ Console errors during the flow
It does not catch:
- ❌ Color, spacing, typography looking wrong
- ❌ Animations janky
- ❌ Responsive breakpoints ugly
Your eyes on the preview are still load-bearing for visual/UX judgment. The tester just keeps you from regressing the functional part while you're judging the visual.
Scenarios requiring a Polkadot wallet signature (admin auth, confirm payment, approve M2, request changes) return SKIPPED (needs-auth-harness). The tester refuses to fabricate signatures. For those flows, verify manually on the preview and note in the PR body which scenarios were skipped.
When a Playwright test fails, the screenshot lands next to the spec in /tmp/. The agent links it in its failure report — always open it before asking for a fix, often it's obvious what broke.
Full list lives in CLAUDE.md §9. Quick reference:
| Kind | Name | What it does |
|---|---|---|
| Subagent | stadium-explorer |
Codebase search tuned to this layout |
| Subagent | stadium-implementer |
Writes code per the approved plan |
| Subagent | stadium-reviewer |
Pre-PR invariant check |
| Skill | stadium-tester |
Drives headless Chromium, runs scenarios |
| Command | /ship-issue <n> |
End-to-end flow for one issue |
| Command | /triage-issue <n> |
Plan only, posted as issue comment |
| Command | /address-review <pr> |
Process PR review comments |
| Command | /log-improvement <desc> |
Append to docs/improvement-backlog.md |
| Command | /promote-backlog |
Convert backlog entries to GitHub issues |
| Command | /pre-pr-check |
Run server tests + client build + lint |
| Command | /verify-tester |
Health check for the tester Skill |
- Skip
## Test scenarioson an issue you intend to/ship-issue— the workflow bails. - Push directly to
developormain. - Merge an agent PR without clicking the Vercel preview at least once.
- Run the tester against
stadium.joinwebzero.comor the production Railway host — the runner refuses (exit code3), don't try to bypass. - Flip a PR out of draft before the tester is green.
- Add the agent to
.github/CODEOWNERS. - Use
--no-verifyor otherwise skip/pre-pr-checkfailures. - Hardcode values (admin addresses, magic amounts) instead of reading from schema or env.
/verify-testerfails on fresh clone → runbash .claude/skills/stadium-tester/setup.shmanually and check for npm / Chromium errors.gh auth loginbrowser flow blocked → usegh auth login --with-token < token.txtwith a personal access token (scopes:repo,workflow,read:org).- Tester passes locally but fails on preview → check
window.__STADIUM_MOCK__in the preview's devtools; if it'sundefined, the Vercel env var didn't propagate to that build. - Agent flags invariants are violated → read
CLAUDE.md §4and thestadium-revieweroutput before pushing back; the invariants are there because each one caused a production regression once. - Issue templates are missing
## Test scenarios→ someone filed the issue with a blank template; ask them to edit, don't invent scenarios.
Open items worth doing live at docs/improvement-backlog.md. Use /log-improvement during a /ship-issue run to add observations without breaking scope. Use /promote-backlog (with your confirmation) to convert them into GitHub issues with the claude-suggested label.