| name | verify-feature |
| description | End-to-end verification of a feature implementation before opening a PR. Starts the SimpleModule.Host (killing port 5001 if occupied), drives the feature in a real browser via playwright-cli, runs every local CI step, and only then opens a pull request. Use when the user asks to "verify the feature", "test and ship", "run e2e + CI + PR", or any variation that means "prove it works, then PR it". |
| allowed-tools | Bash, Read, Edit, Write |
verify-feature
Run this skill after a feature is implemented and committed locally. It is a gated pipeline — each stage must pass before the next runs. If any stage fails, stop, surface the failure, and do NOT open a PR.
Inputs to gather first
Before starting, confirm these from conversation context (do not ask the user unless missing):
- Feature description — what was implemented (used to pick the page and assertions for stage 2)
- Page route — the Inertia route (e.g.
AuditLogs/Browse) or URL path to exercise
- Branch — current branch (must not be
main)
If route/path is unknown, grep the diff for Inertia.Render("...") calls to infer it.
Stage 1 — Start the application
The host listens on https://localhost:5001 (see CLAUDE.md). Free the port if held, then start the app in the background.
PORT_PIDS=$(lsof -ti tcp:5001 2>/dev/null || true)
if [ -n "$PORT_PIDS" ]; then
echo "Port 5001 occupied by PID(s): $PORT_PIDS — killing"
kill -9 $PORT_PIDS
sleep 1
fi
dotnet run --project template/SimpleModule.Host
Run the dotnet run command via Bash with run_in_background: true. Capture the shell ID — you will need it to stop the app later.
Wait for readiness. Poll the health endpoint with curl (-k because the cert is self-signed) until it returns 200, then continue. Cap the wait at 90 seconds.
for i in $(seq 1 45); do
if curl -sk -o /dev/null -w "%{http_code}" https://localhost:5001/ | grep -qE '^(200|302|401)$'; then
echo "App is up"; break
fi
sleep 2
done
If readiness times out, read the background shell's output, surface the error, and abort the skill.
Stage 2 — Verify the feature with playwright-cli
Use the playwright-cli skill's commands directly (already documented in .claude/skills/playwright-cli/SKILL.md). The cert is self-signed; open with --ignore-https-errors via the run-code escape if needed, otherwise just navigate — playwright-cli accepts self-signed certs by default.
Pattern:
playwright-cli open https://localhost:5001/<route-path>
playwright-cli snapshot
playwright-cli click eN
playwright-cli snapshot
playwright-cli console
playwright-cli close
Assertions to make from snapshots and console:
- The expected page route is in the URL.
- Key UI affordances from the feature are present in the snapshot (form, button, table row, etc.).
- After exercising the feature (submit/save/etc.), the resulting state is correct (success toast, new row, navigation).
playwright-cli console returns no error-level entries related to the feature.
If any assertion fails, stop and report. Do not proceed to CI.
Stage 3 — Stop the app before CI
CI's npm run build + dotnet build will conflict with the running host. Kill the background shell now.
PORT_PIDS=$(lsof -ti tcp:5001 2>/dev/null || true)
[ -n "$PORT_PIDS" ] && kill -9 $PORT_PIDS
Also call KillShell on the background Bash shell from stage 1.
Stage 4 — Run local CI
Execute the steps from .claude/commands/ci.md in order. Stop on first failure.
npm run check
npm run build
dotnet build
dotnet test --no-build
npm run test:smoke -w tests/e2e
Print this table at the end of stage 4:
| Step | Status |
|---|
| Lint & Format | pass/fail |
| Frontend Build | pass/fail |
| .NET Build | pass/fail |
| .NET Tests | pass/fail |
| E2E Smoke Tests | pass/fail |
If any step fails, surface the relevant error output, suggest a fix, and abort — do not open a PR.
Stage 5 — Create the PR
Only reached when stages 1–4 all passed.
-
Check there are commits ahead of main:
git log --oneline main..HEAD
If empty, stop — there is nothing to PR.
-
Push the branch:
git push -u origin HEAD
-
Open the PR with gh, using a HEREDOC for the body. Follow the project's commit message style (see git log).
gh pr create --title "<concise title, <70 chars>" --body "$(cat <<'EOF'
## Summary
- <what changed>
- <why>
## Verification
- Manually exercised <feature> at https://localhost:5001/<route> via playwright-cli
- All local CI steps passed (lint, frontend build, .NET build, tests, smoke tests)
## Test plan
- [ ] CI green on PR
- [ ] Reviewer spot-checks <area>
EOF
)"
-
Return the PR URL.
Hard rules
- Never add
Co-authored-by: Claude or any AI attribution to the commit, PR body, or PR title (see CLAUDE.md Attribution Policy).
- Never force-push, never push to
main, never use --no-verify.
- Stop on first failure. Do not paper over a broken stage to get to the PR.
- The PR step is gated. If stages 1–4 didn't all pass, surface the failure instead and exit.
- Before killing PIDs on port 5001, confirm they're processes you started (or that the user expects to be killable) — don't blindly kill an unrelated long-lived process if the user has something else bound there.