diff --git a/AGENTS.MD b/AGENTS.MD index cb8cadc..3c9c3bd 100644 --- a/AGENTS.MD +++ b/AGENTS.MD @@ -20,7 +20,7 @@ Codex CLI output: avoid Markdown tables by default; they render poorly there. Us - Skill descriptions: short generic trigger phrase, not summary; no personal names, long paths, or workflow narration unless needed for routing. - Skill frontmatter: quote `description`; after SKILL.md edits, YAML-parse frontmatter before commit. - After adding/removing/renaming a skill: run `scripts/sync-skills` (mirrors into `~/.claude/skills` + `~/.codex/skills`, prunes dead links). `--dry-run` to preview. -- Upstream sync: treat `steipete/agent-scripts` as a source to mine, not a branch to merge. Preserve Bram-local skills/helpers (`hermes-win`, `hermes-dashboard`, `autoreview`, `bram-maintainer-loop-v2`, `tdd`, `to-prd`, `to-issues`, `grill-with-docs`). Scrub or skip non-Bram personal/product assumptions; do not adopt broken symlinks unless Bram explicitly configures that repo. Mining marker + flow: `docs/upstream-mined.md`. +- Upstream sync: treat `steipete/agent-scripts` as a source to mine, not a branch to merge. Preserve Bram-local skills/helpers (`hermes-win`, `hermes-dashboard`, `autoreview`, `bram-maintainer-loop-v2`, `tdd`, `to-prd`, `to-tickets`, `grill-with-docs`). Scrub or skip non-Bram personal/product assumptions; do not adopt broken symlinks unless Bram explicitly configures that repo. Mining marker + flow: `docs/upstream-mined.md`. - Read `~/Projects/agent-scripts/tools.md` when the tool catalog matters. ## Routing diff --git a/CHANGELOG.md b/CHANGELOG.md index ca9b71d..102ed26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ summary: Timeline of guardrail helper changes mirrored from Sweetistics and rela # Changelog +## 2026-08-19 — Recent Skill Refresh +- Replaced the retired `to-issues` route with `to-tickets`, refreshed the Matt Pocock TDD/setup/ticket bundle from current upstream, upgraded Peekaboo CLI and guidance to v4, and updated browser automation for cmux-first routing plus fail-closed Chrome extension relay use. + ## 2026-08-19 — Diagnosis, Design, and Writing Skills - Added Matt Pocock's `diagnosing-bugs` workflow plus minimally adapted Codex-native copies of PStack's `architect` and `blast-radius`, and an unchanged PStack `unslop` workflow, with upstream attribution, MIT notices, UI metadata, validation, and local skill-mirror discovery. diff --git a/README.md b/README.md index 2957286..8e8d8e0 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Treat this repo as Bram's canonical shared agent setup and portable helper mirro Upstream intake from `steipete/agent-scripts`: - Mine selectively; do not merge wholesale. -- Preserve Bram-local skills/helpers: `hermes-win`, `hermes-dashboard`, `autoreview`, `bram-maintainer-loop-v2`, `tdd`, `to-prd`, `to-issues`, `grill-with-docs`. +- Preserve Bram-local skills/helpers: `hermes-win`, `hermes-dashboard`, `autoreview`, `bram-maintainer-loop-v2`, `tdd`, `to-prd`, `to-tickets`, `grill-with-docs`. - Skip or scrub non-Bram personal/product defaults before adopting docs or skills. - Do not adopt symlinks to missing repos unless Bram explicitly configures them. - Prefer generic helper/script fixes, CI smoke checks, and non-personal skill improvements. diff --git a/docs/upstream-mined.md b/docs/upstream-mined.md index a527dd5..5fcbd03 100644 --- a/docs/upstream-mined.md +++ b/docs/upstream-mined.md @@ -3,6 +3,7 @@ - Reviewed `upstream/main` through: `6878dd818b34659a925ec45fb7225a81b6a5c69a` (2026-07-22, reviewed 2026-07-23) - Full classification report of the 232-commit pass (through `0798fed`): 19 groups already present, 12 skip (Peter-personal), 19 port candidates, 2 preserved-skill conflict families (autoreview, maintainer-loop). Port candidates pending Bram triage. - 2026-07-23 pass (`0798fed..6878dd8`, 1 commit): ported codex-first git-mechanics mandate, guarded CI waits, fresh work-order sessions, AGENTS.md-only rule; scrubbed openclaw watcher example + CLAUDE.md-symlink claim; kept Bram divergences (no fast_mode, loopback-only gate, short description, `$bram-maintainer-loop-v2` pointer). +- 2026-08-19 targeted refresh: mined `skills/browser-use` through `2e320ff086cfc82d01037edab0683857d48c1698`; combined current relay hardening with Bram's cmux-first route. Global marker unchanged because this was not a full upstream classification pass. ## Flow (repeat per pass) diff --git a/skills/browser-use/SKILL.md b/skills/browser-use/SKILL.md index 6d85252..d7313f9 100644 --- a/skills/browser-use/SKILL.md +++ b/skills/browser-use/SKILL.md @@ -1,24 +1,33 @@ --- name: browser-use -description: "Browser automation in cmux or Chrome DevTools; no AppleScript." +description: "Browser automation in cmux or signed-in Chrome; fail-closed relay fallback." --- # Browser Use -Use this for browser tasks in cmux or against an existing Chrome session. +_Source: [steipete/agent-scripts](https://github.com/steipete/agent-scripts), browser-use through `2e320ff0`; combined with Bram's cmux-first routing._ -Hard rule: use `cmux browser` in cmux; otherwise use `mcporter` `chrome-devtools`. Do not fall back to AppleScript, `osascript`, GUI scripting, or macOS `open` for browser control. +Control a browser without AppleScript or generic GUI scripting. Preserve the user's signed-in state when the task depends on cookies, SSO, device trust, or extensions. -## cmux Browser +## Route -Prefer this path when `cmux browser status` prints `enabled`. +1. Use `cmux browser` when `cmux browser status` reports `enabled`. +2. Otherwise use the callable Codex `Chrome` or `Chrome [Internal]` plugin when available in the active session. Installed on disk is not enough. +3. Otherwise use the OpenClaw extension-backed Chrome DevTools MCP route through mcporter. +4. Use full-profile direct DevTools attachment only as an explicit last fallback. + +Never substitute an isolated browser, Playwright, Puppeteer, AppleScript, `osascript`, generic GUI scripting, or macOS `open` unless the user explicitly asked for a new or isolated browser. Peekaboo is allowed only for Chrome or extension setup, native browser chrome, and visible prompts. + +For a rendered-browser bug, prove behavior in the selected real browser. Treat `curl`, source inspection, API checks, and isolated tests as supporting evidence, not live UI proof. + +## cmux browser ```bash cmux browser status cmux --json browser open https://example.com --focus false ``` -Use the returned `surface_ref` for the task: +Use the returned `surface_ref`: ```bash cmux browser surface:25 get url @@ -32,63 +41,115 @@ cmux browser surface:25 eval 'document.title' cmux browser surface:25 screenshot --out /tmp/cmux-browser.png ``` -Use explicit `--text` / `--value` when a mutating command also has flags; otherwise trailing flags can be parsed as input text. Run actions sequentially and re-snapshot after DOM changes; refs from older snapshots can go stale. +Use explicit `--text` and `--value` when a mutating command also has flags. Otherwise trailing flags can be parsed as input text. Run actions sequentially and re-snapshot after DOM changes because older refs can go stale. -Use `cmux identify --json` when you need caller workspace/window/surface context. If a snapshot or eval returns `js_error`, fall back to: +Use `cmux identify --json` when caller workspace, window, or surface context matters. If snapshot or evaluation returns `js_error`, fall back to: ```bash cmux browser surface:25 get text body cmux browser surface:25 get html body ``` -cmux uses WKWebView. Known gaps: viewport emulation, offline emulation, tracing/screencast, network interception, and low-level raw input. +cmux uses WKWebView. Known gaps include viewport and offline emulation, tracing, screencast, network interception, and low-level raw input. -## Check MCP +## OpenClaw extension relay -Use this path when cmux browser is unavailable and Chrome DevTools MCP is the target. +The Chrome DevTools MCP call is the agent-facing interface. The OpenClaw extension is its authenticated transport. Require relay-only routing so a missing relay cannot silently become direct DevTools attachment: ```bash -npx -y mcporter list chrome-devtools --schema -npx -y mcporter call chrome-devtools.list_pages --args '{}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools. ``` -If `list_pages` fails with `DevToolsActivePort`, restart the mcporter daemon and retry: +A Chrome "Allow remote debugging?" prompt or relay-policy error means the extension transport was not used. + +OpenClaw creates a random per-host relay key. The extension and same-host clients use nonce-bound mutual HMAC proofs. The reusable key must not enter URLs, child process arguments, configuration, command output, chat, logs, or screenshots. + +New pairings default to all eligible ordinary tabs except tabs paused in the popup. Existing pairings keep their stored mode. In selected-tabs mode, membership in the Chrome tab group named `OpenClaw` is the sharing boundary. Restricted pages, incognito tabs, other profiles, and ineligible URLs stay excluded. + +Direct remote Gateway pairing does not create a local relay for local mcporter. Do not copy remote secrets or create ad-hoc SSH tunnels around that boundary. + +### Setup and repair + +- Run `openclaw browser extension install` before loading the unpacked extension. It installs a stable copy and registers its deterministic Chrome ID. +- Use `openclaw browser extension status --json`. Require no reported issues and `manualSetupRequired: false`. +- Confirm Settings reports automatic setup ready and the popup reports connected. +- If the extension attempted native messaging before installation, restart Chrome once. Chrome caches the miss for the process lifetime. +- After pairing or route changes, run `npx -y mcporter daemon stop`. A restart can reuse a child with a dead upstream socket; a stop forces a clean child on the next call. +- MCPorter discovers the relay through `openclaw browser extension cdp --json`. A source-checkout launcher may need `MCPORTER_CHROME_DEVTOOLS_RELAY_TIMEOUT_MS=15000` for its freshness build. + +Do not run the CDP discovery command or inspect process arguments as routine diagnostics because either can expose relay credentials. + +### Fail-closed readiness proof + +Require every condition: + +1. Extension status reports the stable copy and exact native registrations with no issues. +2. The popup reports connected and the target tab is eligible and not paused. +3. The mcporter daemon was stopped after pairing or route changes. +4. A call with `MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require` succeeds. +5. Selection and evaluation both succeed in a known disposable tab. ```bash -npx -y mcporter daemon restart -npx -y mcporter call chrome-devtools.list_pages --args '{}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.list_pages --args '{}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.select_page --args '{"pageId":9}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.evaluate_script --args '{"function":"() => ({title: document.title, href: location.href})"}' --output json ``` -If it still fails, stop and say Chrome DevTools MCP is unavailable. Do not use AppleScript. +A relay-policy error means the extension route is unavailable. Report or repair it instead of retrying without `require`. -Avoid noisy recovery loops. Repeated MCP/browser restarts can trigger -reconnect/login prompts and alerts. Try once, then pause and choose a quieter -path. +## Chrome DevTools flow -## Typical Flow +Use current snapshot UIDs. Prefer DOM snapshots over screenshots unless layout matters. ```bash -# pick the page id from list_pages -npx -y mcporter call chrome-devtools.select_page pageId=9 --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.list_pages --args '{}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.select_page --args '{"pageId":9}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.take_snapshot --args '{}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.click --args '{"uid":"1_38","includeSnapshot":true}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.fill --args '{"uid":"1_13","value":"text","includeSnapshot":true}' --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.evaluate_script --args '{"function":"() => document.title"}' --output json +``` -# inspect page -npx -y mcporter call chrome-devtools.take_snapshot --args '{}' --output text +Capture state before the action, perform the requested interaction, then snapshot or evaluate the rendered result. Keep secrets out of DOM, input, network, console, and screenshot output. Return only safe shapes for credential checks, such as present or absent, length, status code, or account name. -# navigate selected page -npx -y mcporter call chrome-devtools.navigate_page url=https://example.com --output text +If automation is unavailable, report the verification gap instead of switching to prohibited or isolated tooling. -# click an element uid from the latest snapshot -npx -y mcporter call chrome-devtools.click uid=1_38 includeSnapshot=true --output text +## Argument and output mechanics -# type/fill -npx -y mcporter call chrome-devtools.fill uid=1_13 value='text' includeSnapshot=true --output text +`--args` accepts inline JSON only. It does not read `@file`. Flag-style named arguments do: -# run JS, keep secrets out of output -npx -y mcporter call chrome-devtools.evaluate_script --args '{"function":"() => document.title"}' --output json +```bash +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.navigate_page url=@/tmp/target-url.txt --output text +MCPORTER_CHROME_DEVTOOLS_RELAY_POLICY=require npx -y mcporter call chrome-devtools.evaluate_script function=@/tmp/probe.js --output json ``` -Use `take_snapshot` before actions and use current `uid` values only. Avoid `take_screenshot` unless visual layout matters. +Use a mode-0600 file for sign-in URLs, magic links, callbacks, and multiline scripts so their values do not enter shell history, process arguments, or captured output. + +Other mechanics: + +- Interactive navigation, snapshots, and consent pages can exceed the short default timeout. Use `--timeout 30000`. +- `take_screenshot` paths are confined to configured workspace roots. When necessary, omit `filePath`, read base64 JSON output, and decode it locally. +- `new_page` can fail for an unavailable or unshared target. Prefer navigating an eligible shared tab. +- Run `npx -y mcporter list chrome-devtools --schema` instead of guessing parameter names. + +## Clicks that do not click + +A UID click can report success while a page ignores the synthetic event. Verify state after every activation. + +When click no-ops, use `press_key` with `Tab`, `Shift+Tab`, or `Enter`, and confirm focus with a screenshot first. Never send blind Enter on a consent screen. + +Navigation and re-rendering invalidate UIDs. Re-run `take_snapshot` after each state change. + +## Empty relay mid-task + +An empty page list usually means there are no eligible tabs, the tab was paused, selected-tabs mode lost its group members, or the extension disconnected. Confirm Chrome is running, check the popup connection and pause state, then check the access mode. + +Restarting mcporter cannot repair extension disconnection, tab eligibility, or access policy. Do not switch to full-profile attachment or an isolated browser to hide the gap. + +## Legacy full-profile fallback + +Use direct attachment only after the callable plugin and authenticated local extension relay are unavailable. It exposes the full real-profile tab set and can show Chrome's blocking remote-debugging prompt. -## Secret Handling +Approve one visible, unambiguous prompt, then retry `list_pages` once. If the prompt is absent, ambiguous, or the retry fails, stop. Never loop approvals, repeatedly restart Chrome or mcporter, or kill browser processes. -Never print tokens/passwords from page DOM, network logs, or inputs. For token checks, return shape only: present/absent, length, status code, account/org name. +Verify the intended real-profile tabs before acting and label this route as full-profile direct attachment, never extension relay success. diff --git a/skills/github-project-triage/SKILL.md b/skills/github-project-triage/SKILL.md index cd28af2..e1041fa 100644 --- a/skills/github-project-triage/SKILL.md +++ b/skills/github-project-triage/SKILL.md @@ -120,7 +120,7 @@ Never work multiple tickets at once in one worker. For each item: - Go: performance improvements unless complexity rises too much; bugfixes with repro/root cause and verification path; small UI/UX tweaks; docs fixes; narrow test/internal fixes; low-risk dependency/CI cleanup with green proof. - Ask first: new features, product/vision choices, broad behavior changes, risky dependencies, security-sensitive changes without strong proof, live-provider work without usable credentials, anything that cannot be end-to-end tested. - Refactor preference: choose a clean bounded refactor when it is the better fix for an autonomous item; do not use "small patch" as the default if it leaves worse design. -3. Implement or fix the PR in the best maintainable way. Use `tdd` for behavior changes unless trivial/docs-only: start with a failing regression or characterization test when feasible, make it pass, then refactor within scope. Use `to-prd` or `to-issues` when the item is too vague or too large. +3. Implement or fix the PR in the best maintainable way. Use `tdd` for behavior changes unless trivial/docs-only: start with a failing regression or characterization test when feasible, make it pass, then refactor within scope. Use `to-prd` or `to-tickets` when the item is too vague or too large. 4. Verify locally and live end-to-end when possible. For UI behavior, use the repo's expected live UI proof path. For API/provider behavior, use a real usable key/account through the expected secret workflow when available. If access is missing, stop before pretending the item is done and ask Bram for the exact access or waiver. 5. Run `autoreview` before commit/land unless trivial/docs-only or explicitly skipped; address accepted/actionable findings. 6. Ensure CI is green when CI work is authorized. Do not push, merge, close, rerun, or mutate public state without matching permission. diff --git a/skills/peekaboo/SKILL.md b/skills/peekaboo/SKILL.md index f58109a..a573941 100644 --- a/skills/peekaboo/SKILL.md +++ b/skills/peekaboo/SKILL.md @@ -1,52 +1,122 @@ --- name: peekaboo -description: "macOS screenshots, UI inspection, clicks, typing, app/window automation." +description: "Peekaboo v4 macOS screenshots, inspection, and UI automation." --- # Peekaboo -Use for macOS screen capture, UI inspection, and GUI automation. +Use Peekaboo v4 for native macOS capture, Accessibility inspection, and UI automation. Prefer exact background delivery so the user's foreground app, keyboard focus, and physical cursor stay untouched. -## Binary +_Source: [openclaw/Peekaboo v4.2.0](https://github.com/openclaw/Peekaboo/releases/tag/v4.2.0), signed release and v4 command contract._ -- Prefer `peekaboo` on PATH. -- Use `~/bin/peekaboo` only when Bram has installed a local build there. -- Check first: `peekaboo --version || ~/bin/peekaboo --version`. +## Resolve the binary -## Safety - -- Check permissions before capture/automation: `peekaboo permissions status --json`. -- Screenshot needs Screen Recording; clicks/typing/window control need Accessibility. -- Prefer `--json` for machine parsing and `--no-remote` when testing local TCC. -- Do not click/type/destructively automate unless user asked or target is a controlled test. - -## Common Commands +Prefer `peekaboo` on `PATH`. Bram's release install lives in `~/.local/bin`, which precedes Homebrew. Check the selected binary before relying on syntax: ```bash PB="${PEEKABOO_BIN:-$(command -v peekaboo || true)}" -[ -n "$PB" ] || PB="$HOME/bin/peekaboo" [ -x "$PB" ] || { echo "peekaboo missing"; exit 1; } +"$PB" --version --json +``` + +Require major version 4. Version 3 used removed commands such as top-level `list`, `image`, `hotkey`, and `click --coords`. + +## Runtime host and permissions + +- Use `bridge status --verbose --json` to see whether Peekaboo selected its reusable daemon, GUI Bridge, or local runtime. +- Check `permissions status --all-sources --json`. Grant Screen Recording, Accessibility, and Event Synthesizing to the selected runtime source, not merely to the invoking terminal. +- When an installed `Peekaboo.app` must provide the GUI Bridge, launch it without focus using `open -gj -a Peekaboo`, then confirm the selected socket and `hostKind`. +- Prefer Bridge capture from SSH, LaunchAgents, Codex, and other background sessions. `--no-remote` is a local-debug override, not the default proof path. +- Never run an unsigned or ad-hoc build against saved TCC or Keychain state. + +## v4 command names + +- Inventory: `app list`, `window list`, and `screen list`. +- Screenshots and visual maps: `see`. +- Accessibility-only inspection: `see --tree --no-screenshot`. +- Standalone keys and chords: `press`. +- Named Accessibility actions: `action`. +- Coordinate clicks: `click --at x,y`. +- Drags: `drag --from x,y --to x,y`. +- Stable postconditions: `verify` instead of fixed sleeps. + +Use `tools --json`, `tools describe --json`, `learn`, and ` --help` when the command surface matters. + +## Background-first safety + +- Supply an exact `--app`, `--pid`, `--window-id`, or fresh snapshot target for mutations. +- Keep background delivery as the default. Add `--foreground` only when the user authorized focus or shared-pointer interaction, or when the target demonstrably rejects background delivery. +- Shared-cursor and targetless global input require explicit foreground mode. This includes `move`, `drag`, targetless or smooth scrolling, targetless keyboard input, and long-press clicks. +- Do not click, type, paste, quit, move, resize, or otherwise mutate UI unless the user asked or the target is a controlled test. +- Re-observe after every mutation. Never replay an indeterminate action blindly. +- Treat element IDs as opaque and valid only for the captured state. Use a new `see` after navigation or re-rendering. + +## Common commands + +```bash +"$PB" permissions status --all-sources --json +"$PB" bridge status --verbose --json + +"$PB" screen list --json +"$PB" app list --include-hidden --include-background --json +"$PB" window list --app Safari --json + +# Screenshot only. +"$PB" see --no-elements --mode screen --path /tmp/screen.png --json -"$PB" permissions status --json -"$PB" list screens --json -"$PB" list apps --json -"$PB" list windows --app Safari --json -"$PB" image --mode screen --screen-index 0 --path /tmp/screen.png --json --no-remote -"$PB" see --app frontmost --path /tmp/frontmost.png --json --annotate +# Visual map with element IDs and snapshot ID. +"$PB" see --app Safari --annotate --path /tmp/safari-see.png --json + +# Accessibility tree without pixels. +"$PB" see --app Safari --tree --no-screenshot --json + +# Use IDs and snapshot from a fresh observation. +"$PB" click --on "$ELEMENT_ID" --snapshot "$SNAPSHOT_ID" --json +"$PB" action AXPress --on "$ELEMENT_ID" --snapshot "$SNAPSHOT_ID" --json + +# Process-targeted background keyboard delivery. +"$PB" type "text" --app TextEdit --json +"$PB" press Return --app TextEdit --window-id 1234 --json +"$PB" paste "text" --app TextEdit --json + +"$PB" verify --app Safari --window-exists --timeout 2s --json "$PB" tools --json -"$PB" learn -"$PB" click --coords 100,100 --json -"$PB" type "text" --json ``` +## Click coordinates safely + +Screenshot pixels are not click coordinates. `click --at` uses logical points. With target flags, coordinates are relative to the resolved window. Without a target they are global screen coordinates. Add `--global` when targeted coordinates must remain screen-global. + +A background coordinate click requires a fresh exact-window snapshot: + +```bash +"$PB" window list --app Safari --json +"$PB" see --app Safari --window-id 12345 --path /tmp/safari.png --json +"$PB" click --window-id 12345 --at 20,40 --snapshot "$SNAPSHOT_ID" --json +``` + +Peekaboo revalidates the captured process generation, window ID, and bounds before dispatch. If it cannot establish an exact receipt, let the command fail. Do not guess or silently promote to foreground mode. + +For element work, prefer IDs from a fresh `see` and pass the snapshot explicitly. After an action changes UI, capture a new snapshot. + +## Input strategies + +Use these only when diagnosing delivery paths: + +- `--input-strategy actionOnly` proves live Accessibility re-resolution and action invocation. +- `action AXPress` is the cleanest direct Accessibility smoke test. +- `--input-strategy synthOnly` proves coordinate resolution and event delivery, but requires an independent state check. +- Coordinates cannot use `actionOnly`. + ## Workflow -1. Resolve `PB` as above and confirm version when install state matters. -2. Run `permissions status --json`; if missing TCC, report exact missing grant. -3. For screenshots, use `image`; include `--path`, `--json`, and usually `--no-remote`. -4. For element targeting, run `see --json --annotate`, then click by element id/snapshot. -5. For long-running/change-aware screen capture, use `capture live`; for video frame sampling, use `capture video`. -6. Use `tools --json` for command/tool discovery and `learn` when the full agent guide is useful. -7. Verify output files with `sips -g pixelWidth -g pixelHeight ` or view the image. +1. Resolve the v4 binary and record its version. +2. Check the selected runtime host and permissions. +3. Resolve the target with `app list` or `window list`; prefer PID or window ID for exact mutation. +4. Observe with `see --no-elements`, ordinary `see`, or `see --tree --no-screenshot`. +5. Interact in the background with an exact target and fresh snapshot. +6. Verify every mutation with a new observation or `verify` predicate. +7. Use explicit foreground mode only for authorized shared cursor or confirmed application limitations. +8. Verify image artifacts with `sips -g pixelWidth -g pixelHeight ` or view them locally. -Docs: `~/Projects/Peekaboo/docs/commands/`. +Source of truth: live help plus the [Peekaboo command docs](https://github.com/openclaw/Peekaboo/tree/main/docs/commands). When copied examples and live help disagree, use live help. diff --git a/skills/setup-matt-pocock-skills/SKILL.md b/skills/setup-matt-pocock-skills/SKILL.md index 46293e8..d7f25b4 100644 --- a/skills/setup-matt-pocock-skills/SKILL.md +++ b/skills/setup-matt-pocock-skills/SKILL.md @@ -1,16 +1,18 @@ --- name: setup-matt-pocock-skills -description: "Configure this repo for the engineering skills — set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills." +description: "Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills." disable-model-invocation: true --- # Setup Matt Pocock's Skills +_Source: [mattpocock/skills](https://github.com/mattpocock/skills), synced from `main` at `885e2ca4`; adapted to use Bram's canonical `AGENTS.MD` policy._ + Scaffold the per-repo configuration that the engineering skills assume: -- **Issue tracker** — where issues live (GitHub by default; local markdown is also supported out of the box) -- **Triage labels** — the strings used for the five canonical triage roles -- **Domain docs** — where `CONTEXT.md` and ADRs live, and the consumer rules for reading them +- **Issue tracker**: where issues live. GitHub is the default; local Markdown is also supported. +- **Triage labels**: the strings used for the five canonical triage roles. +- **Domain docs**: where `CONTEXT.md` and ADRs live, and the consumer rules for reading them. This is a prompt-driven skill, not a deterministic script. Explore, present what you found, confirm with the user, then write. @@ -20,66 +22,64 @@ This is a prompt-driven skill, not a deterministic script. Explore, present what Look at the current repo to understand its starting state. Read whatever exists; don't assume: -- `git remote -v` and `.git/config` — is this a GitHub repo? Which one? -- `AGENTS.md` and `CLAUDE.md` at the repo root — does either exist? Is there already an `## Agent skills` section in either? -- `CONTEXT.md` and `CONTEXT-MAP.md` at the repo root -- `docs/adr/` and any `src/*/docs/adr/` directories -- `docs/agents/` — does this skill's prior output already exist? -- `.scratch/` — sign that a local-markdown issue tracker convention is already in use -- Is the `triage` skill installed? (a `triage` skill folder alongside this one, or `triage` in your available skills.) This decides whether Section B runs at all. -- Monorepo signals — a `pnpm-workspace.yaml`, a `workspaces` field in `package.json`, or a populated `packages/*` with its own `src/`. Present only in a genuinely large multi-package repo; their absence means single-context, which is almost every repo. +- `git remote -v` and `.git/config`: is this a GitHub repo? Which one? +- `AGENTS.MD` and `AGENTS.md` at the repo root: does either exist? Is there already an `## Agent skills` section? +- `CONTEXT.md` and `CONTEXT-MAP.md` at the repo root. +- `docs/adr/` and any `src/*/docs/adr/` directories. +- `docs/agents/`: does this skill's prior output already exist? +- `.scratch/`: a sign that a local-Markdown issue tracker convention is already in use. +- Is the `triage` skill installed? A `triage` skill folder beside this one or `triage` in the available skills decides whether section B runs. +- Monorepo signals: a `pnpm-workspace.yaml`, a `workspaces` field in `package.json`, or a populated `packages/*` with its own `src/`. These are present only in a genuinely large multi-package repo. Their absence means single-context, which fits almost every repo. + +Ignore `CLAUDE.md`. Bram repositories use an AGENTS instruction file as canonical. ### 2. Present findings and ask -Summarise what's present and what's missing. Then take the sections in order — one section, one answer, then the next. +Summarize what's present and what's missing. Then take the sections in order. One section, one answer, then the next. -Lead each section with the recommended answer so the user can accept it in a word. Give a one-line explainer only when the choice genuinely branches; skip the section entirely when exploration already settled it (Section B when `triage` isn't installed, Section C when there's no monorepo). +Lead each section with the recommended answer so the user can accept it in a word. Give a one-line explanation only when the choice genuinely branches. Skip the section when exploration already settled it, such as section B when `triage` isn't installed or section C when there is no monorepo. -**Section A — Issue tracker.** +**Section A: Issue tracker.** -> Explainer: The "issue tracker" is where issues live for this repo. Skills like `to-tickets`, `triage`, `to-spec`, and `qa` read from and write to it — they need to know whether to call `gh issue create`, write a markdown file under `.scratch/`, or follow some other workflow you describe. Pick the place you actually track work for this repo. +> The issue tracker is where issues live for this repo. Skills such as `to-tickets`, `triage`, and `to-spec` read from and write to it. They need to know whether to call `gh issue create`, write a Markdown file under `.scratch/`, or follow another workflow. -Default posture: these skills were designed for GitHub. If a `git remote` points at GitHub, propose that. If a `git remote` points at GitLab (`gitlab.com` or a self-hosted host), propose GitLab. Otherwise (or if the user prefers), offer: +Default posture: these skills were designed for GitHub. If a `git remote` points at GitHub, propose that. If a remote points at GitLab, propose GitLab. Otherwise, or if the user prefers, offer: -- **GitHub** — issues live in the repo's GitHub Issues (uses the `gh` CLI) -- **GitLab** — issues live in the repo's GitLab Issues (uses the [`glab`](https://gitlab.com/gitlab-org/cli) CLI) -- **Local markdown** — issues live as files under `.scratch//` in this repo (good for solo projects or repos without a remote) -- **Other** (Jira, Linear, etc.) — ask the user to describe the workflow in one paragraph; the skill will record it as freeform prose +- **GitHub**: issues live in the repository's GitHub Issues and use the `gh` CLI. +- **GitLab**: issues live in GitLab Issues and use the [`glab`](https://gitlab.com/gitlab-org/cli) CLI. +- **Local Markdown**: issues live under `.scratch//` in this repository. +- **Other**: ask the user to describe the workflow in one paragraph and record it as freeform prose. -Record the choice in `docs/agents/issue-tracker.md`. The GitHub and GitLab templates carry a "PRs as a request surface" flag, defaulted **off** — leave it off and don't raise it; a user who wants external PRs in the triage queue can flip the flag in the file later. +Record the choice in `docs/agents/issue-tracker.md`. The GitHub and GitLab templates carry a "PRs as a request surface" flag, defaulted off. Leave it off and don't raise it. A user who wants external PRs in the triage queue can change the file later. -**Section B — Triage label vocabulary.** Skip this section entirely if the `triage` skill isn't installed (exploration told you) — an uninstalled skill needs no labels. +**Section B: Triage label vocabulary.** Skip this section if `triage` isn't installed. If it is installed, ask exactly one question: -> Do you want to keep the default triage labels? (recommended: **yes**) +> Do you want to keep the default triage labels? Recommended: yes. -The defaults are the five canonical roles, each label string equal to its name: `needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`. On **yes**, write them as-is. Only if the user says no — usually because their tracker already uses other names (e.g. `bug:triage` for `needs-triage`) — collect the overrides so `triage` applies existing labels instead of creating duplicates. +The defaults are the five canonical roles, each label string equal to its name: `needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`. On yes, write them as-is. Only if the user says no, usually because the tracker already uses other names, collect overrides so `triage` does not create duplicate labels. -**Section C — Domain docs.** Default to **single-context** — one `CONTEXT.md` + `docs/adr/` at the repo root. This fits almost every repo; write it without asking. +**Section C: Domain docs.** Default to single-context, with one `CONTEXT.md` and `docs/adr/` at the repository root. Write it without asking. -Offer **multi-context** — a root `CONTEXT-MAP.md` pointing to per-context `CONTEXT.md` files — only when exploration found monorepo signals. Then confirm which layout they want. +Offer multi-context, with a root `CONTEXT-MAP.md` pointing to per-context `CONTEXT.md` files, only when exploration found monorepo signals. Then confirm which layout the user wants. ### 3. Confirm and edit Show the user a draft of: -- The `## Agent skills` block to add to whichever of `CLAUDE.md` / `AGENTS.md` is being edited (see step 4 for selection rules) -- The contents of `docs/agents/issue-tracker.md`, `docs/agents/domain.md`, and `docs/agents/triage-labels.md` (the last only when `triage` is installed) +- The `## Agent skills` block for the repository's AGENTS file. +- `docs/agents/issue-tracker.md`. +- `docs/agents/domain.md`. +- `docs/agents/triage-labels.md`, only when `triage` is installed. -Let them edit before writing. +Let the user edit the draft before writing. ### 4. Write -**Pick the file to edit:** - -- If `CLAUDE.md` exists, edit it. -- Else if `AGENTS.md` exists, edit it. -- If neither exists, ask the user which one to create — don't pick for them. - -Never create `AGENTS.md` when `CLAUDE.md` already exists (or vice versa) — always edit the one that's already there. +Use the existing instruction file. Prefer `AGENTS.MD` when present, otherwise `AGENTS.md`. If neither exists, ask which casing to create. Never create or edit `CLAUDE.md`. -If an `## Agent skills` block already exists in the chosen file, update its contents in-place rather than appending a duplicate. Don't overwrite user edits to the surrounding sections. +If an `## Agent skills` block already exists, update it in place. Do not overwrite surrounding user content. The block: @@ -88,29 +88,29 @@ The block: ### Issue tracker -[one-line summary of where issues are tracked]. See `docs/agents/issue-tracker.md`. +[One-line summary of where issues are tracked]. See `docs/agents/issue-tracker.md`. ### Triage labels -[one-line summary of the label vocabulary]. See `docs/agents/triage-labels.md`. +[One-line summary of the label vocabulary]. See `docs/agents/triage-labels.md`. ### Domain docs -[one-line summary of layout — "single-context" or "multi-context"]. See `docs/agents/domain.md`. +[One-line summary of the single-context or multi-context layout]. See `docs/agents/domain.md`. ``` -Include the `### Triage labels` sub-block, and write `docs/agents/triage-labels.md`, only when `triage` is installed and Section B ran. When it isn't, both are omitted. +Include the `### Triage labels` block and write `docs/agents/triage-labels.md` only when `triage` is installed and section B ran. -Then write the docs files using the seed templates in this skill folder as a starting point: +Use the seed templates in this skill folder: -- [issue-tracker-github.md](./issue-tracker-github.md) — GitHub issue tracker -- [issue-tracker-gitlab.md](./issue-tracker-gitlab.md) — GitLab issue tracker -- [issue-tracker-local.md](./issue-tracker-local.md) — local-markdown issue tracker -- [triage-labels.md](./triage-labels.md) — label mapping (only if `triage` is installed) -- [domain.md](./domain.md) — domain doc consumer rules + layout +- [issue-tracker-github.md](./issue-tracker-github.md): GitHub issue tracker. +- [issue-tracker-gitlab.md](./issue-tracker-gitlab.md): GitLab issue tracker. +- [issue-tracker-local.md](./issue-tracker-local.md): local-Markdown issue tracker. +- [triage-labels.md](./triage-labels.md): label mapping, only if `triage` is installed. +- [domain.md](./domain.md): domain doc consumer rules and layout. -For "other" issue trackers, write `docs/agents/issue-tracker.md` from scratch using the user's description. +For another issue tracker, write `docs/agents/issue-tracker.md` from the user's description. ### 5. Done -Tell the user the setup is complete and which engineering skills will now read from these files. Mention they can edit `docs/agents/*.md` directly later — re-running this skill is only necessary if they want to switch issue trackers or restart from scratch. +Report which files changed and which engineering skills will read them. The user can edit `docs/agents/*.md` directly later. Re-run this skill only to switch trackers or restart the setup. diff --git a/skills/setup-matt-pocock-skills/domain.md b/skills/setup-matt-pocock-skills/domain.md index b548c53..e5257bc 100644 --- a/skills/setup-matt-pocock-skills/domain.md +++ b/skills/setup-matt-pocock-skills/domain.md @@ -5,8 +5,8 @@ How the engineering skills should consume this repo's domain documentation when ## Before exploring, read these - **`CONTEXT.md`** at the repo root, or -- **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic. -- **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src//docs/adr/` for context-scoped decisions. +- **`CONTEXT-MAP.md`** at the repo root if it exists: it points at one `CONTEXT.md` per context. Read each one relevant to the topic. +- **`docs/adr/`**: read ADRs that touch the area you're about to work in. In multi-context repos, also check `src//docs/adr/` for context-scoped decisions. If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved. @@ -42,10 +42,10 @@ Multi-context repo (presence of `CONTEXT-MAP.md` at the root): When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids. -If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`). +If the concept you need isn't in the glossary yet, that's a signal: either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`). ## Flag ADR conflicts If your output contradicts an existing ADR, surface it explicitly rather than silently overriding: -> _Contradicts ADR-0007 (event-sourced orders) — but worth reopening because…_ +> _Contradicts ADR-0007 (event-sourced orders), but worth reopening because..._ diff --git a/skills/setup-matt-pocock-skills/issue-tracker-github.md b/skills/setup-matt-pocock-skills/issue-tracker-github.md index 82cfbf5..b258aeb 100644 --- a/skills/setup-matt-pocock-skills/issue-tracker-github.md +++ b/skills/setup-matt-pocock-skills/issue-tracker-github.md @@ -1,6 +1,6 @@ # Issue tracker: GitHub -Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all operations. +Issues and specs for this repo live as GitHub issues. Use the `gh` CLI for all operations. ## Conventions @@ -11,7 +11,7 @@ Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all op - **Apply / remove labels**: `gh issue edit --add-label "..."` / `--remove-label "..."` - **Close**: `gh issue close --comment "..."` -Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone. +Infer the repo from `git remote -v`; `gh` does this automatically when run inside a clone. ## Pull requests as a triage surface @@ -23,7 +23,7 @@ When set to `yes`, PRs run through the same labels and states as issues, using t - **List external PRs for triage**: `gh pr list --state open --json number,title,body,labels,author,authorAssociation,comments` then keep only `authorAssociation` of `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, or `NONE` (drop `OWNER`/`MEMBER`/`COLLABORATOR`). - **Comment / label / close**: `gh pr comment`, `gh pr edit --add-label`/`--remove-label`, `gh pr close`. -GitHub shares one number space across issues and PRs, so a bare `#42` may be either — resolve with `gh pr view 42` and fall back to `gh issue view 42`. +GitHub shares one number space across issues and PRs, so a bare `#42` may be either: resolve with `gh pr view 42` and fall back to `gh issue view 42`. ## When a skill says "publish to the issue tracker" @@ -39,7 +39,7 @@ Used by `/wayfinder`. The **map** is a single issue with **child** issues as tic - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`. - **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. -- **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos///issues//dependencies/blocked_by -F issue_id=`, where `` is the blocker's numeric **database id** (`gh api repos///issues/ --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every blocker is closed. +- **Blocking**: GitHub's **native issue dependencies**, the canonical, UI-visible representation. Add an edge with `gh api --method POST repos///issues//dependencies/blocked_by -F issue_id=`, where `` is the blocker's numeric **database id** (`gh api repos///issues/ --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only, the live gate). Where dependencies aren't available, fall back to a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every blocker is closed. - **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins. -- **Claim**: `gh issue edit --add-assignee @me` — the session's first write. +- **Claim**: `gh issue edit --add-assignee @me`, the session's first write. - **Resolve**: `gh issue comment --body ""`, then `gh issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md b/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md index 8a54714..114790a 100644 --- a/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +++ b/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md @@ -1,6 +1,6 @@ # Issue tracker: GitLab -Issues and PRDs for this repo live as GitLab issues. Use the [`glab`](https://gitlab.com/gitlab-org/cli) CLI for all operations. +Issues and specs for this repo live as GitLab issues. Use the [`glab`](https://gitlab.com/gitlab-org/cli) CLI for all operations. ## Conventions @@ -10,9 +10,9 @@ Issues and PRDs for this repo live as GitLab issues. Use the [`glab`](https://gi - **Comment on an issue**: `glab issue note --message "..."`. GitLab calls comments "notes". - **Apply / remove labels**: `glab issue update --label "..."` / `--unlabel "..."`. Multiple labels can be comma-separated or by repeating the flag. - **Close**: `glab issue close `. `glab issue close` does not accept a closing comment, so post the explanation first with `glab issue note --message "..."`, then close. -- **Merge requests**: GitLab calls PRs "merge requests". Use `glab mr create`, `glab mr view`, `glab mr note`, etc. — the same shape as `gh pr ...` with `mr` in place of `pr` and `note`/`--message` in place of `comment`/`--body`. +- **Merge requests**: GitLab calls PRs "merge requests". Use `glab mr create`, `glab mr view`, `glab mr note`, etc., the same shape as `gh pr ...` with `mr` in place of `pr` and `note`/`--message` in place of `comment`/`--body`. -Infer the repo from `git remote -v` — `glab` does this automatically when run inside a clone. +Infer the repo from `git remote -v`; `glab` does this automatically when run inside a clone. ## Merge requests as a triage surface @@ -40,7 +40,7 @@ Used by `/wayfinder`. The **map** is a single issue with **child** issues as tic - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `glab issue create --label wayfinder:map`. (On GitLab tiers with native epics, an epic may hold the map instead; a labelled issue works everywhere.) - **Child ticket**: an issue carrying `Part of #` at the top of its description and labels `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. -- **Blocking**: GitLab's **native blocking link** — the canonical, UI-visible representation. Add it with the `/blocked_by #` quick action, posted as a note (`glab issue note --message "/blocked_by #"`). Native blocking links are a Premium/Ultimate feature; on the free tier (or where unavailable) fall back to a `Blocked by: #, #` line at the top of the description. A ticket is unblocked when every blocker is closed. -- **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker — a native `blocked_by` link to an open issue (`glab api projects/:id/issues/:iid/links`), or an open issue in the `Blocked by` line — or an assignee; first in map order wins. -- **Claim**: `glab issue update --assignee @me` — the session's first write. +- **Blocking**: GitLab's **native blocking link**, the canonical, UI-visible representation. Add it with the `/blocked_by #` quick action, posted as a note (`glab issue note --message "/blocked_by #"`). Native blocking links are a Premium/Ultimate feature; on the free tier (or where unavailable) fall back to a `Blocked by: #, #` line at the top of the description. A ticket is unblocked when every blocker is closed. +- **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker: a native `blocked_by` link to an open issue (`glab api projects/:id/issues/:iid/links`), an open issue in the `Blocked by` line, or an assignee; first in map order wins. +- **Claim**: `glab issue update --assignee @me`, the session's first write. - **Resolve**: `glab issue note --message ""`, then `glab issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/skills/setup-matt-pocock-skills/issue-tracker-local.md b/skills/setup-matt-pocock-skills/issue-tracker-local.md index 6b124b3..b57c38e 100644 --- a/skills/setup-matt-pocock-skills/issue-tracker-local.md +++ b/skills/setup-matt-pocock-skills/issue-tracker-local.md @@ -1,12 +1,12 @@ # Issue tracker: Local Markdown -Issues and specs (you may know a spec as a PRD) for this repo live as markdown files in `.scratch/`. +Issues and specs for this repo live as Markdown files in `.scratch/`. ## Conventions - One feature per directory: `.scratch//` - The spec is `.scratch//spec.md` -- Implementation issues are one file per ticket at `.scratch//issues/-.md`, numbered from `01` — never a single combined tickets file +- Implementation issues are one file per ticket at `.scratch//issues/-.md`, numbered from `01`, never a single combined tickets file - Triage state is recorded as a `Status:` line near the top of each issue file (see `triage-labels.md` for the role strings) - Comments and conversation history append to the bottom of the file under a `## Comments` heading @@ -22,7 +22,7 @@ Read the file at the referenced path. The user will normally pass the path or th Used by `/wayfinder`. The **map** is a file with one **child** file per ticket. -- **Map**: `.scratch//map.md` — the Notes / Decisions-so-far / Fog body. +- **Map**: `.scratch//map.md` (the Notes / Decisions-so-far / Fog body). - **Child ticket**: `.scratch//issues/NN-.md`, numbered from `01`, with the question in the body. A `Type:` line records the ticket type (`research`/`prototype`/`grilling`/`task`); a `Status:` line records `claimed`/`resolved`. - **Blocking**: a `Blocked by: NN, NN` line near the top. A ticket is unblocked when every file it lists is `resolved`. - **Frontier**: scan `.scratch//issues/` for files that are open, unblocked, and unclaimed; first by number wins. diff --git a/skills/tdd/SKILL.md b/skills/tdd/SKILL.md index 7940999..6ad9703 100644 --- a/skills/tdd/SKILL.md +++ b/skills/tdd/SKILL.md @@ -1,111 +1,42 @@ --- name: tdd -description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development. +description: "Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions red-green-refactor, or wants integration tests." --- # Test-Driven Development -## Philosophy +_Source: [mattpocock/skills](https://github.com/mattpocock/skills), synced from `main` at `885e2ca4`; adapted for Bram's autonomous maintainer loop._ -**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. +TDD is the red -> green loop. This skill is the reference that makes that loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, and the rules of the loop. Every section applies on every cycle. Consult them before and during the loop, not after. -**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure. +When exploring the codebase, read `CONTEXT.md` if it exists so test names and interface vocabulary match the project's domain language, and respect ADRs in the area you're touching. -**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior. +## What a good test is -See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines. - -## Anti-Pattern: Horizontal Slices - -**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code." - -This produces **crap tests**: - -- Tests written in bulk test _imagined_ behavior, not _actual_ behavior -- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior -- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine -- You outrun your headlights, committing to test structure before understanding the implementation - -**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it. - -``` -WRONG (horizontal): - RED: test1, test2, test3, test4, test5 - GREEN: impl1, impl2, impl3, impl4, impl5 - -RIGHT (vertical): - RED→GREEN: test1→impl1 - RED→GREEN: test2→impl2 - RED→GREEN: test3→impl3 - ... -``` - -## Workflow - -### 1. Planning - -When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching. +Tests verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. A good test reads like a specification. "User can checkout with valid cart" says exactly what capability exists, and it survives refactors because it doesn't care about internal structure. -Before writing any code: - -- [ ] Confirm with user what interface changes are needed -- [ ] Confirm with user which behaviors to test (prioritize) -- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation) -- [ ] Design interfaces for [testability](interface-design.md) -- [ ] List the behaviors to test (not implementation steps) -- [ ] Get user approval on the plan - -Loop mode: if `bram-maintainer-loop-v2` classified the item as `Autonomous` and implementation permission exists, treat that as approval for one tracer-bullet cycle. Ask Bram only for product/API/security decisions, test scope changes, or missing live-proof access. - -Ask: "What should the public interface look like? Which behaviors are most important to test?" - -**You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case. - -### 2. Tracer Bullet - -Write ONE test that confirms ONE thing about the system: - -``` -RED: Write test for first behavior → test fails -GREEN: Write minimal code to pass → test passes -``` - -This is your tracer bullet - proves the path works end-to-end. - -### 3. Incremental Loop +See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines. -For each remaining behavior: +## Seams: where tests go -``` -RED: Write next test → fails -GREEN: Minimal code to pass → passes -``` +A **seam** is the public boundary you test at: the interface where you observe behavior without reaching inside. Tests live at seams, never against internals. -Rules: +**Test only at pre-agreed seams.** Before writing any test, write down the seams under test and confirm them with the user. No test is written at an unconfirmed seam. You can't test everything, so agreeing the seams up front is how testing effort lands on the critical paths and complex logic instead of every edge case. -- One test at a time -- Only enough code to pass current test -- Don't anticipate future tests -- Keep tests focused on observable behavior +Ask: "What's the public interface, and which seams should we test?" -### 4. Refactor +When the shape of that interface is itself in question, call the Skill tool with "codebase-design" for the vocabulary. It is the shared source of the module, interface, depth, seam, adapter, leverage, and locality terms. Consult it as a reference, not a session to run. -After all tests pass, look for [refactor candidates](refactoring.md): +In `bram-maintainer-loop-v2`, an item classified as autonomous with implementation authority already has approval for its agreed tracer-bullet seam. Ask Bram only when test scope, a product or API contract, security, or live-proof access still needs a decision. -- [ ] Extract duplication -- [ ] Deepen modules (move complexity behind simple interfaces) -- [ ] Apply SOLID principles where natural -- [ ] Consider what new code reveals about existing code -- [ ] Run tests after each refactor step +## Anti-patterns -**Never refactor while RED.** Get to GREEN first. +- **Implementation-coupled**: mocks internal collaborators, tests private methods, or verifies through a side channel such as querying the database instead of using the interface. The tell is a test that breaks after a refactor even though behavior did not change. +- **Tautological**: the assertion recomputes the expected value the same way the code does, so it passes by construction and cannot disagree with the implementation. Expected values must come from an independent source of truth such as a known-good literal, worked example, or specification. +- **Horizontal slicing**: writing all tests first, then all implementation. Bulk tests verify imagined behavior and commit to test structure before the implementation teaches you what matters. Work in vertical slices instead: one test -> one implementation -> repeat. Each test is a tracer bullet that responds to what the last cycle taught you. -## Checklist Per Cycle +## Rules of the loop -``` -[ ] Test describes behavior, not implementation -[ ] Test uses public interface only -[ ] Test would survive internal refactor -[ ] Code is minimal for this test -[ ] No speculative features added -``` +- **Red before green.** Write the failing test first, then only enough code to pass it. Don't anticipate future tests or add speculative features. +- **One slice at a time.** One seam, one test, one minimal implementation per cycle. +- **Refactoring is not part of the loop.** It belongs to the review stage, not the red -> green implementation cycle. Never refactor while red. diff --git a/skills/tdd/agents/openai.yaml b/skills/tdd/agents/openai.yaml new file mode 100644 index 0000000..651b838 --- /dev/null +++ b/skills/tdd/agents/openai.yaml @@ -0,0 +1,3 @@ +interface: + display_name: "TDD" + short_description: "Test-driven red-green-refactor" diff --git a/skills/tdd/deep-modules.md b/skills/tdd/deep-modules.md deleted file mode 100644 index 0d9720c..0000000 --- a/skills/tdd/deep-modules.md +++ /dev/null @@ -1,33 +0,0 @@ -# Deep Modules - -From "A Philosophy of Software Design": - -**Deep module** = small interface + lots of implementation - -``` -┌─────────────────────┐ -│ Small Interface │ ← Few methods, simple params -├─────────────────────┤ -│ │ -│ │ -│ Deep Implementation│ ← Complex logic hidden -│ │ -│ │ -└─────────────────────┘ -``` - -**Shallow module** = large interface + little implementation (avoid) - -``` -┌─────────────────────────────────┐ -│ Large Interface │ ← Many methods, complex params -├─────────────────────────────────┤ -│ Thin Implementation │ ← Just passes through -└─────────────────────────────────┘ -``` - -When designing interfaces, ask: - -- Can I reduce the number of methods? -- Can I simplify the parameters? -- Can I hide more complexity inside? diff --git a/skills/tdd/interface-design.md b/skills/tdd/interface-design.md deleted file mode 100644 index a0a20ca..0000000 --- a/skills/tdd/interface-design.md +++ /dev/null @@ -1,31 +0,0 @@ -# Interface Design for Testability - -Good interfaces make testing natural: - -1. **Accept dependencies, don't create them** - - ```typescript - // Testable - function processOrder(order, paymentGateway) {} - - // Hard to test - function processOrder(order) { - const gateway = new StripeGateway(); - } - ``` - -2. **Return results, don't produce side effects** - - ```typescript - // Testable - function calculateDiscount(cart): Discount {} - - // Hard to test - function applyDiscount(cart): void { - cart.total -= discount; - } - ``` - -3. **Small surface area** - - Fewer methods = fewer tests needed - - Fewer params = simpler test setup diff --git a/skills/tdd/refactoring.md b/skills/tdd/refactoring.md deleted file mode 100644 index 8a44439..0000000 --- a/skills/tdd/refactoring.md +++ /dev/null @@ -1,10 +0,0 @@ -# Refactor Candidates - -After TDD cycle, look for: - -- **Duplication** → Extract function/class -- **Long methods** → Break into private helpers (keep tests on public interface) -- **Shallow modules** → Combine or deepen -- **Feature envy** → Move logic to where data lives -- **Primitive obsession** → Introduce value objects -- **Existing code** the new code reveals as problematic diff --git a/skills/tdd/tests.md b/skills/tdd/tests.md index ff22f80..7ab8647 100644 --- a/skills/tdd/tests.md +++ b/skills/tdd/tests.md @@ -59,3 +59,19 @@ test("createUser makes user retrievable", async () => { expect(retrieved.name).toBe("Alice"); }); ``` + +**Tautological tests**: Expected value restates the implementation, so the test passes by construction. + +```typescript +// BAD: Expected value is recomputed the way the code computes it +test("calculateTotal sums line items", () => { + const items = [{ price: 10 }, { price: 5 }]; + const expected = items.reduce((sum, i) => sum + i.price, 0); + expect(calculateTotal(items)).toBe(expected); +}); + +// GOOD: Expected value is an independent, known literal +test("calculateTotal sums line items", () => { + expect(calculateTotal([{ price: 10 }, { price: 5 }])).toBe(15); +}); +``` diff --git a/skills/to-issues/SKILL.md b/skills/to-issues/SKILL.md deleted file mode 100644 index 542e5dd..0000000 --- a/skills/to-issues/SKILL.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -name: to-issues -description: Break a plan, spec, or PRD into independently-grabbable issues on the project issue tracker using tracer-bullet vertical slices. Use when user wants to convert a plan into issues, create implementation tickets, or break down work into issues. ---- - -# To Issues - -Break a plan into independently-grabbable issues using vertical slices (tracer bullets). - -If tracker labels are unknown, inspect repo labels with `gh label list` or ask Bram only when publishing requires a decision. - -## Process - -### 1. Gather context - -Work from whatever is already in the conversation context. If the user passes an issue reference (issue number, URL, or path) as an argument, fetch it from the issue tracker and read its full body and comments. - -### 2. Explore the codebase (optional) - -If you have not already explored the codebase, do so to understand the current state of the code. Issue titles and descriptions should use the project's domain glossary vocabulary, and respect ADRs in the area you're touching. - -### 3. Draft vertical slices - -Break the plan into **tracer bullet** issues. Each issue is a thin vertical slice that cuts through ALL integration layers end-to-end, NOT a horizontal slice of one layer. - -Slices may be 'HITL' or 'AFK'. HITL slices require human interaction, such as an architectural decision or a design review. AFK slices can be implemented and merged without human interaction. Prefer AFK over HITL where possible. - -Loop mode: in `bram-maintainer-loop-v2`, draft the slices and AFK/HITL labels as the decision boundary. Publish issues only when issue creation is authorized. - - -- Each slice delivers a narrow but COMPLETE path through every layer (schema, API, UI, tests) -- A completed slice is demoable or verifiable on its own -- Prefer many thin slices over few thick ones - - -### 3b. Require real proof when reality is the product - -If the slice changes behavior that only matters against a real dependency, the issue must require an automatic real proof gate. Fake/default tests are still required for machinery, but they are not enough to close or merge real behavior. - -Examples of real dependencies: live hosts, browsers, devices, external CLIs, OAuth-backed services, payment providers, review systems, deployment targets, hardware, licensed desktop apps, or consuming repos. - - -- Acceptance criteria must name the real proof command, workflow, smoke, or CI job. -- The real proof must be automatic once configured; no manual Bram step may be required during merge. -- A skipped, missing, or fake-only real proof fails the issue. -- Mark the slice HITL unless the required live credentials/host/config already exist in automation and the agent can verify them without asking. -- If real proof is impossible, split first: one HITL slice to create the automated proof gate, then AFK implementation slices blocked by it. -- If the product promise changes because real proof shows a feature is unsupported, include docs/ADR/PRD cleanup in the same vertical slice. - - -### 4. Quiz the user - -Present the proposed breakdown as a numbered list. For each slice, show: - -- **Title**: short descriptive name -- **Type**: HITL / AFK -- **Blocked by**: which other slices (if any) must complete first -- **User stories covered**: which user stories this addresses (if the source material has them) -- **Real proof**: automatic live gate required, or "not needed" with a reason - -Ask the user: - -- Does the granularity feel right? (too coarse / too fine) -- Are the dependency relationships correct? -- Should any slices be merged or split further? -- Are the correct slices marked as HITL and AFK? -- Does every real-product slice have a non-skippable automatic proof gate? - -Iterate until the user approves the breakdown. - -### 5. Publish the issues to the issue tracker - -For each approved slice, publish a new issue to the issue tracker. Use the issue body template below. These issues are considered ready for AFK agents, so publish them with the correct triage label unless instructed otherwise. - -Publish issues in dependency order (blockers first) so you can reference real issue identifiers in the "Blocked by" field. - - -## Parent - -A reference to the parent issue on the issue tracker (if the source was an existing issue, otherwise omit this section). - -## What to build - -A concise description of this vertical slice. Describe the end-to-end behavior, not layer-by-layer implementation. - -Avoid specific file paths or code snippets — they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it here and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits. - -## Acceptance criteria - -- [ ] Criterion 1 -- [ ] Criterion 2 -- [ ] Criterion 3 - -## Required proof - -- Fake/local gate: exact command(s) that must pass. -- Real gate: exact automatic live command, workflow, smoke, or CI job that must pass; or "Not required" with the reason. -- Merge rule: if a required real gate is skipped, missing, or replaced by fake-only proof, this issue is not complete. - -## Blocked by - -- A reference to the blocking ticket (if any) - -Or "None - can start immediately" if no blockers. - - - -Do NOT close or modify any parent issue. diff --git a/skills/to-tickets/SKILL.md b/skills/to-tickets/SKILL.md index 5271c71..0a5335d 100644 --- a/skills/to-tickets/SKILL.md +++ b/skills/to-tickets/SKILL.md @@ -1,83 +1,120 @@ --- name: to-tickets -description: "Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker — edges as text in one file per ticket locally, or native blocking links on a real tracker." +description: "Break a plan, spec, or conversation into tracer-bullet tickets with blocking edges and required proof, then publish them to the configured issue tracker." disable-model-invocation: true --- # To Tickets -Break a plan, spec, or conversation into a set of **tickets** — tracer-bullet vertical slices, each declaring the tickets that **block** it. +_Source: [mattpocock/skills](https://github.com/mattpocock/skills), synced from `main` at `885e2ca4`; extended with Bram's AFK/HITL and automatic live-proof rules._ -The issue tracker and triage label vocabulary should have been provided to you — run `/setup-matt-pocock-skills` if not. +Break a plan, spec, or conversation into **tickets**: tracer-bullet vertical slices, each declaring the tickets that block it. + +The issue tracker and triage label vocabulary should have been configured. If not, tell the user to run `/setup-matt-pocock-skills`. ## Process ### 1. Gather context -Work from whatever is already in the conversation context. If the user passes a reference (a spec path, an issue number or URL) as an argument, fetch it and read its full body and comments. +Work from the conversation context. If the user passes a spec path, issue number, URL, or other reference, fetch it and read its full body and comments. -### 2. Explore the codebase (optional) +### 2. Explore the codebase when needed -If you have not already explored the codebase, do so to understand the current state of the code. Ticket titles and descriptions should use the project's domain glossary vocabulary, and respect ADRs in the area you're touching. +Explore enough code to understand the current state. Ticket titles and descriptions should use the project's domain glossary vocabulary and respect relevant ADRs. -Look for opportunities to prefactor the code to make the implementation easier. "Make the change easy, then make the easy change." +Look for prefactoring that would make implementation easier. Make the change easy, then make the easy change. ### 3. Draft vertical slices -Break the work into **tracer bullet** tickets. +Break the work into tracer-bullet tickets. -- Each slice cuts a narrow but COMPLETE path through every layer (schema, API, UI, tests) — vertical, NOT a horizontal slice of one layer -- A completed slice is demoable or verifiable on its own -- Each slice is sized to fit in a single fresh context window -- Any prefactoring should be done first +- Each slice cuts a narrow but complete path through every relevant layer, such as schema, API, UI, and tests. Do not create horizontal layer tickets. +- A completed slice is demoable or verifiable on its own. +- Each slice fits in one fresh context window. +- Put required prefactoring first. -Give each ticket its **blocking edges** — the other tickets that must complete before it can start. A ticket with no blockers can start immediately. +Give each ticket its **blocking edges**, meaning the tickets that must complete before it can start. A ticket with no blockers can start immediately. + +Classify each ticket: + +- **AFK** when an agent can implement, prove, review, and land it without user interaction. +- **HITL** when it needs a user decision, manual approval, unavailable credential, live environment setup, or another non-automatable action. + +Prefer AFK. Do not label a ticket AFK when its proof still requires Bram. + +**Wide refactors are the exception to vertical slicing.** A wide refactor is one mechanical change, such as renaming a column or retyping a shared symbol, whose blast radius prevents one vertical slice from landing green. Sequence it as expand-contract: + +1. Expand by adding the new form beside the old. +2. Migrate callers in batches sized by blast radius, each blocked by the expansion. +3. Contract by deleting the old form after every migration batch. + +If individual migration batches cannot stay green, use an integration branch and make them block one final integrate-and-verify ticket. + +### 3b. Require real proof when reality is the product + +If behavior matters only against a real dependency, require an automatic real proof gate. Fake or local tests still prove the machinery, but they do not close the ticket. + +Real dependencies include live hosts, browsers, devices, external CLIs, OAuth-backed services, payment providers, review systems, deployment targets, hardware, licensed desktop apps, and consuming repositories. + + + +- Acceptance criteria name the exact real proof command, workflow, smoke test, or CI job. +- The real proof runs automatically once configured. No manual Bram step may remain in an AFK ticket. +- A skipped, missing, or fake-only real proof fails the ticket. +- Mark the ticket HITL unless the required credentials, host, and configuration already exist in automation. +- If automatic real proof does not exist, create one HITL ticket to establish the proof gate. Block AFK implementation tickets on it. +- If live proof changes the supported product promise, include the related docs, ADR, or spec cleanup in the same slice. -**Wide refactors are the exception to vertical slicing.** A **wide refactor** is one mechanical change — rename a column, retype a shared symbol — whose **blast radius** fans across the whole codebase, so a single edit breaks thousands of call sites at once and no vertical slice can land green. Don't force it into a tracer bullet; sequence it as **expand–contract**. First expand: add the new form beside the old so nothing breaks. Then migrate the call sites over in batches sized by blast radius (per package, per directory), each batch its own ticket blocked by the expand, keeping CI green batch to batch because the old form still exists. Finally contract: delete the old form once no caller remains, in a ticket blocked by every migrate batch. When even the batches can't stay green alone, keep the sequence but let them share an integration branch that all block a final integrate-and-verify ticket — green is promised only there. + ### 4. Quiz the user Present the proposed breakdown as a numbered list. For each ticket, show: -- **Title**: short descriptive name -- **Blocked by**: which other tickets (if any) must complete first -- **What it delivers**: the end-to-end behaviour this ticket makes work +- **Title**: short descriptive name. +- **Type**: AFK or HITL. +- **Blocked by**: tickets that genuinely gate it. +- **What it delivers**: end-to-end behavior that becomes usable. +- **User stories**: covered stories when the source includes them. +- **Real proof**: the automatic live gate, or "not needed" with a reason. -Ask the user: +Ask whether the granularity, blocking edges, AFK or HITL labels, and real proof gates are correct. Iterate until the user approves the breakdown. -- Does the granularity feel right? (too coarse / too fine) -- Are the blocking edges correct — does each ticket only depend on tickets that genuinely gate it? -- Should any tickets be merged or split further? +### 5. Publish to the configured tracker -Iterate until the user approves the breakdown. +Publish approved tickets in dependency order so blockers get identifiers first. -### 5. Publish the tickets to the configured tracker +- **Local files**: write one file per ticket under `.scratch//issues/-.md`, numbered from `01`. Never combine tickets into one file. +- **A real tracker**: publish one issue per ticket. Use native blocking or sub-issue relationships where available, otherwise write the blocking references in the body. Apply the `ready-for-agent` label to AFK tickets unless instructed otherwise. -Publish the approved tickets. **How** depends on the tracker `/setup-matt-pocock-skills` configured — the tickets are the same either way, only the shape of the blocking edges changes: +Do not close or modify a parent issue. -- **Local files** → write one file per ticket under `.scratch//issues/-.md`, numbered from `01` in dependency order (blockers first). Each file's "Blocked by" lists the numbers/titles it depends on. Use the per-ticket file template below — one ticket per file, never a single combined file. -- **A real issue tracker (GitHub, Linear, …)** → publish one issue per ticket in dependency order (blockers first) so each ticket's blocking edges can reference real identifiers. Use the platform's native blocking / sub-issue relationship where it has one; otherwise set each ticket's "Blocked by" to the blocking issues. Apply the `ready-for-agent` triage label unless instructed otherwise — the tickets are agent-grabbable by construction. + -Work the **frontier**: any ticket whose blockers are all done. For a purely linear chain that means top to bottom. +# : -Do NOT close or modify any parent issue. +**Type:** AFK or HITL - +**What to build:** the end-to-end behavior this ticket makes work from the user's perspective. + +**Blocked by:** ticket numbers and titles, or "None (can start immediately)". -# +**Status:** ready-for-agent or ready-for-human -**What to build:** the end-to-end behaviour this ticket makes work, from the user's perspective — not a layer-by-layer implementation list. +## Acceptance criteria -**Blocked by:** the numbers/titles of the tickets that gate this one, or "None — can start immediately". +- [ ] Criterion 1 +- [ ] Criterion 2 -**Status:** ready-for-agent +## Required proof -- [ ] Acceptance criterion 1 -- [ ] Acceptance criterion 2 +- Fake or local gate: exact command. +- Real gate: exact automatic live command, workflow, smoke test, or CI job, or "Not required" with the reason. +- Merge rule: a skipped or fake-only required real gate means the ticket is incomplete. @@ -85,23 +122,31 @@ Do NOT close or modify any parent issue. ## Parent -A reference to the parent issue on the tracker (if the source was an existing issue, otherwise omit this section). +Reference the parent issue when the source was an existing issue. Otherwise omit this section. + +## Type + +AFK or HITL. ## What to build -The end-to-end behaviour this ticket makes work, from the user's perspective — not layer-by-layer implementation. +Describe the end-to-end behavior, not a layer-by-layer implementation list. ## Acceptance criteria - [ ] Criterion 1 - [ ] Criterion 2 +## Required proof + +- Fake or local gate: exact command. +- Real gate: exact automatic live command, workflow, smoke test, or CI job, or "Not required" with the reason. +- Merge rule: a skipped or fake-only required real gate means the ticket is incomplete. + ## Blocked by -- A reference to each blocking ticket, or "None — can start immediately". +Reference every blocking ticket, or write "None (can start immediately)". -In either form, avoid specific file paths or code snippets — they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits. - -Work the frontier one ticket at a time with `/implement`, clearing context between tickets. +Avoid specific file paths or code snippets because they go stale. If a prototype produced a decision-rich state machine, reducer, schema, or type shape, include only the part that records the decision and note that it came from the prototype.