@muggleai/works 5.8.0 → 5.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,129 +1,130 @@
1
- ---
2
- name: muggle-test-prepare
3
- model: opus
4
- description: "Get a user's local environment ready before running E2E acceptance tests — verify the dev servers, APIs, and sibling services they need are up and responding, and offer to start whatever is missing (with approval per step). Trigger when the user wants to confirm specific ports or localhost URLs are listening before testing (check if localhost:3000 and the api on 8080 are up, are my services running), spin up their local dev stack, or verify their setup — and whenever another muggle skill (muggle-test, muggle-do, muggle-test-feature-local) needs services running but they're not. This is environment readiness and service startup, not running the tests."
5
- ---
6
-
7
- # Muggle Test Prepare
8
-
9
- > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-test-prepare"`.
10
-
11
- Make sure the local services a user needs for E2E acceptance testing are up and ready. Check what's already running, discover sibling service directories by folder name, and offer to start anything that's missing — always with the user in control.
12
-
13
- Some users start their own services (tmux scripts, docker-compose, a terminal per service). Others want help launching them. This skill handles both: it verifies readiness first, and only offers to start things when something is missing.
14
-
15
- ## Privacy Boundary
16
-
17
- This skill touches the user's local machine — processes, ports, directories outside the current repo. Every action is explicit and confirmed.
18
-
19
- - **Folder names are public.** You may list directory names in a parent folder to discover sibling services.
20
- - **File contents are private until confirmed.** Never read files inside a directory the user hasn't explicitly identified as a service to start. Once confirmed, you may inspect only top-level project indicator files (`package.json`, `Makefile`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `docker-compose.yml`) to determine the start command.
21
- - **Never traverse upward more than one level** from the current working directory to list folders.
22
-
23
- ## PID Tracking
24
-
25
- All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
26
-
27
- ```json
28
- {
29
- "session_started": "2025-01-15T10:30:00Z",
30
- "testing_scope": "frontend",
31
- "excluded_services": [
32
- {"name": "payment-gateway", "reason": "Needs production certificates"}
33
- ],
34
- "services": [
35
- {
36
- "name": "backend-api",
37
- "dir": "/Users/user/Github/backend-api",
38
- "command": "npm run dev",
39
- "pid": 12345,
40
- "port": 3001,
41
- "log": "/tmp/muggle-prepare-backend-api.log"
42
- }
43
- ]
44
- }
45
- ```
46
-
47
- `testing_scope` records what the user is testing (from [scope](./steps/scope.md)). `excluded_services` records services the user said can't run locally (from [viability-check](./steps/viability-check.md)).
48
-
49
- This file is **ephemeral runtime state**, not the saved recipe. The durable plan lives at `<repo>/.muggle-ai/prepare-plan.json` (or the parent-dir-keyed entry in `~/.muggle-ai/prepare-plans.json`) and is consulted in [reuse-plan](./steps/reuse-plan.md) before any other stage. The two files never merge.
50
-
51
- **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
52
- - Option 1: "Keep them running — skip to testing"
53
- - Option 2: "Tear down and start fresh"
54
- - Option 3: "Add more services to the running set"
55
-
56
- Prune dead PIDs silently.
57
-
58
- ## Preferences
59
-
60
- Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-gates/README.md).
61
-
62
- | Preference | Gates |
63
- |------------|-------|
64
- | `autoRebase` | [rebase-check](./steps/rebase-check.md) — rebase onto `origin/<default>` before starting dev servers |
65
- | `reusePreparePlan` | [reuse-plan](./steps/reuse-plan.md) — reuse the saved prepare plan for this stack, or rediscover |
66
- | `autoSelectLocalHost` | [check-running](./steps/check-running.md) — reuse the recorded dev-server URL silently, or confirm it each run |
67
-
68
- ## Workflow
69
-
70
- Run the stages in this order. The sequence number is display-only — it lives only in this table for at-a-glance ordering; detail files and cross-references use slugs. Each row links to its detail file; read the file when you reach the stage.
71
-
72
- | # | Stage | Summary |
73
- |:--|:------|:--------|
74
- | 0 | [reuse-plan](./steps/reuse-plan.md) | Reuse saved prepare plan (gated); short-circuits to check-running on reuse |
75
- | 1 | [rebase-check](./steps/rebase-check.md) | Rebase onto default branch (gated) |
76
- | 2 | [scope](./steps/scope.md) | Frontend / backend / full stack |
77
- | 3 | [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
78
- | 4 | [identify-services](./steps/identify-services.md) | Pick required services + startup mode |
79
- | 5 | [check-running](./steps/check-running.md) | Detect what's already listening |
80
- | 6 | [env-file](./steps/env-file.md) | Env file present + correct |
81
- | 7 | [start-commands](./steps/start-commands.md) | Determine per-service start command |
82
- | 8 | [fresh-install](./steps/fresh-install.md) | Auto-install deps if missing/stale |
83
- | 9 | [start-services](./steps/start-services.md) | Launch + two-stage readiness |
84
- | 10 | [smoke-test](./steps/smoke-test.md) | HTTP + body sniff + log tail; clean-restart on fail |
85
- | 11 | [readiness-report](./steps/readiness-report.md) | Final ready table |
86
-
87
- ## Cleanup
88
-
89
- Triggered when the user says "stop services", "tear down", "clean up", "I'm done testing", another skill signals run complete, or this skill is re-invoked with "tear down and start fresh".
90
-
91
- 1. Read `/tmp/muggle-test-prepare.json`
92
- 2. Skip services marked `external: true`
93
- 3. For each managed service: `kill <pid>` (SIGTERM)
94
- 4. Wait ~2 s, verify with `kill -0`
95
- 5. If still alive: `kill -9 <pid>`
96
- 6. `rm -f /tmp/muggle-prepare-*.log`
97
- 7. `rm -f /tmp/muggle-test-prepare.json`
98
-
99
- Report:
100
-
101
- ```
102
- Stopped 3 services:
103
- backend-api (PID 12345)
104
- auth-service (PID 12346)
105
- frontend (PID 12347)
106
- ```
107
-
108
- ## Integration Contract (for other skills)
109
-
110
- `muggle-test-feature-local`, `muggle-do`, and local-mode `muggle-test` MUST invoke this skill before any workflow step. Idempotent — fast exit when healthy. Treat success as short-lived; re-invoke if more than a few minutes pass before testing. Never bypass on "the user knows their stack is up" — that assumption is why this skill exists.
111
-
112
- After a test run, the caller can re-invoke for cleanup or leave services running for the next run.
113
-
114
- ## Guardrails
115
-
116
- - **Never invent or default a host/port** — the dev-server URL is a recorded value, not a guess. Resolve it from `<repo>/.muggle-ai/last-host.json` (the [`autoSelectLocalHost`](../muggle-preferences/preference-gates/autoSelectLocalHost.md) cache) before probing ports; a framework default like `:3000` is never a fallback. See [check-running](./steps/check-running.md).
117
- - **No silent auto-selection without a gate** — when no preference authorizes a silent choice (host, restart, kill), confirm with the user. A gate set to `always` is the only license to skip the question; absent that, ask.
118
- - **Verify first, offer to start second** — check what's already running before proposing to start anything.
119
- - **The user may prefer to start services themselves** — always offer that option.
120
- - **Never start a process the user didn't approve.**
121
- - **Never read file contents outside confirmed directories** — folder names are discoverable; file contents require explicit user selection.
122
- - **Never leave orphan processes untracked** — every background PID goes into the tracking file.
123
- - **Never kill a process the user started independently** — `external: true` survives cleanup.
124
- - **Never assume start commands** — verify via indicator file; confirm with user.
125
- - **Bail early on non-viable services** — don't start what can't run locally.
126
- - **Idempotent** — already-tracked alive services are kept; [smoke-test](./steps/smoke-test.md) still runs against them.
127
- - **Port-listening is never enough** — smoke-test (HTTP + body sniff + log tail) is mandatory before the final report.
128
- - **Clean Restart is the recommended fix** — first option in the smoke-test diagnose-and-fix loop; lint/build/missing-deps issues need nuke-and-reinstall.
129
- - **Fresh install is automatic** — [fresh-install](./steps/fresh-install.md) notifies, doesn't ask.
1
+ ---
2
+ name: muggle-test-prepare
3
+ model: opus
4
+ description: "Get a user's local environment ready before running E2E acceptance tests — verify the dev servers, APIs, and sibling services they need are up and responding, and offer to start whatever is missing (with approval per step). Trigger when the user wants to confirm specific ports or localhost URLs are listening before testing (check if localhost:3000 and the api on 8080 are up, are my services running), spin up their local dev stack, or verify their setup — and whenever another muggle skill (muggle-test, muggle-do, muggle-test-feature-local) needs services running but they're not. This is environment readiness and service startup, not running the tests."
5
+ ---
6
+
7
+ # Muggle Test Prepare
8
+
9
+ > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-test-prepare"`.
10
+
11
+ Make sure the local services a user needs for E2E acceptance testing are up and ready. Check what's already running, discover sibling service directories by folder name, and offer to start anything that's missing — always with the user in control.
12
+
13
+ Some users start their own services (tmux scripts, docker-compose, a terminal per service). Others want help launching them. This skill handles both: it verifies readiness first, and only offers to start things when something is missing.
14
+
15
+ The skill runs in two phases because a dispatched agent has no channel back to the user. **Decide (in-session):** resolve every choice that needs a human — plan reuse, scope, exclusions, service selection, start approvals. **Execute (agent):** hand the fully-resolved plan to the `test-prepare-runner` agent (`plugin/agents/test-prepare-runner.md`); it runs the mechanical stages headless and returns the readiness verdict, or a `needs-input:` line for any decision the plan left open.
16
+
17
+ ## Privacy Boundary
18
+
19
+ This skill touches the user's local machine — processes, ports, directories outside the current repo. Every action is explicit and confirmed.
20
+
21
+ - **Folder names are public.** You may list directory names in a parent folder to discover sibling services.
22
+ - **File contents are private until confirmed.** Never read files inside a directory the user hasn't explicitly identified as a service to start. Once confirmed, you may inspect only top-level project indicator files (`package.json`, `Makefile`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `docker-compose.yml`) to determine the start command.
23
+ - **Never traverse upward more than one level** from the current working directory to list folders.
24
+
25
+ ## PID Tracking
26
+
27
+ All launched processes are tracked in `/tmp/muggle-test-prepare.json`:
28
+
29
+ ```json
30
+ {
31
+ "session_started": "2025-01-15T10:30:00Z",
32
+ "testing_scope": "frontend",
33
+ "excluded_services": [
34
+ {"name": "payment-gateway", "reason": "Needs production certificates"}
35
+ ],
36
+ "services": [
37
+ {
38
+ "name": "backend-api",
39
+ "dir": "/Users/user/Github/backend-api",
40
+ "command": "npm run dev",
41
+ "pid": 12345,
42
+ "port": 3001,
43
+ "log": "/tmp/muggle-prepare-backend-api.log"
44
+ }
45
+ ]
46
+ }
47
+ ```
48
+
49
+ `testing_scope` records what the user is testing (from [scope](./steps/scope.md)). `excluded_services` records services the user said can't run locally (from [viability-check](./steps/viability-check.md)).
50
+
51
+ This file is **ephemeral runtime state**, not the saved recipe. The durable plan lives at `<repo>/.muggle-ai/prepare-plan.json` (or the parent-dir-keyed entry in `~/.muggle-ai/prepare-plans.json`) and is consulted in [reuse-plan](./steps/reuse-plan.md) before any other stage. The two files never merge. The `test-prepare-runner` agent writes this file during execution; the triage below and Cleanup read it.
52
+
53
+ **On every invocation**, check this file first. If it exists with live PIDs (verify with `kill -0`), `AskUserQuestion`:
54
+ - Option 1: "Keep them running — skip to testing"
55
+ - Option 2: "Tear down and start fresh"
56
+ - Option 3: "Add more services to the running set"
57
+
58
+ Prune dead PIDs silently.
59
+
60
+ ## Preferences
61
+
62
+ Gates run per [`preference-gates/README.md`](../muggle-preferences/preference-gates/README.md). All three resolve in the Decide phase; the agent receives outcomes, never gates.
63
+
64
+ | Preference | Gates |
65
+ |------------|-------|
66
+ | `autoRebase` | [rebase-check](./steps/rebase-check.md) — rebase onto `origin/<default>` before starting dev servers |
67
+ | `reusePreparePlan` | [reuse-plan](./steps/reuse-plan.md) — reuse the saved prepare plan for this stack, or rediscover |
68
+ | `autoSelectLocalHost` | [check-running](./steps/check-running.md) — reuse the recorded dev-server URL silently, or confirm it each run |
69
+
70
+ ## Workflow
71
+
72
+ **Decide (in-session).** Run these stages in order; read each detail file when you reach it:
73
+
74
+ | # | Stage | Summary |
75
+ |:--|:------|:--------|
76
+ | 0 | [reuse-plan](./steps/reuse-plan.md) | Reuse saved prepare plan (gated); on reuse, skip straight to dispatch |
77
+ | 1 | [rebase-check](./steps/rebase-check.md) | Rebase onto default branch (gated) |
78
+ | 2 | [scope](./steps/scope.md) | Frontend / backend / full stack |
79
+ | 3 | [viability-check](./steps/viability-check.md) | Exclude services that can't run locally |
80
+ | 4 | [identify-services](./steps/identify-services.md) | Pick required services + startup mode |
81
+
82
+ The Decide phase's output is the **resolved prepare plan**: `services[]` (name, dir, start command, expected port, `external` flag, approval granted), `testingScope`, `excludedServices[]`, the recorded dev-server URL, and resolved gate outcomes.
83
+
84
+ **Execute (agent).** Dispatch the `test-prepare-runner` agent (subagent type `muggle:test-prepare-runner`; bare `test-prepare-runner` where the plugin namespace is absent), synchronously, passing the resolved plan; it returns `READY` / `DEGRADED` plus the readiness table. The agent's own definition lists its stage files; in a harness with no agent/subagent facility, run the execute-phase stages ([check-running](./steps/check-running.md) through [readiness-report](./steps/readiness-report.md)) inline instead.
85
+
86
+ Relay the readiness table to the user or calling skill verbatim. A `needs-input:` line from the agent names an unresolved decision — resolve it here (asking the user if needed) and re-dispatch; the agent never asks.
87
+
88
+ ## Cleanup
89
+
90
+ Triggered when the user says "stop services", "tear down", "clean up", "I'm done testing", another skill signals run complete, or this skill is re-invoked with "tear down and start fresh". Runs in-session, not in the agent.
91
+
92
+ 1. Read `/tmp/muggle-test-prepare.json`
93
+ 2. Skip services marked `external: true`
94
+ 3. For each managed service: `kill <pid>` (SIGTERM)
95
+ 4. Wait ~2 s, verify with `kill -0`
96
+ 5. If still alive: `kill -9 <pid>`
97
+ 6. `rm -f /tmp/muggle-prepare-*.log`
98
+ 7. `rm -f /tmp/muggle-test-prepare.json`
99
+
100
+ Report:
101
+
102
+ ```
103
+ Stopped 3 services:
104
+ backend-api (PID 12345)
105
+ auth-service (PID 12346)
106
+ frontend (PID 12347)
107
+ ```
108
+
109
+ ## Integration Contract (for other skills)
110
+
111
+ `muggle-test-feature-local`, `muggle-do`, and local-mode `muggle-test` MUST invoke this skill before any workflow step. Idempotent — fast exit when healthy. Treat success as short-lived; re-invoke if more than a few minutes pass before testing. Never bypass on "the user knows their stack is up" — that assumption is why this skill exists.
112
+
113
+ After a test run, the caller can re-invoke for cleanup or leave services running for the next run.
114
+
115
+ ## Guardrails
116
+
117
+ - **Never invent or default a host/port** — the dev-server URL is a recorded value, not a guess. Resolve it from `<repo>/.muggle-ai/last-host.json` (the [`autoSelectLocalHost`](../muggle-preferences/preference-gates/autoSelectLocalHost.md) cache) before probing ports; a framework default like `:3000` is never a fallback. See [check-running](./steps/check-running.md).
118
+ - **No silent auto-selection without a gate** — when no preference authorizes a silent choice (host, restart, kill), confirm with the user. A gate set to `always` is the only license to skip the question; absent that, ask.
119
+ - **Verify first, offer to start second** — check what's already running before proposing to start anything.
120
+ - **The user may prefer to start services themselves** — always offer that option.
121
+ - **Never start a process the user didn't approve** — approvals are granted in Decide and travel in the plan; the agent starts nothing outside it.
122
+ - **Never read file contents outside confirmed directories** — folder names are discoverable; file contents require explicit user selection.
123
+ - **Never leave orphan processes untracked** — every background PID goes into the tracking file.
124
+ - **Never kill a process the user started independently** — `external: true` survives cleanup.
125
+ - **Never assume start commands** — verify via indicator file; confirm with user.
126
+ - **Bail early on non-viable services** — don't start what can't run locally.
127
+ - **Idempotent** — already-tracked alive services are kept; [smoke-test](./steps/smoke-test.md) still runs against them.
128
+ - **Port-listening is never enough** — smoke-test (HTTP + body sniff + log tail) is mandatory before the final report.
129
+ - **Clean Restart is the recommended fix** — first option in the smoke-test diagnose-and-fix loop; lint/build/missing-deps issues need nuke-and-reinstall.
130
+ - **Fresh install is automatic** — [fresh-install](./steps/fresh-install.md) notifies, doesn't ask.
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "5.8.0",
3
- "buildId": "run-67-1",
4
- "commitSha": "f0fbb486a0d7886d880eaec3129bc53964524f01",
5
- "buildTime": "2026-08-01T07:54:45Z",
2
+ "release": "5.8.1",
3
+ "buildId": "run-68-1",
4
+ "commitSha": "5196f24a9e206da839b8605702a0a4f7c7c5e695",
5
+ "buildTime": "2026-08-01T08:31:31Z",
6
6
  "serviceName": "muggle-ai-works-mcp"
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@muggleai/works",
3
3
  "mcpName": "io.github.multiplex-ai/muggle",
4
- "version": "5.8.0",
4
+ "version": "5.8.1",
5
5
  "description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -43,6 +43,7 @@
43
43
  "test": "vitest run",
44
44
  "test:watch": "vitest",
45
45
  "test:gates:behavioral": "tsx internal/skill-gate-eval/src/run.ts",
46
+ "test:agents:behavioral": "tsx internal/agent-gate-eval/src/run.ts",
46
47
  "eval:studio-gen": "tsx internal/studio-gen-eval/src/run.ts"
47
48
  },
