@muggleai/works 5.8.0 → 5.9.0

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.
Files changed (38) hide show
  1. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  2. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  3. package/dist/plugin/agents/test-prepare-runner.md +47 -0
  4. package/dist/plugin/agents/visual-walkthrough-builder.md +58 -0
  5. package/dist/plugin/hooks/hooks.json +6 -0
  6. package/dist/plugin/scripts/guardrail-watch-gate.sh +40 -0
  7. package/dist/plugin/scripts/guardrails.mjs +84 -2
  8. package/dist/plugin/scripts/pr-watch-guards.sh +17 -0
  9. package/dist/plugin/skills/CLAUDE.md +39 -36
  10. package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +5 -3
  11. package/dist/plugin/skills/muggle-pr-followup/blocked-tick.md +2 -2
  12. package/dist/plugin/skills/muggle-pr-followup/cancel-cron.md +5 -3
  13. package/dist/plugin/skills/muggle-pr-followup/contract.md +8 -2
  14. package/dist/plugin/skills/muggle-pr-followup/evals/evals.json +30 -3
  15. package/dist/plugin/skills/muggle-pr-followup/finalize.md +1 -1
  16. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +3 -1
  17. package/dist/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +41 -236
  18. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +130 -129
  19. package/dist/release-manifest.json +4 -4
  20. package/package.json +7 -6
  21. package/plugin/.claude-plugin/plugin.json +1 -1
  22. package/plugin/.cursor-plugin/plugin.json +1 -1
  23. package/plugin/agents/test-prepare-runner.md +47 -0
  24. package/plugin/agents/visual-walkthrough-builder.md +58 -0
  25. package/plugin/hooks/hooks.json +6 -0
  26. package/plugin/scripts/guardrail-watch-gate.sh +40 -0
  27. package/plugin/scripts/guardrails.mjs +84 -2
  28. package/plugin/scripts/pr-watch-guards.sh +17 -0
  29. package/plugin/skills/CLAUDE.md +39 -36
  30. package/plugin/skills/muggle-pr-followup/arm-watcher.md +5 -3
  31. package/plugin/skills/muggle-pr-followup/blocked-tick.md +2 -2
  32. package/plugin/skills/muggle-pr-followup/cancel-cron.md +5 -3
  33. package/plugin/skills/muggle-pr-followup/contract.md +8 -2
  34. package/plugin/skills/muggle-pr-followup/evals/evals.json +30 -3
  35. package/plugin/skills/muggle-pr-followup/finalize.md +1 -1
  36. package/plugin/skills/muggle-pr-followup/state-schemas.md +3 -1
  37. package/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +41 -236
  38. package/plugin/skills/muggle-test-prepare/SKILL.md +130 -129
