verify-katacode
Skill1 starsChanged 39 days agoMITView on GitHub
Drive the Kata Code web app on an isolated local stack, pair a browser, click through chat, settings, and usage, and capture screenshots plus accessibility snapshots. Use when proving a user-facing web change, running UAT, or checking that the app still boots and pairs.
- Reads credentials
- Installs packages
In this repository21 other files it gives its agents.
- .cursor/rules/global.mdcCursor rule
- .cursor/rules/kata-code-browser.mdcCursor rule
- .cursor/rules/lifecycle.mdcCursor rule
- .cursor/rules/open-pstack-models.mdcCursor rule
- .cursor/rules/ponytail.mdcCursor rule
- .cursor/rules/sub-agents.mdcCursor rule
- 1passwordSkill
- astra-orchestratorSkill
- eli5Skill
- readmeSkill
- rebase-kata-upstreamSkill
- release-testflightSkill
- resolve-reviewsSkill
- show-meSkill
- test-t3-appSkill
- test-t3-mobileSkill
- thermo-nuclear-code-quality-reviewSkill
- thermo-nuclear-reviewSkill
- thermo-runSkill
- thermosSkill
- unslopSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 4 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 41
After pairing, a first-run client opens /welcome and the Connect / Agents / Projects wizard.
- Very specific: line 45
If node_modules is missing, run vp i and launch again.
- Distinctive: line 49
Run this first whenever anything looks off, and before you drive:
- Distinctive: line 65
If doctor fails, stop. Do not click around in some other Kata Code tab "to save time." Attaching to the user's session is how you consume …
- Very specific: line 75
Use the new Pairing URL: exactly once.
- Very specific: line 81
Use one named session for the run.
- Very specific: line 125
Do not call internal atoms, test-only endpoints, or t3-sqlite-state.ts exec to claim a user path works.
- Very specific: line 131
Write proof under uat-evidence/<RUN_ID>/ in the repo.
- Very specific: line 150
Check a second view of any mutation.
- Very specific: line 151
Do not put pairing URLs, #token= fragments, or Token: lines in evidence.
- Distinctive: line 158
When the proof is captured, or as soon as a launch/drive attempt fails:
- Very specific: line 168
Do not remove ~/.katacode or the worktree .katacode.
- Distinctive: line 174
All three are executable. Run them from the repository root.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Verify Kata Code (web)
This skill is for a cold agent that has never seen the app. It launches a disposable Kata Code web stack, pairs a browser the way a user does, drives one mapped feature, and leaves proof on disk.
The primary surface is the web client at apps/web, served with the local server. Desktop wraps the same routes in Electron. Mobile is a separate React Native app. Marketing is a separate site. Do not claim those other clients are verified because the web app worked.
Iterative human testing against a kept-alive worktree stack is the sibling test-t3-app skill. This skill is stricter: dedicated --home-dir, never attach to a stack you did not start, always capture evidence, always tear down what you started.
Launch
From the repository root, load the printed values into the current shell:
eval "$(.agents/skills/verify-katacode/bin/launch)"launch writes progress on stderr and only KEY=value lines on stdout, so eval exports RUN_ID, RUNNER_PID, HOME_DIR, VERIFY_ROOT, WEB_ORIGIN, SERVER_PORT, WEB_PORT, EVIDENCE_DIR, ENV_FILE, and PAIRING_URL. The same exports are also written to $ENV_FILE (${TMPDIR:-/tmp}/katacode-verify-<RUN_ID>/run.env) for a later source "$ENV_FILE".
That starts node scripts/dev-runner.ts dev --home-dir <disposable> with no --browser, no --share, and with VITE_HTTP_URL / VITE_WS_URL unset. Dev is single-origin. Vite proxies /api, /oauth, /.well-known, and /ws. Baking a localhost origin into the bundle breaks every remote browser.
Ready means all of these are true:
- the shell has
RUN_ID,WEB_ORIGIN,HOME_DIR, andPAIRING_URLset (fromevalorsource "$ENV_FILE") - the log contains a
[dev-runner] ... serverPort=... webPort=... baseDir=...line whosebaseDiris the disposable home - the server log contains a
/pair#token=...URL (Effect logs it aspairingUrl:;katacode pairprintsPairing URL:) GET $WEB_ORIGIN/.well-known/kata/environmentreturns JSON withenvironmentId,label, andserverVersion
Ports hash from the worktree path and move when occupied. A developer vp run dev may already be sitting on this worktree's default ports. Read the values launch printed. Do not assume 5733 / 13773. Vite often binds IPv6-only ([::1]). bin/launch and bin/doctor probe ::1, then 127.0.0.1, then localhost, and print the host that actually returned descriptor JSON as WEB_ORIGIN. Pairing URLs still print localhost. On IPv4-only localhost that hangs; open PAIRING_OPEN_URL="${WEB_ORIGIN}/pair#${PAIRING_URL#*#}", not $PAIRING_URL. Do not assume 5733 / 13773.
The disposable home is ${TMPDIR:-/tmp}/katacode-verify-<RUN_ID>/home. Runtime state is <home>/userdata. Never launch against ~/.katacode or the worktree .katacode. Those are the user's live (or worktree) databases.
bin/launch starts the runner in a new process session and then exits. That is intentional: the stack must outlive the helper. bin/cleanup is what stops it, using the pid in run.json.
bin/launch starts the runner with --no-auto-bootstrap-project-from-cwd and KATACODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD=0. Web mode otherwise creates a project from the worktree cwd (often titled server). A fresh launched home must have no auto-created project after onboarding.
After pairing, a first-run client opens /welcome and the Connect / Agents / Projects wizard. Finish that wizard without importing projects, then you should see the empty landing, not a thread in this repo.
Teardown is bin/cleanup. It is required after a failed launch too, so a half-started runner is not left holding ports.
If node_modules is missing, run vp i and launch again. bin/launch puts $REPO_ROOT/node_modules/.bin on PATH so vp is found without a global install. Do not invent a different start command.
Doctor
Run this first whenever anything looks off, and before you drive:
.agents/skills/verify-katacode/bin/doctorPass the run id if .last-run is stale: bin/doctor web-20260826-163000-a1b2c3d4.
Doctor is read-only. It answers "is this instance worth driving?" by checking:
- the runner pid from
run.jsonis alive and its start identity matchesrunnerStart server-runtime.jsonpid is alive and in that runner's process tree- the recorded web and server ports are listened to by processes under that runner
- the home dir is the disposable one, not
~/.katacodeor the worktree.katacode - the web origin serves the environment descriptor and the app shell
If doctor fails, stop. Do not click around in some other Kata Code tab "to save time." Attaching to the user's session is how you consume their pairing token, write into their database, or kill the wrong pid.
On Linux, Vite often binds IPv6-only ([::1]). localhost then times out on IPv4. bin/doctor probes ::1 first. If the descriptor probe fails in the first second after launch, run doctor once more against the same run id before treating the instance as dead.
A consumed pairing token is not a doctor failure. Mint a replacement against the same home:
node apps/server/src/bin.ts pair --base-dir "$HOME_DIR"Use the new Pairing URL: exactly once. Tokens from pair have standard client scopes. The startup URL has admin scopes, which you need for Settings → Connections. For usage, settings general/appearance, the empty landing, and the command palette, a replacement token is enough.
Drive
Install the browser CLI if needed (npm i -g agent-browser && agent-browser install), then load its current command list with agent-browser skills get core so you match the installed version. Before the first open, run agent-browser --version and require 0.37.1 or later if you will record video. Recording was tested on 0.37.1 and 0.38.1; 0.37.0 was not tested. Otherwise run agent-browser upgrade (listed in --help, not exercised in KAT-3652) and check the version again. Do it before you pair: when the CLI version changes, the next command restarts the browser and the paired tab is gone. Also require the Recording checks in agent-browser doctor to pass (ffmpeg with libvpx and libx264). If --version errors, the active node may have no agent-browser install, as happens under mise. Run npm i -g agent-browser, or put the node version that has it first on PATH (mise ls node lists them), and check again. If the version still stays below 0.37.1, plan on the screenshot fallback under Evidence.
Use one named session for the run. Do not pass --session-name (that persists cookies under ~/.agent-browser).
PAIRING_OPEN_URL="${WEB_ORIGIN}/pair#${PAIRING_URL#*#}"
agent-browser --session katacode-verify open "$PAIRING_OPEN_URL"
agent-browser --session katacode-verify set viewport 1400 900
agent-browser --session katacode-verify wait --text "Connect your computers"
agent-browser --session katacode-verify snapshot -i
# If `/pair` was already mounted (token-free before-shot), fill Pairing token and Continue instead.$PAIRING_URL is the value from eval "$(bin/launch)" or source "$ENV_FILE". It ends in /pair#token=... and still uses localhost. $PAIRING_OPEN_URL keeps that fragment on $WEB_ORIGIN (so [::1] when Vite is IPv6-only). Open $PAIRING_OPEN_URL exactly once as the first navigation that consumes the token (after any token-free $WEB_ORIGIN/ before-shot in the pairing recipe). Opening it twice, or opening it in a second browser, burns the token. If the before-shot already mounted /pair, hash auto-submit will not run; use the form or reload.
After pairing, the app strips the token from the URL and redirects to /. FirstRunGate then replace-navigates to /welcome. Wait until you see the setup dialog Set up Kata Code and heading Connect your computers. Do not treat What should we work on? as pairing proof yet. /welcome paints that empty hero behind the wizard.
Finish the wizard without importing:
- Connect. The local computer row shows Connected. Click Continue. Do not open Add a computer.
- Agents. Heading Connect your agents. Click Continue. Do not require an agent to be Ready.
- Projects. Heading Your projects or Choose your projects. Click Do not import projects.
Then wait until the setup dialog is gone and the URL is /. A correct launch then shows:
- the text What should we work on? (a styled div, not a heading role) and a button Add project
A draft at /draft/... after that skip means a project already exists (cwd auto-bootstrap or an import). That is a launch failure for this skill, not a pairing failure.
Then follow the matching file under features/. Prefer ARIA names, data-testid, and route paths over coordinates. wait --text matches visible text only: icon buttons such as Usage and Refresh usage are named by aria-label, so wait on a heading or use find role button --name.
Stable handles in this app:
| What | Handle |
| Pairing form | heading Pair with this environment, textbox Pairing token, buttons Continue and Reload app |
| Welcome wizard | dialog Set up Kata Code, progress Setup progress, steps Connect / Agents / Projects, headings Connect your computers / Connect your agents / Your projects or Choose your projects, skip-import button Do not import projects |
| Empty landing | text What should we work on? (no heading role), button Add project |
| Add project | dialog Command palette, group Sources listing New project (preselected), Local folder, Git URL, then provider repositories |
| Draft composer | textbox Message |
| Sidebar settings | button Settings |
| Sidebar usage | button Usage |
| Command palette | data-testid="command-palette" with data-palette-mode="command", name Command palette, shortcut mod+k (⌘K on macOS, Ctrl+K elsewhere). The same testid serves File picker (files) and Search project contents (content) |
| Usage page | heading Usage, nav Usage breadcrumb, menu All environments, groups Usage metric (Cost / Tokens / Limits) / Usage period / Usage breakdown, button Refresh usage or Refresh limits |
| Settings | breadcrumb Settings breadcrumb, combobox Search settings, environment-scope nav labels General, Appearance, Keybindings, SnapShots, Providers, Integrations, Source Control, Connections, Archive; project or checkout scope also shows Project |
Do not call internal atoms, test-only endpoints, or t3-sqlite-state.ts exec to claim a user path works. SQLite inspection is a side-effect check after a real UI action, and only against the disposable home.
Provider CLIs (Codex, Claude, Cursor, Grok, OpenCode) live on the server machine. The server detects them from its user's environment, so they can show Ready even in an isolated home. You can prove pairing, navigation, settings, usage chrome, and adding a project without a provider. Do not send a message unless your brief allows a live provider call, because each reply costs money. Record that skip.
Evidence
Write proof under uat-evidence/<RUN_ID>/ in the repo. Cleanup must not delete that directory.
Minimum for a pass:
logs/launch.txtfrombin/launch(already redacted)- one screenshot before the action and one after, or a snapshot pair that shows the same delta
- an accessibility snapshot of the resulting screen (
agent-browser --session katacode-verify snapshot) saved undersnapshots/ evidence.jsonnaming the feature id, entry point used,WEB_ORIGIN(no token), and the observable end state
To record video, use agent-browser 0.37.1 or later (see Drive). record start then attaches to the active tab. It opens no new tab and does not navigate, so the pairing, the viewport, and an unsent composer draft all survive. It writes 30 fps and holds the latest frame between repaints, so idle time is kept and the video length is close to wall-clock time. In KAT-3652, a flow of 10 idle seconds, a page navigation, and 3 more seconds recorded as 13.4 s on 0.37.1 and 13.1 s on 0.38.1, and both kept the frames from before the navigation. Pair first, then run agent-browser --session katacode-verify record start <path.webm> on the paired tab, so the token never enters the video. Run agent-browser --session katacode-verify record stop --json right after the captured action and before you upload the file. Stop finalizes the WebM, and an active recording is not a complete file. Require capturedFrames above 1 in its output; 1 means Chrome sent a single frame and the video is a still.
On 0.36.0, the one older release tested, record start opened a second tab and recorded that one. The new tab reloaded the current URL, and Kata Code opened a new draft there with an empty composer. The first tab kept the unsent draft. Use the screenshot fallback below the floor, when agent-browser doctor fails its Recording checks, or when record stop --json reports capturedFrames of 1 for a flow that changed the screen. Pair first, then capture one agent-browser screenshot per second while you drive the flow. Start the loop only after pairing succeeds, and never capture the pairing form or any token entry, because every frame goes into the uploaded video. Then assemble the frames with ffmpeg -framerate 1 -i frames/%03d.png -c:v libx264 -pix_fmt yuv420p -r 25 out.mp4. Say in the PR comment that the video is a 1 fps capture. Check the frames before you upload.
For a change with an open pull request, attach at least one representative UI screenshot or video from the run to the PR conversation before calling the change verified. First require gh pr comment --help to list --attach; this binary upload requires GitHub CLI 2.101.0 or later. When available, run gh pr comment <number> --body "UI evidence for <feature>." --attach "$EVIDENCE_DIR/screenshots/<file>.png#<observable state>". Post one attachment per comment. In KAT-3532, a comment with several --attach files posted after the first upload, and each later upload then failed with a TLS error. Otherwise use an authenticated GitHub integration or the authenticated PR page that accepts binary uploads. If none is available, report the PR evidence upload as blocked and do not call the change verified. A local filesystem path, an inaccessible file:// link, or a text-only claim does not count. Fetch the PR comment after uploading and require a rendered attachment URL, then record the PR URL, comment URL, and attached evidence filenames in evidence.json. Keep the original files under uat-evidence/<RUN_ID>/ after upload. If the verification has no PR, keep the evidence locally and record pullRequest: null; do not create an empty PR only to host evidence.
Proof standards:
- Exercise the real user path. Pairing in the browser counts. Posting to
/api/auth/browser-sessionyourself does not. - Capture the action and the resulting state, not only the final screen.
- Check a second view of any mutation. Adding a project means the landing heading is gone and the sidebar or composer shows that project. Toggling usage to Tokens means the big number is a token count, not
$0.00. - Do not put pairing URLs,
#token=fragments, orToken:lines in evidence.bin/launchalready redactslogs/launch.txt. If you copy more log, pipe it through the samesedinbin/lib.sh(redact_secrets). - Mocks are not allowed for pairing, routing, or settings persistence. The only acceptable gap is an external provider CLI that is not installed; say so and stop at the UI that names the missing provider.
uat-evidence/ is gitignored. Leave it on disk so a human can open the screenshots. Do not commit it.
Cleanup
When the proof is captured, or as soon as a launch/drive attempt fails:
.agents/skills/verify-katacode/bin/cleanupThat verifies the runner pid in run.json still has the recorded runnerStart identity, then kills that pid and its descendants, then deletes ${TMPDIR:-/tmp}/katacode-verify-<RUN_ID>/. If the pid is gone or the identity no longer matches, cleanup skips signals and only removes this run's state. It does not delete uat-evidence/<RUN_ID>/.
Never pkill -f, never pgrep | kill, never kill a pid you found by matching katacode or the worktree path. This machine runs other Kata Code servers. The worktree you are in may already have a vp run dev on different ports. Kill only the pid launch printed, and only after the start identity matches.
Do not remove ~/.katacode or the worktree .katacode.
Close the katacode-verify agent-browser session after cleanup so the next run does not reuse cookies against a dead origin.
Helpers
All three are executable. Run them from the repository root.
eval "$(.agents/skills/verify-katacode/bin/launch)"
.agents/skills/verify-katacode/bin/doctor
.agents/skills/verify-katacode/bin/doctor web-20260826-163000-a1b2c3d4
.agents/skills/verify-katacode/bin/cleanup
# later shell: source "$ENV_FILE"launch writes uat-evidence/<RUN_ID>/, ${TMPDIR:-/tmp}/katacode-verify-<RUN_ID>/run.json, and run.env. doctor and cleanup read .agents/skills/verify-katacode/.last-run when you omit the id. Run ids are web-<UTC>-<8 hex> and must stay filename-safe (no / or ..).
Feature recipes live in features/. Drive from that map. A proof that uses one convenient entry point is incomplete when the map lists others; report the ones you did not reach rather than silently skipping them.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

