Files
skills/skills/web-shot/SKILL.md
T
mathiasandClaude Opus 5 56a947b2a0 refactor(plugin)!: ship as a Claude Code plugin, one dir link per harness
Skills move to skills/<name>/SKILL.md and the repo gains both manifests, so
it is now a marketplace hosting exactly one plugin whose root is the repo
root (source: "."). Claude Code installs it from git; no symlinks involved.

Why: install.sh wired the library into every consuming repo as an ABSOLUTE
symlink to $CHECKOUT_DIR. The checkout moved three times, most recently when
local-dev@1966d5a dropped the embedded .skills/ copy, and nothing migrated
the links — 243 dangling links across 12 repos, hidden from git by the
**/.claude/skills/ ignore rule. Worse, ~/dev spans two path roots
(/Users/mathias on the iCloud-shared Macs, /home/mathias on koala), so an
absolute link stored there is broken on one side by construction. Re-running
the installer cannot fix that; only removing the mechanism can.

install.sh keeps the harnesses with no plugin system and drops from 42 links
per harness to one directory link, via the convergent ~/.agents/skills
convention that Pi and OpenCode both read:

  ~/.agents/skills          -> $CHECKOUT_DIR/skills
  ~/.config/crush/skills    -> ~/.agents/skills
  ~/.config/opencode/skills -> ~/.agents/skills

wire_claude_repo is deleted outright rather than gated behind a flag — on a
mixed-root fleet it cannot be made correct. Antigravity and Vibe targets go
too; both unused. CHECKOUT_DIR keeps its host-local default deliberately:
pointing it into ~/dev would put a git working tree inside iCloud with two
concurrent writers.

Taskfile drops five near-identical wiring loops (they had already drifted)
and delegates to install.sh. `task check` gains frontmatter validation, a
stray-root-entry gate, and manifest/tag version parity — the loose
secret-hygiene.md sat unloadable for months because nothing checked layout.

Verified: claude plugin validate . passes clean; a probe skill loaded as
skills:zzprobe through --plugin-dir; task check green at 42 skills.

Refs: #23
Bump-Type: minor

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
2026-08-23 14:29:51 +02:00

3.7 KiB

name, description
name description
web-shot 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

# auto-detect Tailscale hostname, screenshot port 8099 root
~/dev/.skills/web-shot/shot.sh --port 8099

# explicit URL
~/dev/.skills/web-shot/shot.sh --url http://flamingo:5173

# capture a search state too (types into input[name=q])
~/dev/.skills/web-shot/shot.sh --port 8181 --search agentsquad

# different output dir
~/dev/.skills/web-shot/shot.sh --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.