Browser Testing With Devtools
shashankswe2020-ux/whoop-mcp
Tests in real browsers. An agent skill from shashankswe2020-ux/whoop-mcp.
Drive and observe the BottleShip emulator to bring up a game, using the AI-agent harness (window.BS.harness + bun tools/harness.ts).
$ npx skills add jenissimo/bottleship --skill bringup -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install jenissimo/bottleship bringup --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/jenissimo/bottleship.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/bringup .claude/skills/bringup && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "bringup" agent skill from https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringup into .claude/skills/bringup/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "bringup", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringupType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add jenissimo/bottleship --skill bringup -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install jenissimo/bottleship bringup --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jenissimo/bottleship.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/bringup .agents/skills/bringup && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "bringup" agent skill from https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringup into .agents/skills/bringup/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "bringup", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add jenissimo/bottleship --skill bringup -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install jenissimo/bottleship bringup --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jenissimo/bottleship.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/bringup .cursor/skills/bringup && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "bringup" agent skill from https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringup into .cursor/skills/bringup/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "bringup", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/jenissimo/bottleship.git --path .claude/skills/bringup--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add jenissimo/bottleship --skill bringup -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install jenissimo/bottleship bringup --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jenissimo/bottleship.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/bringup .gemini/skills/bringup && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "bringup" agent skill from https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringup into .gemini/skills/bringup/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "bringup", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install jenissimo/bottleship bringupInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add jenissimo/bottleship --skill bringup -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/jenissimo/bottleship.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/bringup .github/skills/bringup && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "bringup" agent skill from https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringup into .github/skills/bringup/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "bringup", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add jenissimo/bottleship --skill bringup -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install jenissimo/bottleship bringup --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jenissimo/bottleship.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/bringup .opencode/skills/bringup && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "bringup" agent skill from https://github.com/jenissimo/bottleship/tree/main/.claude/skills/bringup into .opencode/skills/bringup/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "bringup", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
bringupDrive and observe the BottleShip emulator to bring up a game, using the AI-agent harness (window.BS.harness + bun tools/harness.ts).
Bringup is an agent skill from jenissimo/bottleship. Drive and observe the BottleShip emulator to bring up a game, using the AI-agent harness (window.BS.harness + bun tools/harness.ts). Use when loading a game, making it reach a menu/level, diagnosing why it crashes/hangs/renders black, or writing a repeatable bring-up/regression script. Operationalizes CLAUDE.md's debugging workflow on top of the harness verbs. Use the project's CDP harness, not a browser MCP (chrome-devtools MCP is disabled for this project).
Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Agent Workflows, covering Browser testing and Agent instruction files. It works with Model Context Protocol, Chrome DevTools, TypeScript and WebAssembly. The repository describes itself as: Run classic Windows games in your browser. A high-level-emulation engine that boots real x86 Windows executables and reimplements Win32, COM and DirectDraw/Direct3D on WebGPU…. The licence is Apache-2.0.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 77fe4f4. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
bunFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Bringup loads about 2.9k tokens when it runs. Until then it costs about 119 tokens; SKILL.md has 1,292 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from jenissimo/bottleship at commit 77fe4f4, republished under its Apache-2.0 licence (© jenissimo). 1,292 words, ~2,854 tokens.
.claude/skills/bringup/SKILL.md (or your agent's skills folder).The harness turns bring-up from "poke dbg.* by hand, grep logs, guess from
screenshots" into fluent, self-judging automation. It is headless (CLI/CDP)
and in-page (window.__BS__.harness). Logic lives in the worker
HarnessService; the page facade and CLI are thin transports over one
harness_rpc {id,cmd,args}→{id,ok,result|error} contract.
harness upbun tools/harness.ts upLaunches/attaches Chrome with --autoplay-policy=no-user-gesture-required (so
audio unlocks with no gesture — no canvas click needed in automation), opens
http://localhost:5174/?game=dev, arms log streaming, and probes Vite(:5174
/health) + dev-sidecar(:3001 /health) + Chrome(:9333). Bring the dev servers
up first: bun run dev and bun run dev:sidecar (dev:logs still works; start the
server BEFORE streaming). bun tools/harness.ts health re-probes.
Set BS_TAB=<name> (once, for every harness command you run) when another agent is
already using the emulator:
BS_TAB=alpha bun tools/harness.ts up # opens/claims ?game=dev&bs=alpha
BS_TAB=alpha bun tools/harness.ts run my.harness.ts
BS_TAB=alpha bun tools/harness.ts reportThe name picks that tab and ONLY that tab, and re-roots this run's evidence under
logs/alpha/ — screenshots, run-N.harness.ts journals, dumpSurface/shot({save})
PNGs, and the sidecar's log archive. Never read logs/ at the top level while a
session is set; that is somebody else's guest.
Rules: pick a name nobody else is using; never close a tab you did not open; and
do not measure — parallel guests share the CPU, so trace refuses to run while
a second guest tab is open, and A/B timing needs a single tab. With BS_TAB unset
everything behaves exactly as it always has.
A fluent chain (bun tools/harness.ts run <script.harness.ts>, or in the browser
console await window.__BS__.harness.chain()....run()):
import { harness } from "../harness";
await harness()
.streamLogs(["SYSTEM","DDRAW"])
.openWgb(process.env.WGB ?? "/apps/external-wgb/<id>.wgb") // abs path (streamed off disk) or drop-folder URL — take it from env, don't hardcode local paths
.waitForEvent("dialogShow") // event-driven wait (HarnessEventBus)
.click("Play Game") // faithful click by label (global coords)
.tickFrames(120) // wait N presents after the click
.waitUntil(() => read32(0x6b7bf8) === 0) // predicate evaluated IN the worker (spin-loop games)
.expectSurfaceNonBlack("primary") // assertion → aborts + auto fault snapshot on fail
.state(["surfaces","threads"])
.run(); // → one POJO (also written to logs/harness/)Skip intros with the bundle's skipVideo. audioGesture() exists only for a
manually-opened browser; automation uses the autoplay flag.
Touch/mobile runs the same way — .device('phone-landscape'|'tablet-landscape'|'desktop')
then .tap(x,y) / .touchDrag(x0,y0,x1,y1,ms) / .longPress(x,y,ms) / .twoFingerTap(x,y) /
.pinch(x,y,scale), all in GUEST px. These execute CDP-side, so keep .device() and its
gestures in ONE chain: the emulation override is owned by the CDP session and a separate
CLI invocation reconnects without it.
state([...]) — windows/surfaces/memory/threads/rings/audio/video/modules/cpu/screen as one POJO.shot({save}) — PNG of the SCREEN: the frame that reached the canvas, every overlay
(video plane, live GDI dialog rects, stats) composited, read from the mirror the present
path keeps. shot({source:'layer'}) asks for the presenter's pre-composite game layer
instead — the split between "which layer holds the pixels" and "does the composite show
it" — and is always labelled composited:false. A capture that cannot see the screen
errors out; it never returns a plausible substitute.bun tools/harness.ts shot [file] --verify — the browser's own capture of the canvas,
plus a cross-check of every worker-side route against it (with the screen's own churn as
the noise floor). Run it when a screenshot and the tab seem to disagree.screenPixels({x,y,w,h,legend}) — a rect as one string per row, colours quantised to
legend; anything outside it reads ? and is tallied, so a chrome-geometry assertion
(is the etched line present HERE and absent THERE) cannot pass on pixels it did not
recognise.screenMark() … screenChangeSince({allow}) — WHICH pixels a transition touched.
Mark from a REPAIRED screen: a mark taken over an already-damaged one reports "nothing
changed" and the scope assertion then passes on the very bug it exists to catch.
outside.changed answers "what repainted that had no business repainting" (an
over-wide invalidate, a stamp with nothing erased under it); each allow rect's own
count is the positive control, so a run where the click missed fails instead of
passing. Both sides are ours, so it is exact — no reference image, nothing to tune.textures() + dumpSurface(ptr|'primary') — gallery + per-surface PNG to logs/debug/.surfacePixels(sel) / expectSurfaceNonBlack(sel) — cheap liveness from a subsampled readback.waitForControl("New Game"), never tickFrames, or you wait on presents that never come and
it reads exactly like a hang.hitTest(x,y) before anything else. It prints the
window a mouse message is ADDRESSED to next to the control the container hit-test finds, and
agrees:false is a routing bug the pixels cannot show: every control we drive ourselves keeps
working off the container hit-test, while one the guest SUBCLASSED needs the address and gets
nothing. wmTrace then confirms it on the wire (the hwnd on WM_LBUTTONDOWN).paintTrace("start") … paintTrace("read"). The chain has
many links (posted → pump filter → dispatched → BeginPaint/EndPaint+flush → owner-draw chain
with its task counts → per-flush child-window exclusions) and the pixels look identical
whichever one dropped it; the trace names the link and its reason.breakOnApi("d3d9.*")) — JS layer, no JIT-off,
resolves on first hit with args + caller. Best for "where does it first touch X".breakOnExport("d3d9.dll!Direct3DCreate9"), breakOnSymbol("core!UInput::ReadInput")
(needs loadSymbols(module, {name:rva}) from the RE layer first), watchMem(addr),
breakOn(eip) — all require JIT OFF (auto-enabled; perf collapses while
armed — clearBreaks() to restore). Addresses inside the async-park spin loop
are refused (CLAUDE.md §3.5).callsite off the hit: retAddr + retAddrSym, a retAddrTrust verdict, the
module-labelled backtrace, a stack window, and capture.reads
({reg:'esi',offset:12,size:4} — add deref to follow the pointer). Present in EVERY
mode, continuous included. Trust the caller only on verdict:"verified" (the E8 before
[ESP] targets the armed eip); untrusted/unreadable means the armed address is not a
function entry and retAddr names nobody.breakEvents({since,limit}), from
any process, at any later time. Never accumulate hits in a script and print at the end: a
60s pageEval/RPC timeout takes the whole run's evidence with it, the ring does not. It
reports evicted/gap instead of silently returning a shorter list, and says out loud
that 0 events is not evidence the code did not run (block-entry rule).events(n) shows recent harness events; on a WASM trap a
fault event carries the fault-grade snapshot.logLevel("DDRAW","WARN") (logLevel() resets) — rather than
just enlarging the ring, which only postpones losing the same lines.report().pendingModals lists them (text, caption, how long it has waited);
dismissModal() / onModal() answer them.Confirm with a dump / a logged value (a dumpSurface PNG, a state field, a
breakOnApi snapshot) before theorizing about DC topology / vtable layout — the
canvas-vs-selected-bitmap distinction and multi-DC composites are easy to mis-model
(CLAUDE.md diagnostic discipline).
Every .run() writes a re-runnable logs/harness/run-N.harness.ts (journal). Turn
the winning chain into a checked-in *.harness.ts regression script under
tools/harness/regression/ only if it self-judges (throws/sets exitCode with
a stated reason, not "look at the screenshot") and isn't tied to one closed bug
(see tools/harness/README.md). Remove one-off probes; keep only reusable
harness verbs.
bun tools/generate-index.ts →
bun tools/validate-signatures.ts → bun tools/validate-struct-offsets.ts →
bun tools/validate-guest-code-writes.ts → bun tools/validate-stub-tables.ts →
bun run typecheck.src/worker (HMR doesn't reload the worker
entry and hangs the game). The harness ships in the worker bundle — iterate via
a page reload.clearBreaks() when done.harness up) or a real transport click; a
synthetic event won't satisfy the browser autoplay policy.The skill = workflow/checklist; the harness (src/worker/harness/,
src/harness/, tools/harness.ts) = capability/verbs; CLAUDE.md = invariants.
Templates: tools/harness/templates/bringup.harness.ts (bring-up starting point),
tools/harness/templates/diagnose-eip.harness.ts (API-breakpoint + waitUntil). Checked-in
per-game regression scenarios live in tools/harness/regression/ (run the whole batch with
bun tools/harness.ts regress); see tools/harness/README.md for what earns a spot there.
© jenissimo, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/bringup of jenissimo/bottleship.
Open the folder on GitHubat commit 77fe4f4
Bringup next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Bringup this skilljenissimo/bottleship | 132 | — | ~2.9k | Automated safety check: Pass | Apache-2.0 | |
| Browser Testing With Devtoolsshashankswe2020-ux/whoop-mcp | 165 | — | ~3k | Automated safety check: Warn | MIT | |
| Chrome Devtools MCPmanagedcode/dotnet-skills | 486 | — | ~2.2k | Automated safety check: Pass | MIT | |
| Spider Kingaoyunyang/spider-king-skill | 507 | — | ~7.3k | Automated safety check: Pass | MIT | |
| Clawmemyoloshii/ClawMem | 210 | — | ~7.5k | Automated safety check: Pass | MIT | |
| Review Agents Mddominik1001/caldav-mcp | 103 | — | ~1.2k | Automated safety check: Pass | MIT |
shashankswe2020-ux/whoop-mcp
Tests in real browsers. An agent skill from shashankswe2020-ux/whoop-mcp.
managedcode/dotnet-skills
Use Chrome DevTools MCP from .NET agents and .NET-focused repos to inspect, debug, and automate Chrome through an MCP client.
aoyunyang/spider-king-skill
Pure-web protocol reverse skill: turn hostile browser clients into browser-free Python collectors.
yoloshii/ClawMem
ClawMem operational reference for agents at query time — the 3-rule escalation gate, MCP tool routing, the 4 query-optimization levers, pipeline behavior (query vs intentsearch), composite scoring…
dominik1001/caldav-mcp
Reviews an AGENTS.md or CLAUDE.md file against best practices and reports concrete fixes.
anombyte93/prd-taskmaster
Phase 3 of the prd-taskmaster pipeline: smart mode selection and user handoff.
jenissimo/bottleship
Turn a game installer/archive/disc (InstallShield, PackageForTheWeb/WinZip-SFX, Inno/GOG, ISO/BIN-CUE, CAB, FreeArc, plain ZIP) into a .wgb bundle using BottleShip's OWN self-hosted format readers —…
Categories
Drive and observe the BottleShip emulator to bring up a game, using the AI-agent harness (window.BS.harness + bun tools/harness.ts). Bringup is an agent skill from jenissimo/bottleship.ts).
Bringup fits situations like: making it reach a menu/level; diagnosing why it crashes/hangs/renders black; writing a repeatable bring-up/regression script.
Run `npx skills add jenissimo/bottleship --skill bringup -a claude-code`. Or copy the skill folder (.claude/skills/bringup in jenissimo/bottleship) into .claude/skills/bringup in your project. Claude Code loads it when a task matches its description.
Run `npx skills add jenissimo/bottleship --skill bringup -a codex`. Or copy the skill folder (.claude/skills/bringup in jenissimo/bottleship) into .agents/skills/bringup in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jenissimo/bottleship --skill bringup -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/bringup, .gemini/skills/bringup, .github/skills/bringup and .opencode/skills/bringup in your project.
Going by SKILL.md and its folder, Bringup needs the command-line tools its instructions call (bun).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Bringup is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.9k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Bringup: Browser Testing With Devtools (shashankswe2020-ux/whoop-mcp, 165 stars), Chrome Devtools MCP (managedcode/dotnet-skills, 486 stars), Spider King (aoyunyang/spider-king-skill, 507 stars) and Clawmem (yoloshii/ClawMem, 210 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
jenissimo (a GitHub user) maintains it in jenissimo/bottleship, which has 132 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on October 7, 2026.
Source: jenissimo/bottleship on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.