Files
skills/skills/web-shot/SKILL.md
T
mathias c6787e04d7
CI / Check / Test (push) Failing after 1s
CI / Tag release (push) Skipped
feat(index): generate the skills table from frontmatter
Second half of #29. The index was hand-maintained and had already drifted
once: dream and experiment-spec shipped with no row, their rows lost to a
squash-merge after a directory reorg. bin/check-index caught that after the
fact; generating removes the class.

The curated summary and trigger move into each SKILL.md as `summary:` and
`use_when:`, carried over verbatim from the existing table rather than derived
from `description:` — description is a paragraph written for model selection,
and truncating it would have produced a worse table than the one it replaced.
Knowledge now lives once, next to the skill it describes, which is the argument
that made a hand-maintained index the wrong shape to begin with.

The table is written between markers, so the wiring docs, the relationships
tree and the trigger table below it are untouched — those are prose, not data.
Rows are alphabetical now; the conceptual grouping the old order carried lives
in the relationships tree, which is the better place for it. A fourth column
shows each skill's surfaces, which is what makes #29's field visible rather
than merely enforced.

bin/check-index and its test are deleted: a generated table cannot drift in
either direction, so `generate-index --check` subsumes both of its assertions.
Verified by mutation — deleting the tdd row turns `task check` red with
"SKILLS_INDEX.md is out of date".

Closes #29
Bump-Type: minor
2026-08-29 11:23:14 +02:00

4.4 KiB

name, surfaces, summary, use_when, description
name surfaces summary use_when description
web-shot
claude-code
library
Screenshot a running web UI via a koala k3s Playwright job Visual verification of a running UI when no local browser exists Screenshot any running web UI by spawning a one-shot Playwright Job on the koala k3s cluster. Auto-detects the calling host's Tailscale name so a dev server on flamingo:8099, iguana:3000 or koala:8181 just works. Use when the user asks for a screenshot, visual verification, "what does the UI look like", or any time chromium / firefox / a browser is requested but none is installed on the host.

web-shot

Screenshot a locally-running web UI without installing a browser on the agent's host.

Mechanism

  1. shot.sh builds a k8s Job that runs mcr.microsoft.com/playwright:v1.49.0-jammy on koala's k3s cluster.
  2. hostNetwork: true is not used — the pod uses cluster DNS so Tailscale Magic DNS resolves flamingo, iguana, koala directly when the koala node has Tailscale up (it does).
  3. The pod renders the URL with chromium, drops PNGs into an emptyDir, then sleeps briefly so kubectl cp can pull the files out.
  4. PNGs land in ./screenshots/ (or --out DIR) on the agent's host.

Prerequisites

  • kubectl on the calling host with a kubeconfig pointing at koala's k3s.
  • The dev server binds 0.0.0.0 (not 127.0.0.1) so pods on koala can reach it across Tailscale. For Go: http.ListenAndServe(":8099", ...). For Node: --host 0.0.0.0. For Vite: --host.
  • The dev server's host (flamingo, iguana, koala, …) is reachable on Tailscale and Magic DNS resolves the short hostname.

Usage

shot.sh ships beside this SKILL.md, so resolve it from wherever the harness installed the skill rather than from a checkout path — an absolute ~/dev/... went stale the first time the repo moved and cost a caller three hand-rolled Job attempts before they found the working script (#26).

# Claude Code installs the plugin; Crush/Pi/OpenCode get ~/.agents/skills.
SHOT=$(ls ~/.claude/plugins/marketplaces/*/skills/web-shot/shot.sh \
          ~/.agents/skills/web-shot/shot.sh 2>/dev/null | head -1 || true)
[ -n "$SHOT" ] || { echo "web-shot not installed on this host: run install.sh or the plugin install" >&2; exit 1; }

# auto-detect Tailscale hostname, screenshot port 8099 root
"$SHOT" --port 8099

# explicit URL
"$SHOT" --url http://flamingo:5173

# capture a search state too (types into input[name=q])
"$SHOT" --port 8181 --search agentsquad

# different output dir
"$SHOT" --port 3000 --out /tmp/shots

Flags

Flag Default Notes
--port N — Host port. Combined with --host and --path.
--path P / URL path after the host:port.
--host H auto via tailscale status Override the hostname pods will dial.
--url U — Full URL. Overrides --host, --port, --path.
--search Q — Also capture a search state — types Q into input[name=q].
--out D ./screenshots Output dir (created if missing).
--name N web-shot Job name prefix.
-h — Show usage.

Output

  • <out>/home.png — initial page.
  • <out>/search.png — only when --search was passed.

Failure modes

  • kubectl: command not found → install kubectl + tailscale-mode kubeconfig.
  • connection refused from the pod → dev server bound to 127.0.0.1, fix the bind.
  • No matches for selector when --search was given → page lacks input[name=q]. Use a project-specific script or rerun without --search.
  • Image pull slow on first run → ~1GB playwright image cached on koala after first use.

When NOT to use

  • The site needs auth / cookies / login state — extend the script or use a project-local Playwright suite.
  • You need PDF, video, or interaction more elaborate than "type a query and screenshot". Promote to a real Playwright test under the project repo.