48
49
  "muggleConfig": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "muggle",
3
3
  "description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
4
- "version": "5.8.0",
4
+ "version": "5.8.1",
5
5
  "author": {
6
6
  "name": "Muggle AI",
7
7
  "email": "support@muggle-ai.com"
@@ -2,7 +2,7 @@
2
2
  "name": "muggle",
3
3
  "displayName": "Muggle AI",
4
4
  "description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
5
- "version": "5.8.0",
5
+ "version": "5.8.1",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: test-prepare-runner
3
+ description: "Executes a fully-resolved Muggle Test prepare plan — detects what's listening, verifies env files, fresh-installs stale deps, starts approved services, smoke-tests, and returns the readiness table. Dispatched by the muggle-test-prepare skill after all user decisions are resolved; carries the opus pin so execution never runs below its reliability floor on a cheaper session model."
4
+ model: opus
5
+ ---
6
+
7
+ # Test Prepare Runner
8
+
9
+ You bring a local dev stack to verified readiness for E2E testing: detect what's already listening, verify env files, install stale dependencies, start approved services, smoke-test them, and report the readiness table. Every decision — which services, their directories, start commands and approvals, scope, exclusions, the dev-server URL — arrives resolved in the dispatch prompt from the muggle-test-prepare skill. You have no channel to the user: when the plan is missing a decision you need, return one `needs-input:` line naming it and stop — the dispatching skill resolves it (asking the user if needed) and re-dispatches.
10
+
11
+ ## Input contract
12
+
13
+ The dispatch prompt carries the resolved prepare plan:
14
+
15
+ - `services[]` — name, dir, start command, expected port, `external` flag, approval already granted.
16
+ - `testingScope` and `excludedServices[]` (with reasons).
17
+ - The recorded dev-server URL (from the `autoSelectLocalHost` resolution) — never invent or default a host/port; a framework default like `:3000` is not a fallback.
18
+ - Resolved gate values the stages read (`autoRebase` outcome already applied or explicitly skipped upstream).
19
+
20
+ ## Stages
21
+
22
+ Run these stage files from the skill, in order, exactly as written — they are the single source of truth for each stage's procedure:
23
+
24
+ 1. [`../skills/muggle-test-prepare/steps/check-running.md`](../skills/muggle-test-prepare/steps/check-running.md)
25
+ 2. [`../skills/muggle-test-prepare/steps/env-file.md`](../skills/muggle-test-prepare/steps/env-file.md)
26
+ 3. [`../skills/muggle-test-prepare/steps/start-commands.md`](../skills/muggle-test-prepare/steps/start-commands.md)
27
+ 4. [`../skills/muggle-test-prepare/steps/fresh-install.md`](../skills/muggle-test-prepare/steps/fresh-install.md)
28
+ 5. [`../skills/muggle-test-prepare/steps/start-services.md`](../skills/muggle-test-prepare/steps/start-services.md)
29
+ 6. [`../skills/muggle-test-prepare/steps/smoke-test.md`](../skills/muggle-test-prepare/steps/smoke-test.md)
30
+ 7. [`../skills/muggle-test-prepare/steps/readiness-report.md`](../skills/muggle-test-prepare/steps/readiness-report.md)
31
+
32
+ Where a stage file offers the user a choice, take the branch the plan resolved; where the plan doesn't cover it, return `needs-input:` — never guess, never start anything unapproved.
33
+
34
+ ## PID tracking
35
+
36
+ Track every launched process in `/tmp/muggle-test-prepare.json` exactly per the skill's schema (`session_started`, `testing_scope`, `excluded_services`, `services[]` with pid/port/log). Processes the user started independently stay `external: true` and are never killed. Prune dead PIDs silently.
37
+
38
+ ## Output contract
39
+
40
+ Return the readiness-report table verbatim as your report, prefixed by one line: `READY` (all services green), `DEGRADED: <which service, why>` (something is up but failed its smoke test after the clean-restart loop), or `needs-input: <decision>`. The dispatcher relays this to its caller — other skills gate on it, so a wrong `READY` is expensive; when in doubt between READY and DEGRADED, pick DEGRADED and say why. `needs-input:` is only for a decision the plan failed to resolve (a missing URL, an unapproved start, an unknown directory) — a service that stays broken after the loop is `DEGRADED` with the diagnosis, never `needs-input:`, even when no further automated fix exists. Repairing the app's own source code is out of scope entirely: a source-level bug surfaced by the smoke test is a `DEGRADED` diagnosis to report, not a decision to escalate.
41
+
42
+ ## Guardrails
43
+
44
+ - Privacy boundary as the skill defines it: file contents only inside directories the plan names; never traverse upward past one level.
45
+ - Port-listening is never enough — smoke-test (HTTP + body sniff + log tail) is mandatory before the report.
46
+ - Clean Restart is the first fix in the smoke-test loop; fresh-install notifies, doesn't ask.
47
+ - Never leave an orphan process untracked; never kill an `external` one.
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: visual-walkthrough-builder
3
+ description: "Renders the Muggle Test E2E visual walkthrough for a PR — assembles the E2eReport, runs `muggle build-pr-section`, and either posts to the PR (Mode A) or returns the rendered block to the dispatcher (Modes B/C). Dispatched by the muggle-pr-visual-walkthrough skill; carries its sonnet pin so the render runs on sonnet regardless of the session model."
4
+ model: sonnet
5
+ ---
6
+
7
+ # Visual Walkthrough Builder
8
+
9
+ You render and (in Mode A) post the Muggle Test E2E visual walkthrough. The dispatching skill has already resolved the mode, the PR, and user consent. You have no channel to the user: if an input you need is missing, return a single `needs-input:` line naming it and stop — the dispatching skill resolves it and re-dispatches.
10
+
11
+ ## Input contract
12
+
13
+ The dispatch prompt carries:
14
+
15
+ - `mode` — `post` (Mode A), `render-for-new-pr` (Mode B), or `embed` (Mode C).
16
+ - `prNumber` + repo — Mode A only, already verified to exist.
17
+ - The `E2eReport` JSON inline, **or** the run identifiers (`projectId`, per-test `runId`/`testCaseId` list) to assemble it from.
18
+
19
+ When assembling from identifiers, follow [`../skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md`](../skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md). The `E2eReport` schema, required fields, and the inconclusive rule live there and in the CLI's Zod schema (`src/cli/pr-section/types.ts`) — a run that couldn't produce pass/fail is `inconclusive` with a `reason`, never dropped.
20
+
21
+ ## Render
22
+
23
+ Pipe the report to the CLI; it writes `{"body": "...", "comment": "..." | null}`:
24
+
25
+ ```bash
26
+ echo "$REPORT_JSON" | muggle build-pr-section > /tmp/muggle-pr-section.json
27
+ ```
28
+
29
+ - Non-zero exit → surface the CLI's stderr verbatim; do not swallow or retry blindly.
30
+ - `comment` is non-null only in the overflow case; the CLI owns fit-vs-overflow.
31
+
32
+ ## Deliver
33
+
34
+ **Mode A (`post`)** — post `body` as a PR comment, then `comment` only if non-null. Append the Muggle Works signature to each posted body per [`../skills/_shared/vcs/post-signature.md`](../skills/_shared/vcs/post-signature.md) — this post is the walkthrough's own, so the command it names is `/muggle-pr-visual-walkthrough`:
35
+
36
+ ```bash
37
+ sig='🤖 _Posted by `/muggle-pr-visual-walkthrough` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_'
38
+ { jq -r '.body' /tmp/muggle-pr-section.json; printf '\n\n%s\n' "$sig"; } | gh pr comment <prNumber> --body-file -
39
+ { jq -r '.comment' /tmp/muggle-pr-section.json; printf '\n\n%s\n' "$sig"; } | gh pr comment <prNumber> --body-file - # skip when null
40
+ ```
41
+
42
+ Report back: PR URL + whether an overflow comment was posted.
43
+
44
+ **Modes B/C (`render-for-new-pr` / `embed`)** — do not post, do not touch `gh`. Return the CLI output verbatim as your report:
45
+
46
+ ```
47
+ body:
48
+ <body>
49
+ comment:
50
+ <comment or null>
51
+ ```
52
+
53
+ ## Guardrails
54
+
55
+ - Never hand-write or modify the walkthrough markdown — the CLI is the single source of truth. No custom tables, no added "Verdict" lines, no `Tested on:`/`Project:` footers; the CLI computes the verdict and emits per-test dashboard links.
56
+ - Never invent report fields — missing `projectId`, `viewUrl`, or `screenshotUrl` → `needs-input:`, never a placeholder.
57
+ - Never post the overflow comment when `comment` is null.
58
+ - Never create a PR, never choose a mode — both belong to the dispatcher.
@@ -1,36 +1,39 @@
1
- # Skill authoring conventions
2
-
3
- Rules for every skill under `plugin/skills/`. Read before adding or editing one.
4
-
5
- ## One-way dependencies — no reverse references
6
-
7
- Skill cross-references form a one-way graph. If any file in skill **A** references skill **B** — a markdown link to B's files, or a documented dependency on B's internals — then **no file in B may reference A back**. Reference *downward*, toward the more general / lower-level skill you depend on; pass anything the other direction needs as input, not as a link.
8
-
9
- A reverse reference (A → B and B → A) couples the depended-on skill to its caller, creates a cycle no one can reason about in isolation, and makes every edit ripple both ways. The lower-level skill must stay reusable by callers it has never heard of.
10
-
11
- **Runtime dispatch is not a doc reference.** A dumb-pipe skill may *fire* another skill's slash command at runtime (hand off and forget) — that is an action, not a dependency. What the rule forbids is a procedure file **linking to** or **encoding the internals of** the skill it hands off to.
12
-
13
- **Worked example.** `muggle-pr-followup` (the dumb-pipe watcher) is lower-level than `muggle-do` (the executor that orchestrates it). `muggle-do` references `muggle-pr-followup`; `muggle-pr-followup`'s files must not link back to `muggle-do`. A watcher tick still dispatches `/muggle-do …` at runtime — allowed — but no watcher file links a `do/` file or restates its steps, and shared primitives like `muggle-pr-followup/finalize.md` stay dispatch-free so any caller can reuse them.
14
-
15
- When you feel the urge to link "up" to a caller, that is the smell — restructure so the caller passes what is needed in.
16
-
17
- ### Enforcement
18
-
19
- `scripts/check-skill-deps.mjs` derives the cross-skill link graph and fails on any cycle. A "reference" is a markdown file-link into another skill's directory — runtime slash-command dispatch is not a link and is not counted. It runs three ways: the `skill-deps` CI job on every PR, a `PreToolUse` hook (`.claude/settings.json`) that blocks the write mid-session with the offending link named, and `pnpm run verify:skill-deps` locally.
20
-
21
- `plugin/skills/skill-deps.config.json` declares support dirs grouped into their owning skill (`do/` → `muggle-do`), shared namespaces exploded to per-file nodes (`_shared`), and `knownReverseDeps` — pre-existing violations grandfathered so CI stays green. That list is debt: fix each link and delete its entry. A new reverse dependency is blocked whether or not it is on the list.
22
-
23
- ## Model tiers
24
-
25
- Each skill sets a `model:` in its `SKILL.md` frontmatter sized to its cognitive load. `model:` is a native Claude Code field — the override applies while the skill is active and reverts to the session model when it exits. Cheaper, faster models run the mechanical skills; the default (Opus) is reserved for the ones that actually reason. Cost and latency scale with the model, and these skills run often (the watcher fires every minute), so the tier is a real lever, not cosmetics.
26
-
27
- | Model | Skills | Why this tier |
28
- |-------|--------|---------------|
29
- | `haiku` | `muggle`, `muggle-status`, `muggle-repair`, `muggle-upgrade`, `muggle-preferences`, `muggle-feedback`, `muggle-pr-followup` | Routers and dumb pipes. They follow an explicit procedure with no open-ended reasoning: route intent to a downstream skill, run a fixed CLI sequence, CRUD a config file, format a status report, or poll provider state and branch on conditions. `muggle-pr-followup` is the canonical case — a watcher that reads GitHub state and dispatches; all judgment lives in the `muggle-do` it hands off to. |
30
- | `sonnet` | `muggle-pr-visual-walkthrough`, `muggle-test-regenerate-missing` | Multi-step orchestration with light judgment, short of deep reasoning: assemble run data and build a PR section with fit-vs-overflow handling; scan, filter, bulk-dispatch, and classify per-item failures into buckets. More moving parts than a router, but each step is well-defined. |
31
- | `opus` (explicit pin) | `muggle-test-prepare` | Pinned for **reliability**, not raw reasoning load: it's flaky on smaller models, and since other skills gate on the environment it readies, a wrong call is expensive. Pin explicitly rather than leaving `model:` unset so it stays on Opus even when the user's session runs a cheaper model. |
32
- | default (Opus) — no `model:` set | `muggle-do`, `muggle-test`, `muggle-test-feature-local`, `muggle-browser-task`, `muggle-test-import` | Reasoning-heavy. Authoring code to a PR, mapping a code diff to affected user flows and interpreting E2E results, reasoning about an arbitrary website's flow to drive a browser, translating Playwright/Cypress/PRD artifacts into Muggle test cases. Leave `model:` unset so the skill inherits the session model. |
33
-
34
- **Choosing a tier for a new skill.** Ask what the skill actually does. Pure routing / fixed procedure / CRUD / reporting → `haiku`. Several well-defined steps with some judgment or classification → `sonnet`. Open-ended reasoning, code authoring, or interpreting ambiguous real-world state → leave `model:` unset (Opus). When unsure between two tiers, pick the cheaper one and watch for misbehavior — the likeliest to need a bump is anything doing AI-based classification. If a skill proves flaky on its tier and reliability matters more than cost (other skills depend on it, or a wrong call is expensive), pin it up explicitly — `model: opus` — rather than leaving it unset, so the floor holds regardless of the user's session model.
35
-
36
- **Never set `model:` on aliases or commands.** The alias skills (`m`, `mstatus`, …) and `plugin/commands/*.md` are thin routers that re-invoke the canonical skill via the `Skill` tool. The canonical `SKILL.md`'s `model:` takes effect once it loads, so a model on the alias would only apply to the negligible one-line hand-off — and risks drifting from the canonical value.
1
+ # Skill authoring conventions
2
+
3
+ Rules for every skill under `plugin/skills/`. Read before adding or editing one.
4
+
5
+ ## One-way dependencies — no reverse references
6
+
7
+ Skill cross-references form a one-way graph. If any file in skill **A** references skill **B** — a markdown link to B's files, or a documented dependency on B's internals — then **no file in B may reference A back**. Reference *downward*, toward the more general / lower-level skill you depend on; pass anything the other direction needs as input, not as a link.
8
+
9
+ A reverse reference (A → B and B → A) couples the depended-on skill to its caller, creates a cycle no one can reason about in isolation, and makes every edit ripple both ways. The lower-level skill must stay reusable by callers it has never heard of.
10
+
11
+ **Runtime dispatch is not a doc reference.** A dumb-pipe skill may *fire* another skill's slash command at runtime (hand off and forget) — that is an action, not a dependency. What the rule forbids is a procedure file **linking to** or **encoding the internals of** the skill it hands off to.
12
+
13
+ **Worked example.** `muggle-pr-followup` (the dumb-pipe watcher) is lower-level than `muggle-do` (the executor that orchestrates it). `muggle-do` references `muggle-pr-followup`; `muggle-pr-followup`'s files must not link back to `muggle-do`. A watcher tick still dispatches `/muggle-do …` at runtime — allowed — but no watcher file links a `do/` file or restates its steps, and shared primitives like `muggle-pr-followup/finalize.md` stay dispatch-free so any caller can reuse them.
14
+
15
+ When you feel the urge to link "up" to a caller, that is the smell — restructure so the caller passes what is needed in.
16
+
17
+ ### Enforcement
18
+
19
+ `scripts/check-skill-deps.mjs` derives the cross-skill link graph and fails on any cycle. A "reference" is a markdown file-link into another skill's directory — runtime slash-command dispatch is not a link and is not counted. It runs three ways: the `skill-deps` CI job on every PR, a `PreToolUse` hook (`.claude/settings.json`) that blocks the write mid-session with the offending link named, and `pnpm run verify:skill-deps` locally.
20
+
21
+ `plugin/skills/skill-deps.config.json` declares support dirs grouped into their owning skill (`do/` → `muggle-do`), shared namespaces exploded to per-file nodes (`_shared`), and `knownReverseDeps` — pre-existing violations grandfathered so CI stays green. That list is debt: fix each link and delete its entry. A new reverse dependency is blocked whether or not it is on the list.
22
+
23
+ ## Model tiers
24
+
25
+ Each skill sets a `model:` in its `SKILL.md` frontmatter sized to its cognitive load. `model:` is a native Claude Code field — the override applies while the skill is active and reverts to the session model when it exits. Cheaper, faster models run the mechanical skills; the default (Opus) is reserved for the ones that actually reason. Cost and latency scale with the model, and these skills run often (the watcher fires every minute), so the tier is a real lever, not cosmetics.
26
+
27
+ | Model | Skills | Why this tier |
28
+ |-------|--------|---------------|
29
+ | `haiku` | `muggle`, `muggle-status`, `muggle-repair`, `muggle-upgrade`, `muggle-preferences`, `muggle-feedback`, `muggle-pr-followup` | Routers and dumb pipes. They follow an explicit procedure with no open-ended reasoning: route intent to a downstream skill, run a fixed CLI sequence, CRUD a config file, format a status report, or poll provider state and branch on conditions. `muggle-pr-followup` is the canonical case — a watcher that reads GitHub state and dispatches; all judgment lives in the `muggle-do` it hands off to. |
30
+ | `sonnet` | `muggle-pr-visual-walkthrough` (executes via the `visual-walkthrough-builder` agent), `muggle-test-regenerate-missing` | Multi-step orchestration with light judgment, short of deep reasoning: assemble run data and build a PR section with fit-vs-overflow handling; scan, filter, bulk-dispatch, and classify per-item failures into buckets. More moving parts than a router, but each step is well-defined. |
31
+ | `opus` (explicit pin) | `muggle-test-prepare` (executes via the `test-prepare-runner` agent) | Pinned for **reliability**, not raw reasoning load: it's flaky on smaller models, and since other skills gate on the environment it readies, a wrong call is expensive. Pin explicitly rather than leaving `model:` unset so it stays on Opus even when the user's session runs a cheaper model. |
32
+
33
+ | default (Opus) — no `model:` set | `muggle-do`, `muggle-test`, `muggle-test-feature-local`, `muggle-browser-task`, `muggle-test-import` | Reasoning-heavy. Authoring code to a PR, mapping a code diff to affected user flows and interpreting E2E results, reasoning about an arbitrary website's flow to drive a browser, translating Playwright/Cypress/PRD artifacts into Muggle test cases. Leave `model:` unset so the skill inherits the session model. |
34
+
35
+ **A `SKILL.md` `model:` only bites when the skill starts a fresh session; invoked mid-session the session model keeps running.** A skill whose pin must hold regardless resolves its user interaction in the `SKILL.md`, then dispatches a `plugin/agents/*` agent that carries the pin — the harness applies an agent's `model:` on every dispatch. That is why `muggle-pr-visual-walkthrough`, `muggle-test-prepare`, and `muggle-pr-followup` execute through agents. Agents have no user channel; an unresolved decision comes back as `needs-input:` for the skill to resolve.
36
+
37
+ **Choosing a tier for a new skill.** Ask what the skill actually does. Pure routing / fixed procedure / CRUD / reporting → `haiku`. Several well-defined steps with some judgment or classification → `sonnet`. Open-ended reasoning, code authoring, or interpreting ambiguous real-world state → leave `model:` unset (Opus). When unsure between two tiers, pick the cheaper one and watch for misbehavior — the likeliest to need a bump is anything doing AI-based classification. If a skill proves flaky on its tier and reliability matters more than cost (other skills depend on it, or a wrong call is expensive), pin it up explicitly — `model: opus` — rather than leaving it unset, so the floor holds regardless of the user's session model.
38
+
39
+ **Never set `model:` on aliases or commands.** The alias skills (`m`, `mstatus`, …) and `plugin/commands/*.md` are thin routers that re-invoke the canonical skill via the `Skill` tool. The canonical `SKILL.md`'s `model:` takes effect once it loads, so a model on the alias would only apply to the negligible one-line hand-off — and risks drifting from the canonical value.