@@ -1,236 +1,41 @@
1
- ---
2
- name: muggle-pr-visual-walkthrough
3
- model: sonnet
4
- description: Renders and posts a visual walkthrough of Muggle AI E2E acceptance test results to a PR — per-test-case dashboard links, step-by-step screenshots, and pass/fail summary — using the `muggle build-pr-section` CLI for deterministic formatting with automatic fit-vs-overflow. Use at the end of any Muggle Test test run (local or remote) to give PR reviewers clickable visual evidence that user flows work. Triggers on 'post results to PR', 'attach walkthrough to PR', 'share E2E screenshots on the PR', 'add visual walkthrough to PR'.
5
- ---
6
-
7
- # Muggle Test PR Visual Walkthrough
8
-
9
- > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-pr-visual-walkthrough"`.
10
-
11
- Renders a visual walkthrough of Muggle AI E2E acceptance test results and posts it to a PR. Each test case is linked to its detail page on the Muggle AI dashboard, so PR reviewers can click through to see step-by-step screenshots and action scripts — not just a pass/fail flag.
12
-
13
- This is the **canonical PR-walkthrough workflow** shared across every Muggle Test entry point:
14
-
15
- | Caller | Mode | When to invoke |
16
- | :--- | :--- | :--- |
17
- | `muggle-test` | **Mode A** (post to existing PR) | After publishing results, user opts in via `AskUserQuestion` |
18
- | `muggle-test-feature-local` | **Mode A** (post to existing PR) | After publishing the run, user opts in via `AskUserQuestion` |
19
- | `muggle-do` / `open-prs.md` | **Mode B** (render-only for embedding) | During PR creation — caller embeds `body` in `gh pr create` and posts `comment` as follow-up |
20
- | `muggle-test` Mode C / `acceptance-tester` agent | **Mode C** (embed in verdict comment) | Inside a open-PR sweep orchestrator — caller folds the rendered body into a single per-PR verdict comment instead of posting separately |
21
-
22
- Rendering is always done by `muggle build-pr-section`, a battle-tested CLI that handles deterministic markdown layout, per-step screenshots, and automatic fit-vs-overflow (oversized content spills into a follow-up comment). Never hand-write the walkthrough markdown.
23
-
24
- ## Preferences
25
-
26
- This skill is invoked by callers (`muggle-test`, `muggle-test-feature-local`, `muggle-do`) **after** the caller has already consulted the `postPRVisualWalkthrough` gate and decided to post. Therefore **the gating happens upstream, not in this skill** — by the time this skill runs, the user has already approved posting (either via the saved gate value or by explicit pick).
27
-
28
- | Preference | Where it's gated | Decision it gates |
29
- |------------|------------------|-------------------|
30
- | `postPRVisualWalkthrough` | Caller skill (e.g. `muggle-test` Step 9, `muggle-test-feature-local` Step 10) | Post visual walkthrough to PR |
31
-
32
- Per-key gate definitions live in `plugin/skills/muggle-preferences/preference-gates/`. This skill only renders and posts.
33
-
34
- ## Input contract: the `E2eReport` JSON
35
-
36
- Every caller must build an `E2eReport` JSON object and have it in conversation context before invoking this skill. The schema is defined in `src/cli/pr-section/types.ts` (`E2eReportSchema`) and enforced by the CLI with Zod — malformed input exits non-zero with a descriptive stderr message.
37
-
38
- ```json
39
- {
40
- "projectId": "<UUID>",
41
- "tests": [
42
- {
43
- "name": "<test case title>",
44
- "description": "<one-line description of what this test verifies>",
45
- "useCaseName": "<parent use case title>",
46
- "testCaseId": "<UUID>",
47
- "testScriptId": "<UUID>",
48
- "runId": "<UUID>",
49
- "viewUrl": "https://www.muggle-ai.com/...",
50
- "status": "passed",
51
- "steps": [
52
- { "stepIndex": 0, "action": "Click login button", "screenshotUrl": "https://..." },
53
- { "stepIndex": 1, "action": "Type email", "screenshotUrl": "https://..." }
54
- ]
55
- },
56
- {
57
- "name": "Checkout flow",
58
- "description": "Verify a shopper can complete checkout with a saved card.",
59
- "useCaseName": "Purchase",
60
- "testCaseId": "<UUID>",
61
- "testScriptId": "<UUID>",
62
- "runId": "<UUID>",
63
- "viewUrl": "https://www.muggle-ai.com/...",
64
- "status": "failed",
65
- "steps": [
66
- { "stepIndex": 0, "action": "Open cart", "screenshotUrl": "https://..." }
67
- ],
68
- "failureStepIndex": 2,
69
- "error": "Element not found: Click checkout button",
70
- "artifactsDir": "/Users/.../~/.muggle-ai/sessions/<runId>"
71
- },
72
- {
73
- "name": "Clear search input restores full list",
74
- "description": "Verify clearing the search input restores all options.",
75
- "useCaseName": "Filter Dropdowns",
76
- "testCaseId": "<UUID>",
77
- "runId": "<UUID>",
78
- "viewUrl": "https://www.muggle-ai.com/...",
79
- "status": "inconclusive",
80
- "steps": [],
81
- "reason": "No replayable script exists yet — needs first generation run."
82
- }
83
- ]
84
- }
85
- ```
86
-
87
- Required fields per test: `name`, `testCaseId`, `runId`, `viewUrl`, `status`, `steps[]` with `{stepIndex, action, screenshotUrl}`.
88
-
89
- - **Failed** tests additionally require `failureStepIndex` and `error`.
90
- - **Inconclusive** tests additionally require `reason` (one short sentence on why the result is neither pass nor fail). `steps[]` may be empty — that's fine. Inconclusive is for runs that couldn't be classified pass/fail (no replayable script, environment precondition unmet, infra error blocked execution, agent stalled before reaching the assertion). **Never silently drop these — always emit them as `inconclusive`.** The CLI counts them in the overview and renders an `⚠️` row with the dashboard link so reviewers can click through. If you find yourself wanting to skip a test or hand-write a comment because the schema "doesn't fit," that is the schema fitting — use `inconclusive`.
91
-
92
- ### Verdict
93
-
94
- The renderer computes a verdict from the tests and emits a `**Verdict:** ✅ PASS | ❌ FAIL | ⚠️ INCONCLUSIVE` line at the top of the overview. The policy is strict:
95
-
96
- - Any failed test → **FAIL** (regardless of how many passed or are inconclusive).
97
- - No failures but any inconclusive → **INCONCLUSIVE**.
98
- - All passed → **PASS**.
99
- - Empty report → no verdict line.
100
-
101
- You do not compute or render the verdict yourself — the CLI does. Never write a "Verdict: PASS" line into a hand-edited summary; it will conflict with the CLI's computed verdict.
102
-
103
- **Optional but recommended** per test:
104
- - `description` — a one-line summary of what the test case verifies. Shown in the collapsible header for each test and helps reviewers understand the test without expanding it. Pull from the test case's `title`/`description` via `muggle-remote-test-case-get`.
105
- - `useCaseName` — the parent use case title. When present on any test, the overview list is grouped by use case; otherwise it is rendered as a flat list. Pull from `muggle-remote-use-case-get` using the test case's parent use-case id.
106
- - `testScriptId` and `artifactsDir` are also optional.
107
-
108
- If any required field is missing, stop and tell the caller exactly what's missing. Never fabricate data.
109
-
110
- ## Step 1: Assemble the `E2eReport`
111
-
112
- Read `plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md` for the full assembly guide.
113
-
114
- ## Step 2: Render via `muggle build-pr-section`
115
-
116
- Pipe the `E2eReport` JSON to the CLI. It writes `{"body": "...", "comment": "..." | null}` to stdout — the `body` is the E2E markdown block, and `comment` is a non-null overflow comment only when the full body exceeds the byte budget (default 60 KB).
117
-
118
- ```bash
119
- echo "$REPORT_JSON" | muggle build-pr-section > /tmp/muggle-pr-section.json
120
- ```
121
-
122
- - Exit **non-zero** → the CLI wrote a descriptive error to stderr. Surface it to the user; do not swallow it.
123
- - `comment` is **`null`** (fit case) → everything is inline in `body`. Post `body` only.
124
- - `comment` is a **non-null string** (overflow case) → `body` contains the summary + a pointer; `comment` contains the full per-step details. Post both, in order.
125
-
126
- Never hand-write the walkthrough markdown. Never modify the CLI's output before posting. The CLI owns the format.
127
-
128
- ## Step 3 — Mode A: Post to an existing PR
129
-
130
- Used by `muggle-test` and `muggle-test-feature-local`, where the user is mid-development and a PR already exists on the current branch.
131
-
132
- ### 3A.1: Find the PR
133
-
134
- ```bash
135
- gh pr view --json number,url,title 2>/dev/null
136
- ```
137
-
138
- - **PR exists** → continue to 3A.2
139
- - **No PR exists** → use `AskUserQuestion`:
140
- - "Create a new PR with the visual walkthrough in the body"
141
- - "Skip posting"
142
- - If the user chooses to create a new PR, switch to Mode B and return the rendered `body`/`comment` to the caller for embedding in `gh pr create`. Do not create the PR directly from this skill unless the caller has no better way to do it.
143
- - **`gh` not installed or not authenticated** → tell the user, suggest `gh auth login`, stop.
144
-
145
- ### 3A.2: Post the body as a PR comment
146
-
147
- Extract the `body` field with `jq -r` (not `sed`) so JSON escape sequences are properly decoded, append the Muggle Works signature (command `/muggle-pr-visual-walkthrough`) per [`../_shared/vcs/post-signature.md`](../_shared/vcs/post-signature.md), then pipe to `--body-file -`. The renderer's sentinel stays at the top of `body`, so the report-format guardrail still recognises the post:
148
-
149
- ```bash
150
- {
151
- jq -r '.body' /tmp/muggle-pr-section.json
152
- printf '\n\n%s\n' '🤖 _Posted by `/muggle-pr-visual-walkthrough` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_'
153
- } | gh pr comment <pr-number> --body-file -
154
- ```
155
-
156
- ### 3A.3: Post the overflow comment only if the CLI emitted one
157
-
158
- ```bash
159
- {
160
- jq -r '.comment' /tmp/muggle-pr-section.json
161
- printf '\n\n%s\n' '🤖 _Posted by `/muggle-pr-visual-walkthrough` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_'
162
- } | gh pr comment <pr-number> --body-file -
163
- ```
164
-
165
- **Skip this step entirely if `comment` is `null`** — do not post a placeholder. The CLI decides fit-vs-overflow; never post the overflow comment speculatively.
166
-
167
- ### 3A.4: Confirm to the user
168
-
169
- > "Visual walkthrough posted to PR #<number>. Reviewers can click any test case link to see the step-by-step screenshots on the Muggle AI dashboard."
170
-
171
- Include the PR URL in the confirmation.
172
-
173
- ## Step 3 — Mode B: Return rendered block for embedding in a new PR
174
-
175
- Used by `muggle-do`'s `open-prs.md`, where the PR does not exist yet and the caller is assembling the PR body from multiple sections (`## Goal`, `## Acceptance Criteria`, `## Changes`, plus this walkthrough).
176
-
177
- Instead of posting, **return** the CLI output to the caller's context so they can:
178
-
179
- 1. **Embed `body`** in their PR body, concatenated after `## Changes`. `body` already includes its own `## E2E Acceptance Results` header — do not add another.
180
- 2. **Create the PR** with `gh pr create --title "..." --body "..."` using the concatenated body.
181
- 3. **Post `comment` as a follow-up only if the CLI emitted one**, ending the posted body with the signature (the caller owns this post, so command `/muggle-do`) per [`../_shared/vcs/post-signature.md`](../_shared/vcs/post-signature.md):
182
-
183
- ```bash
184
- {
185
- jq -r '.comment' /tmp/muggle-pr-section.json
186
- printf '\n\n%s\n' '🤖 _Posted by `/muggle-do` · [Muggle Works](https://github.com/multiplex-ai/muggle-ai-works)_'
187
- } | gh pr comment <new-pr-number> --body-file -
188
- ```
189
-
190
- Skip if `comment` is `null`.
191
-
192
- In Mode B, this skill does not call `gh pr comment` or `gh pr create` itself — the caller owns PR creation because it also owns branch pushing, title building (including `[E2E FAILING]` prefix on failures), and multi-repo orchestration.
193
-
194
- ## Step 3 — Mode C: Embed mode for open-PR sweep orchestrators
195
-
196
- Used when invoked as a sub-step of a open-PR sweep orchestrator (see `plugin/skills/muggle-test/SKILL.md` Mode C) rather than as a top-level user invocation. The orchestrator's `acceptance-tester` subagent (see `plugin/agents/acceptance-tester.md`) composes a **single per-PR verdict comment** and folds the walkthrough into it — posting separately would create 2–3 disparate comments per test cycle and clutter the PR.
197
-
198
- ### 3C.1: Detect embed mode
199
-
200
- The caller passes `mode: "embed"` as a skill argument. Default behavior (no `mode` passed, or `mode: "post"`) is Mode A — unchanged.
201
-
202
- ### 3C.2: Render but do not post
203
-
204
- Run `muggle build-pr-section` exactly as in Step 2. Then, **instead of calling `gh pr comment`**:
205
-
206
- 1. **Return** the CLI output (`{ body, comment }`) to the caller as this skill's result.
207
- 2. Do **not** find a PR, do **not** post a standalone comment, do **not** prompt the user.
208
- 3. If `comment` is non-null (overflow case), return it alongside `body` — the orchestrator decides how to handle overflow (typically: inline `body` in the verdict comment, post `comment` as a follow-up).
209
-
210
- ### 3C.3: Hand off
211
-
212
- The orchestrator (`acceptance-tester`) concatenates the returned `body` into its verdict comment template alongside the verdict summary, change-list, and any other sections it owns, then posts a single `gh pr comment` itself. This skill's job ends at returning the rendered markdown.
213
-
214
- In Mode C, the same fit-vs-overflow contract from Step 2 applies — never modify the CLI's output, never fabricate fields, never post anything. The caller owns posting.
215
-
216
- ## Tool Reference
217
-
218
- | Phase | Tool |
219
- |:------|:-----|
220
- | Gather per-step data (muggle-test, muggle-test-feature-local) | `muggle-remote-test-script-get` |
221
- | Render the walkthrough markdown | `muggle build-pr-section` (shell) |
222
- | Find existing PR (Mode A) | `gh pr view` |
223
- | Post comment(s) (Mode A) | `gh pr comment` |
224
- | Create new PR (Mode B, caller handles) | `gh pr create` |
225
- | User confirmation (Mode A no-PR branch) | `AskUserQuestion` |
226
-
227
- ## Guardrails
228
-
229
- - **Never hand-write the walkthrough markdown** — always call `muggle build-pr-section`. The CLI is the single source of truth for formatting. If a test outcome doesn't fit `passed | failed`, that's what `inconclusive` is for — never fall back to a hand-written summary, a custom table, a "Verdict: PASS" header, a `Tested on:`/`Project:` footer, or any other freeform text. The CLI already emits per-test-case dashboard links (no project-level link), uses `https://www.muggle-ai.com/...` URLs (never the test target's `localhost` URL), and computes the verdict — anything you would manually add is wrong by construction.
230
- - **Never modify the CLI's output** — post `body` and (if present) `comment` verbatim. Any reformatting defeats the fit-vs-overflow budget math.
231
- - **Never invent report fields** — if `projectId`, a per-test `viewUrl`, or per-step `screenshotUrl` is missing, stop and report what's missing. Do not fabricate URLs or fill in placeholders.
232
- - **Never post the overflow comment when `comment` is `null`** — the CLI decides fit-vs-overflow.
233
- - **Never create a PR without confirmation in Mode A** — if no PR exists, ask the user or switch to Mode B and hand back to the caller.
234
- - **Don't run tests** — this skill only renders and posts existing results. If the `E2eReport` is not in context, redirect the caller to `muggle-test`, `muggle-test-feature-local`, or `muggle-do`.
235
- - **Mode is chosen by the caller, not the user** — `muggle-test` top-level uses Mode A; `muggle-do` uses Mode B; open-PR sweep orchestrators (`muggle-test` Mode C / `acceptance-tester`) pass `mode: "embed"` for Mode C. Don't ask the user which mode to use.
236
- - **Never post in Mode C** — when `mode: "embed"` is passed, return the rendered body to the caller and stop. The orchestrator owns the single verdict comment.
1
+ ---
2
+ name: muggle-pr-visual-walkthrough
3
+ model: sonnet
4
+ description: Renders and posts a visual walkthrough of Muggle AI E2E acceptance test results to a PR — per-test-case dashboard links, step-by-step screenshots, and pass/fail summary — using the `muggle build-pr-section` CLI for deterministic formatting with automatic fit-vs-overflow. Use at the end of any Muggle Test test run (local or remote) to give PR reviewers clickable visual evidence that user flows work. Triggers on 'post results to PR', 'attach walkthrough to PR', 'share E2E screenshots on the PR', 'add visual walkthrough to PR'.
5
+ ---
6
+
7
+ # Muggle Test PR Visual Walkthrough
8
+
9
+ > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-pr-visual-walkthrough"`.
10
+
11
+ Renders a visual walkthrough of Muggle AI E2E acceptance test results and posts it to a PR. Each test case links to its detail page on the Muggle AI dashboard, so reviewers can click through to step-by-step screenshots — not just a pass/fail flag.
12
+
13
+ This skill is a **dispatcher**: it resolves the mode and any user interaction, then hands execution to the `visual-walkthrough-builder` agent (`plugin/agents/visual-walkthrough-builder.md`), which renders and delivers per its own contract.
14
+
15
+ This is the **canonical PR-walkthrough workflow** shared across every Muggle Test entry point:
16
+
17
+ | Caller | Mode | When to invoke |
18
+ | :--- | :--- | :--- |
19
+ | `muggle-test` | **Mode A** (post to existing PR) | After publishing results, user opts in via `AskUserQuestion` |
20
+ | `muggle-test-feature-local` | **Mode A** (post to existing PR) | After publishing the run, user opts in via `AskUserQuestion` |
21
+ | `muggle-do` / `open-prs.md` | **Mode B** (render-only for embedding) | During PR creation — caller embeds `body` in the PR create call and posts `comment` as follow-up |
22
+ | `muggle-test` Mode C / `acceptance-tester` agent | **Mode C** (embed in verdict comment) | Inside an open-PR sweep orchestrator — caller folds the rendered body into a single per-PR verdict comment |
23
+
24
+ ## Preferences
25
+
26
+ Callers consult the `postPRVisualWalkthrough` gate **before** invoking this skill — by the time it runs, posting is already approved. Per-key gate definitions live in `plugin/skills/muggle-preferences/preference-gates/`.
27
+
28
+ ## Procedure
29
+
30
+ 1. **Resolve the mode.** Chosen by the caller, never the user: top-level `muggle-test`/`muggle-test-feature-local` → `post` (Mode A); `muggle-do` PR creation → `render-for-new-pr` (Mode B); an orchestrator passing `mode: "embed"` → Mode C.
31
+ 2. **Mode A only — find the PR** with `gh pr view --json number,url,title`. No PR on the branch → `AskUserQuestion`: create a new PR with the walkthrough in the body (switch to Mode B and hand the rendered block back to the caller), or skip posting. `gh` missing/unauthenticated → tell the user, suggest `gh auth login`, stop. This is the skill's only interactive branch — resolve it **before** dispatching.
32
+ 3. **Gather the inputs.** The `E2eReport` JSON if the caller already assembled it (see [`e2e-report-assembly.md`](e2e-report-assembly.md)), else the run identifiers (`projectId`, per-test `runId`/`testCaseId`) the agent needs to assemble it.
33
+ 4. **Dispatch** the `visual-walkthrough-builder` agent (subagent type `muggle:visual-walkthrough-builder`; bare `visual-walkthrough-builder` where the plugin namespace is absent), synchronously, passing: mode, PR number + repo (Mode A), and the report JSON or identifiers. In a harness with no agent/subagent facility, execute `plugin/agents/visual-walkthrough-builder.md` inline instead.
34
+ 5. **Relay the result.** Mode A → confirm to the user with the PR URL. Modes B/C → return the agent's `{body, comment}` to the caller verbatim; the caller owns PR creation (Mode B) or the single verdict comment (Mode C). A `needs-input:` line from the agent names a missing report field — surface it to the caller; never fabricate the field.
35
+
36
+ ## Guardrails
37
+
38
+ - The rendered markdown is CLI-owned end to end — this skill never writes, edits, or post-processes it; those rules ride with the agent.
39
+ - Mode is chosen by the caller, not the user.
40
+ - Never create a PR without confirmation in Mode A.
41
+ - Don't run tests — this skill only dispatches rendering/posting of existing results. No report and no run identifiers in context → redirect the caller to `muggle-test`, `muggle-test-feature-local`, or `muggle-do`.
@@ -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.