@muggleai/works 4.13.1 → 4.15.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 (137) hide show
  1. package/README.md +3 -3
  2. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  3. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  4. package/dist/plugin/README.md +1 -1
  5. package/dist/plugin/agents/acceptance-tester.md +2 -0
  6. package/dist/plugin/commands/mbt.md +7 -0
  7. package/dist/plugin/commands/mdo.md +3 -3
  8. package/dist/plugin/commands/mprfollowup.md +7 -0
  9. package/dist/plugin/skills/CLAUDE.md +15 -0
  10. package/dist/plugin/skills/_aliases.json +2 -1
  11. package/dist/plugin/skills/_shared/ci-check-to-command.md +10 -0
  12. package/dist/plugin/skills/_shared/dev-loop/action-script.md +3 -0
  13. package/dist/plugin/skills/_shared/dev-loop/failures.md +14 -0
  14. package/dist/plugin/skills/_shared/dev-loop/fresh-session.md +10 -0
  15. package/dist/plugin/skills/_shared/dev-loop/publish.md +13 -0
  16. package/dist/plugin/skills/_shared/dev-loop/run.md +34 -0
  17. package/dist/plugin/skills/_shared/dev-loop/timeouts.md +6 -0
  18. package/dist/plugin/skills/_shared/failure-mode-handling.md +2 -2
  19. package/dist/plugin/skills/_shared/github-cli-recipes/pr-checks.md +22 -0
  20. package/dist/plugin/skills/_shared/github-cli-recipes.md +1 -0
  21. package/dist/plugin/skills/_shared/post-merge-cleanup.md +1 -1
  22. package/dist/plugin/skills/_shared/pr-branch-worktree.md +1 -1
  23. package/dist/plugin/skills/_shared/rebase-before-e2e.md +7 -1
  24. package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -1
  25. package/dist/plugin/skills/_shared/resolve-rebase-conflicts.md +60 -0
  26. package/dist/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +8 -1
  27. package/dist/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +2 -1
  28. package/dist/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +4 -0
  29. package/dist/plugin/skills/_shared/use-worktrees.md +2 -1
  30. package/dist/plugin/skills/do/address-reviews.md +7 -1
  31. package/dist/plugin/skills/do/build.md +2 -1
  32. package/dist/plugin/skills/do/cleanup.md +14 -0
  33. package/dist/plugin/skills/do/e2e-acceptance.md +5 -66
  34. package/dist/plugin/skills/do/fix-ci.md +60 -0
  35. package/dist/plugin/skills/do/input-routing.md +12 -0
  36. package/dist/plugin/skills/do/open-prs/forward.md +3 -3
  37. package/dist/plugin/skills/do/open-prs/update.md +1 -1
  38. package/dist/plugin/skills/do/pre-flight.md +3 -3
  39. package/dist/plugin/skills/mbt/SKILL.md +8 -0
  40. package/dist/plugin/skills/mdo/SKILL.md +3 -3
  41. package/dist/plugin/skills/mprfollowup/SKILL.md +8 -0
  42. package/dist/plugin/skills/muggle/SKILL.md +1 -0
  43. package/{plugin/skills/muggle-do-task → dist/plugin/skills/muggle-browser-task}/SKILL.md +1 -1
  44. package/dist/plugin/skills/muggle-do/SKILL.md +29 -10
  45. package/dist/plugin/skills/muggle-feedback/SKILL.md +1 -1
  46. package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +4 -5
  47. package/dist/plugin/skills/muggle-pr-followup/SKILL.md +5 -3
  48. package/dist/plugin/skills/muggle-pr-followup/auto-track.md +5 -1
  49. package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +5 -3
  50. package/dist/plugin/skills/muggle-pr-followup/contract.md +34 -17
  51. package/dist/plugin/skills/muggle-pr-followup/finalize.md +29 -0
  52. package/dist/plugin/skills/muggle-pr-followup/reconcile.md +33 -0
  53. package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +10 -2
  54. package/dist/plugin/skills/muggle-preferences/ops/configure.md +2 -1
  55. package/dist/plugin/skills/muggle-preferences/preference-gates/autoResolveConflicts.md +11 -0
  56. package/dist/plugin/skills/muggle-preferences/preference-gates/autoWatchPR.md +13 -0
  57. package/dist/plugin/skills/muggle-preferences/preference-gates/reusePreparePlan.md +11 -0
  58. package/dist/plugin/skills/muggle-status/SKILL.md +1 -1
  59. package/dist/plugin/skills/muggle-test/SKILL.md +30 -48
  60. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +20 -44
  61. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +5 -1
  62. package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +7 -5
  63. package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +2 -0
  64. package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +30 -0
  65. package/dist/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +44 -0
  66. package/dist/release-manifest.json +4 -4
  67. package/package.json +7 -6
  68. package/plugin/.claude-plugin/plugin.json +1 -1
  69. package/plugin/.cursor-plugin/plugin.json +1 -1
  70. package/plugin/README.md +1 -1
  71. package/plugin/agents/acceptance-tester.md +2 -0
  72. package/plugin/commands/mbt.md +7 -0
  73. package/plugin/commands/mdo.md +3 -3
  74. package/plugin/commands/mprfollowup.md +7 -0
  75. package/plugin/skills/CLAUDE.md +15 -0
  76. package/plugin/skills/_aliases.json +2 -1
  77. package/plugin/skills/_shared/ci-check-to-command.md +10 -0
  78. package/plugin/skills/_shared/dev-loop/action-script.md +3 -0
  79. package/plugin/skills/_shared/dev-loop/failures.md +14 -0
  80. package/plugin/skills/_shared/dev-loop/fresh-session.md +10 -0
  81. package/plugin/skills/_shared/dev-loop/publish.md +13 -0
  82. package/plugin/skills/_shared/dev-loop/run.md +34 -0
  83. package/plugin/skills/_shared/dev-loop/timeouts.md +6 -0
  84. package/plugin/skills/_shared/failure-mode-handling.md +2 -2
  85. package/plugin/skills/_shared/github-cli-recipes/pr-checks.md +22 -0
  86. package/plugin/skills/_shared/github-cli-recipes.md +1 -0
  87. package/plugin/skills/_shared/post-merge-cleanup.md +1 -1
  88. package/plugin/skills/_shared/pr-branch-worktree.md +1 -1
  89. package/plugin/skills/_shared/rebase-before-e2e.md +7 -1
  90. package/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -1
  91. package/plugin/skills/_shared/resolve-rebase-conflicts.md +60 -0
  92. package/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +8 -1
  93. package/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +2 -1
  94. package/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +4 -0
  95. package/plugin/skills/_shared/use-worktrees.md +2 -1
  96. package/plugin/skills/do/address-reviews.md +7 -1
  97. package/plugin/skills/do/build.md +2 -1
  98. package/plugin/skills/do/cleanup.md +14 -0
  99. package/plugin/skills/do/e2e-acceptance.md +5 -66
  100. package/plugin/skills/do/fix-ci.md +60 -0
  101. package/plugin/skills/do/input-routing.md +12 -0
  102. package/plugin/skills/do/open-prs/forward.md +3 -3
  103. package/plugin/skills/do/open-prs/update.md +1 -1
  104. package/plugin/skills/do/pre-flight.md +3 -3
  105. package/plugin/skills/mbt/SKILL.md +8 -0
  106. package/plugin/skills/mdo/SKILL.md +3 -3
  107. package/plugin/skills/mprfollowup/SKILL.md +8 -0
  108. package/plugin/skills/muggle/SKILL.md +1 -0
  109. package/{dist/plugin/skills/muggle-do-task → plugin/skills/muggle-browser-task}/SKILL.md +1 -1
  110. package/plugin/skills/muggle-do/SKILL.md +29 -10
  111. package/plugin/skills/muggle-feedback/SKILL.md +1 -1
  112. package/plugin/skills/muggle-pr-followup/CLAUDE.md +4 -5
  113. package/plugin/skills/muggle-pr-followup/SKILL.md +5 -3
  114. package/plugin/skills/muggle-pr-followup/auto-track.md +5 -1
  115. package/plugin/skills/muggle-pr-followup/bootstrap.md +5 -3
  116. package/plugin/skills/muggle-pr-followup/contract.md +34 -17
  117. package/plugin/skills/muggle-pr-followup/finalize.md +29 -0
  118. package/plugin/skills/muggle-pr-followup/reconcile.md +33 -0
  119. package/plugin/skills/muggle-pr-followup/state-schemas.md +10 -2
  120. package/plugin/skills/muggle-preferences/ops/configure.md +2 -1
  121. package/plugin/skills/muggle-preferences/preference-gates/autoResolveConflicts.md +11 -0
  122. package/plugin/skills/muggle-preferences/preference-gates/autoWatchPR.md +13 -0
  123. package/plugin/skills/muggle-preferences/preference-gates/reusePreparePlan.md +11 -0
  124. package/plugin/skills/muggle-status/SKILL.md +1 -1
  125. package/plugin/skills/muggle-test/SKILL.md +30 -48
  126. package/plugin/skills/muggle-test-feature-local/SKILL.md +20 -44
  127. package/plugin/skills/muggle-test-prepare/SKILL.md +5 -1
  128. package/plugin/skills/muggle-test-prepare/steps/check-running.md +7 -5
  129. package/plugin/skills/muggle-test-prepare/steps/identify-services.md +2 -0
  130. package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +30 -0
  131. package/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +44 -0
  132. package/dist/plugin/commands/mrelease.md +0 -7
  133. package/dist/plugin/skills/mrelease/SKILL.md +0 -8
  134. package/dist/plugin/skills/muggle-works-npm-release/SKILL.md +0 -200
  135. package/plugin/commands/mrelease.md +0 -7
  136. package/plugin/skills/mrelease/SKILL.md +0 -8
  137. package/plugin/skills/muggle-works-npm-release/SKILL.md +0 -200
@@ -58,7 +58,7 @@ For a `local-e2e` block, use `localUrl`, `projectId`, and the working-tree path
58
58
 
59
59
  Before launching the local runner:
60
60
 
61
- 1. **Dev-server + backend readiness** — per [`../_shared/dev-server-readiness.md`](../_shared/dev-server-readiness.md) (port + compile log + backend health). Halt on any failure.
61
+ 1. **Dev-server + backend readiness** — invoke [`muggle-test-prepare`](../muggle-test-prepare/SKILL.md), the readiness/service-start owner (idempotent fast-exit when healthy; probes via `dev-server-readiness.md`). Halt on failure.
62
62
  2. **Auth** — `muggle-remote-auth-status` must be `authenticated`; else escalate.
63
63
  3. **Identity tenant/domain match** — if test credentials were marked `existing`, confirm the repo's configured identity tenant/domain matches the recorded tenant/domain. Mismatch → halt.
64
64
 
@@ -96,71 +96,11 @@ Based on the changed files and the requirements goal, determine which test cases
96
96
  - Test cases that cover areas potentially affected by the changes
97
97
  - When in doubt, include the test case (better to over-test than miss a regression)
98
98
 
99
- ### Step 4: Execute Tests Locally
99
+ ### Step 4: Run the dev loop, publish, gather screenshots
100
100
 
101
- For each relevant test case:
101
+ For each relevant test case, run the shared loop in [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md): `muggle-remote-test-script-list` by `testCaseId` to pick [replay vs regen](../_shared/dev-loop/run.md), [execute with `timeoutMs`](../_shared/dev-loop/timeouts.md), [fetch the result](../_shared/dev-loop/failures.md) and [interpret failures](../_shared/dev-loop/failures.md), [publish](../_shared/dev-loop/publish.md), and gather [per-step screenshots](../_shared/dev-loop/publish.md).
102
102
 
103
- 1. Call `muggle-remote-test-script-list` filtered by `testCaseId` to check for an existing script.
104
-
105
- 2. **If a script exists** (replay path):
106
- - `muggle-remote-test-script-get` with `testScriptId` → note `actionScriptId`
107
- - `muggle-remote-action-script-get` with that id → full `actionScript`
108
- - **Use the API response as-is.** Do not edit, shorten, or rebuild `actionScript`; replay needs full `label` paths for element lookup.
109
- - `muggle-local-execute-replay` with:
110
- - `testScript`: the full script object
111
- - `actionScript`: the full action script object (from `muggle-remote-action-script-get`)
112
- - `localUrl`: the resolved local URL
113
- - `timeoutMs`: `600000` (10 min) or `900000` (15 min) for complex flows
114
-
115
- 3. **If no script exists** (generation path):
116
- - `muggle-remote-test-case-get` with `testCaseId` to fetch the full test case object.
117
- - `muggle-local-execute-test-generation` with:
118
- - `testCase`: the full test case object
119
- - `localUrl`: the resolved local URL
120
- - `timeoutMs`: `600000` (10 min) or `900000` (15 min) for complex flows
121
-
122
- 4. When execution completes, call `muggle-local-run-result-get` with the `runId` returned by the execute call.
123
-
124
- 5. **Retain per test case:** `testCaseId`, `testScriptId` (if present), `runId`, `status` (passed/failed), `artifactsDir`.
125
-
126
- ### Local Execution Timeout (`timeoutMs`)
127
-
128
- The MCP client often uses a **default wait of 300000 ms (5 minutes)**. **Exploratory script generation** (identity login, multi-step app flows, many LLM iterations) routinely **runs longer than 5 minutes** while Electron is still healthy.
129
-
130
- - **Always pass `timeoutMs`** — `600000` (10 min) or `900000` (15 min) — unless the test case is known to be simple.
131
- - If the tool reports **`Electron execution timed out after 300000ms`** but Electron logs show the run still progressing (steps, screenshots, LLM calls), treat it as **orchestration timeout**, not an Electron app defect: **increase `timeoutMs` and retry**.
132
-
133
- ### Interpreting Failures
134
-
135
- - **`Electron execution timed out after 300000ms`:** Orchestration wait too short — see `timeoutMs` above.
136
- - **Exit code 26** (and messages like **LLM failed to generate / replay action script**): Often corresponds to a completed exploration whose **outcome was goal not achievable** (`goal_not_achievable`, summary with `halt`). Use `muggle-local-run-result-get` and read the **summary / structured summary**; do not assume an Electron crash.
137
- - **Fix for precondition failures:** Choose a project/account that already has the needed state, or narrow the test goal so generation does not try to create resources from scratch unless intentional.
138
-
139
- ### Step 5: Publish Test Scripts
140
-
141
- After each test execution completes (whether pass or fail):
142
-
143
- 1. Call `muggle-local-publish-test-script` with:
144
- - `runId`: the run ID from execution
145
- - `cloudTestCaseId`: the test case ID
146
-
147
- 2. **Retain from publish response:**
148
- - `testScriptId`: the cloud test script ID
149
- - `viewUrl`: the URL to view the run on muggle-ai.com
150
-
151
- This ensures all screenshots are uploaded to the cloud and accessible via URLs for PR comments.
152
-
153
- ### Step 6: Fetch Screenshot URLs
154
-
155
- For each published test script:
156
-
157
- 1. Call `muggle-remote-test-script-get` with the `testScriptId` from publish.
158
-
159
- 2. Extract from the response:
160
- - `steps[].operation.screenshotUrl`: cloud URL for each step's screenshot
161
- - `steps[].operation.action`: the action description for each step
162
-
163
- 3. **Retain per test case:** array of `{ stepIndex, action, screenshotUrl }`.
103
+ Inputs to the loop: `mode` from the script-exists check, `localUrl`/project from Step 1.7, `cwd` = the working tree recorded in `state.md`.
164
104
 
165
105
  ### Step 7: Collect Results
166
106
 
@@ -216,8 +156,7 @@ For each test case:
216
156
  ## Non-negotiables
217
157
 
218
158
  - No silent auth skip; always verify with `muggle-remote-auth-status` first.
219
- - Replay: never hand-build or simplify `actionScript` — only use full response from `muggle-remote-action-script-get`.
220
- - Always pass `timeoutMs` for execution calls; do not rely on default 5-minute timeout.
159
+ - Replay/timeout/result discipline per [`../_shared/dev-loop/run.md`](../_shared/dev-loop/run.md) — never hand-build `actionScript`, always pass `timeoutMs`, read structured run-result fields.
221
160
  - No hiding failures: surface errors, exit codes, and artifact paths.
222
161
  - In `local-e2e` mode, every relevant test case must be executed — generate a new script if none exists (no skips).
223
162
  - Always publish after execution to ensure screenshots are cloud-accessible for PR comments.
@@ -0,0 +1,60 @@
1
+ # Fix-CI (watcher-dispatched)
2
+
3
+ Resolve red CI on a PR's head — lint/format, typecheck, and failing unit tests — verifying green before re-push. A dumb-pipe dispatch like address-reviews: the executor receives a PR URL, slug, and the failing check names, and fixes them — it owns the fix, not the decision to dispatch.
4
+
5
+ ## Turn preamble
6
+
7
+ ```
8
+ **/muggle-do fix-ci** — fixing <count> red check(s) on <owner>/<repo>#<n>.
9
+ ```
10
+
11
+ ## Input
12
+
13
+ `$ARGUMENTS` carries a `github.com/.../pull/<n>` URL, `slug=<slug>`, and the failing check names (no review ids). Parse all three.
14
+
15
+ ## Inputs from disk
16
+
17
+ From `~/.muggle-ai/muggle-do/sessions/<slug>/`: `prs.json` (PR + local checkout / branch), `last_seen.json` (`ci_fix_attempts`, `ci_escalated_shas`, `pushed_shas`), `state.md` (worktree path, validation strategy).
18
+
19
+ ## Procedure
20
+
21
+ ### Step 1 — Re-attach
22
+
23
+ Check out the PR branch in the session's working tree (per `state.md`). Capture `red_sha = prs.json[0].head_sha`.
24
+
25
+ ### Step 2 — Map each failing check to a local command
26
+
27
+ Per [`../_shared/ci-check-to-command.md`](../_shared/ci-check-to-command.md). Fix the in-scope checks in the working tree; record out-of-scope checks for escalation (Step 6).
28
+
29
+ ### Step 3 — Verify before push
30
+
31
+ - Build (typecheck + lint on the changed surface) + unit suite must pass.
32
+ - Run E2E (per [`../muggle-preferences/preference-gates/autoE2ETest.md`](../muggle-preferences/preference-gates/autoE2ETest.md)) only if the fix touched app logic; lint/format-only fixes skip E2E.
33
+
34
+ A fix that can't be made green locally is not pushed → Step 6.
35
+
36
+ ### Step 4 — Commit + push
37
+
38
+ Commit per the `fix(ci): <check> — <what>` convention ([`../_shared/pr-followup-helpers/reply-routing.md`](../_shared/pr-followup-helpers/reply-routing.md)). Push. Append the new SHA to `last_seen.pushed_shas`. **No PR replies** — the fix commit is the response.
39
+
40
+ ### Step 5 — Update state + respawn
41
+
42
+ - Increment `last_seen.ci_fix_attempts[red_sha]`.
43
+ - Respawn the watcher: `/loop 1m /muggle:muggle-pr-followup <slug> <n>`. CI on the new SHA is the verify loop — a still-red SHA returns as a fresh dispatch, bounded by the per-SHA fix budget (Step 6).
44
+
45
+ ### Step 6 — Escalate (budget spent or out of scope)
46
+
47
+ When the failing checks are all out of scope, or `ci_fix_attempts[red_sha]` has reached 3 with CI still red:
48
+
49
+ 1. Add `red_sha` to `last_seen.ci_escalated_shas` so the SHA is not re-fixed.
50
+ 2. Emit one terminal message naming the unresolved checks.
51
+ 3. Emit the cycle event with `outcome: "ci-escalated"` (Step 7). Do not loop further on this SHA.
52
+
53
+ ### Step 7 — Telemetry
54
+
55
+ Emit one `muggle-do:cycle` event ([`../_shared/telemetry-events/muggle-do-cycle.md`](../_shared/telemetry-events/muggle-do-cycle.md)): `outcome: "ci-fixed"` when a fix pushed, `"ci-escalated"` when escalated — with `ci_checks_in` / `ci_checks_fixed` / `ci_checks_escalated`.
56
+
57
+ ## Guardrails
58
+
59
+ - Max 3 fix attempts per SHA; out-of-scope checks escalate immediately rather than churn.
60
+ - No PR replies; the fix commit is the response.
@@ -0,0 +1,12 @@
1
+ # Input routing
2
+
3
+ How `/muggle-do` resolves `$ARGUMENTS` to a mode. Modes 1–3 are programmatic — dispatched by the watcher — so never ask on those. Inspect in order:
4
+
5
+ 1. **Address-reviews** — a `github.com/.../pull/<n>` URL **and** one or more review ids (integers ≥ 100000000) → [`address-reviews.md`](address-reviews.md).
6
+ 2. **Fix-CI** — a `github.com/.../pull/<n>` URL **and** a `fix ci` / `fix-ci` directive with failing check names (no review ids) → [`fix-ci.md`](fix-ci.md).
7
+ 3. **Post-merge cleanup** — a `cleanup` token and `slug=<slug>` (no PR URL, no review ids) → [`cleanup.md`](cleanup.md).
8
+ 4. **Empty / `help` / `menu` / `?`** → menu + session selector.
9
+ 5. **Task automation** (perform an action on a website) → `muggle:muggle-browser-task`.
10
+ 6. **Otherwise** → forward pipeline at Stage 1.
11
+
12
+ When in doubt between #5 and #6, ask one question.
@@ -40,13 +40,13 @@ Forward pipeline's Stage 7. Invoked by `/muggle-do` after stages 1–6 of a fres
40
40
 
41
41
  After every repo is processed, build the watcher manifest and dispatch one watcher loop per opened PR. The dispatches are the LAST action this stage takes.
42
42
 
43
- Write `.muggle-do/sessions/<slug>/prs.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#prsjson):
43
+ Write `~/.muggle-ai/muggle-do/sessions/<slug>/prs.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#prsjson):
44
44
 
45
45
  ```json
46
46
  [{ "repo": "owner/repo", "number": 142, "url": "...", "head_sha": "...", "state": "open" }]
47
47
  ```
48
48
 
49
- Seed `.muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty cursor shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `reviewId: 0`.
49
+ Seed `~/.muggle-ai/muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty cursor shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `reviewId: 0`.
50
50
 
51
51
  **Do not** seed `cycle.json` or `requirements.md`. The watcher is a dumb pipe; `/muggle-do` reads reviews off GitHub.
52
52
 
@@ -71,7 +71,7 @@ If `prs.json` is empty, **do not dispatch** — record the reason in `result.md`
71
71
 
72
72
  ## Post-merge cleanup
73
73
 
74
- Gated by `autoCleanup`. Fires in a follow-up turn after merge — never from this stage. See [`../../_shared/post-merge-cleanup.md`](../../_shared/post-merge-cleanup.md).
74
+ Gated by `autoCleanup`. Triggered when the watcher's terminal tick observes the merge and dispatches `/muggle-do`'s cleanup directive ([`../cleanup.md`](../cleanup.md)) — never from this stage. See [`../../_shared/post-merge-cleanup.md`](../../_shared/post-merge-cleanup.md).
75
75
 
76
76
  Append one short reminder tied to the gate value:
77
77
 
@@ -13,7 +13,7 @@ Does **not** create a PR, seed session state, or dispatch a watcher (`/muggle-do
13
13
  ## Inputs
14
14
 
15
15
  - Per-repo: path, branch (head ref name).
16
- - The existing PR URL + number from `.muggle-do/sessions/<slug>/prs.json`.
16
+ - The existing PR URL + number from `~/.muggle-ai/muggle-do/sessions/<slug>/prs.json`.
17
17
  - **Optional** E2E acceptance report from stage 6. Produced by [`../e2e-acceptance.md`](../e2e-acceptance.md); schema in [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md).
18
18
 
19
19
  ## Procedure
@@ -26,8 +26,8 @@ Before asking anything, gather every fact you can resolve without the user:
26
26
 
27
27
  1. **Candidate repo(s).** Match keywords in the task description against configured repo names. If one repo is an obvious match, propose it as the default; if two or three are plausible, list them.
28
28
  2. **Current branch and default branch** for each candidate repo. Run `git -C <repo> symbolic-ref refs/remotes/origin/HEAD --short` and `git -C <repo> branch --show-current`. If the current branch is the default, the pre-flight must collect a new branch name.
29
- 3. **Running dev server.** Detect listening ports and reconcile env-file URL/port using [`../_shared/dev-server-readiness.md`](../_shared/dev-server-readiness.md).
30
- 4. **Running backend.** Probe backend health per [`../_shared/dev-server-readiness.md`](../_shared/dev-server-readiness.md) ("Backend health"). Note up/down.
29
+ 3. **Local environment readiness.** Invoke [`muggle-test-prepare`](../muggle-test-prepare/SKILL.md) — the owner of dev-server/backend detection and service start (idempotent; it probes via `dev-server-readiness.md` internally). Use what it reports as the dev-server/URL pre-flight signal.
30
+ 4. **Backend health.** Covered by the same `muggle-test-prepare` invocation above (it probes backend health); note up/down.
31
31
  5. **Muggle Test MCP auth.** Call `muggle-remote-auth-status`. If expired, you will ask to re-auth in the questionnaire.
32
32
  6. **Candidate Muggle Test projects.** Call `muggle-remote-project-list` and rank by semantic match against the task description and the repo's dev URL.
33
33
  7. **Existing test-user secrets.** For each candidate Muggle Test project, call `muggle-remote-secret-list` and note whether `managed_profile_email` / `managed_profile_password` exist.
@@ -55,7 +55,7 @@ Present **one `AskUserQuestion`** (or the platform's structured-selection equiva
55
55
  8. **Test-user credentials** — only if validation is Local E2E AND the Auth0 tenant in the repo differs from the tenant the managed secrets were created under. Options: "Reuse existing secrets (may fail if tenant mismatch — will surface failure)" / "Create new secrets for this tenant (provide email + password)" / "Switch to staging replay".
56
56
  9. **PR target branch** — default: the repo's default branch. "Use default" / "Target a different branch".
57
57
  10. **Re-auth Muggle Test MCP?** — only if auth was missing/expired. "Log in now" / "Abort".
58
- 11. **Worktree for this change?** — gate: [`autoUseWorktree`](../muggle-preferences/preference-gates/autoUseWorktree.md). Options: create a sibling worktree, or work in the current checkout.
58
+ 11. **Worktree for this change?** — gate: [`autoUseWorktree`](../muggle-preferences/preference-gates/autoUseWorktree.md). Options: create a dedicated worktree (per [`../_shared/use-worktrees.md`](../_shared/use-worktrees.md)), or work in the current checkout.
59
59
  12. **Rebase onto `origin/<default>` first?** — gate: [`autoRebase`](../muggle-preferences/preference-gates/autoRebase.md), only if `behind > 0`. Options: rebase before stage 6, or run as-is.
60
60
  13. **Run E2E at the end of every cycle?** — gate: [`autoE2ETest`](../muggle-preferences/preference-gates/autoE2ETest.md), only if step 10's silent detection resolved to `ask`. Options: always run stage 6, or ask each cycle.
61
61
 
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: mbt
3
+ description: Explicit short alias for the `muggle-browser-task` skill. ONLY invoke when the user explicitly types `mbt` or `/mbt` — never auto-trigger from any other phrasing.
4
+ ---
5
+
6
+ # mbt — alias for muggle-browser-task
7
+
8
+ Invoke the `muggle-browser-task` skill via the Skill tool. Forward any user-provided arguments unchanged.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: mdo
3
- description: Explicit short alias for the `muggle-do-task` skill. ONLY invoke when the user explicitly types `mdo` or `/mdo` — never auto-trigger from any other phrasing.
3
+ description: Explicit short alias for the `muggle-do` skill. ONLY invoke when the user explicitly types `mdo` or `/mdo` — never auto-trigger from any other phrasing.
4
4
  ---
5
5
 
6
- # mdo — alias for muggle-do-task
6
+ # mdo — alias for muggle-do
7
7
 
8
- Invoke the `muggle-do-task` skill via the Skill tool. Forward any user-provided arguments unchanged.
8
+ Invoke the `muggle-do` skill via the Skill tool. Forward any user-provided arguments unchanged.
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: mprfollowup
3
+ description: Explicit short alias for the `muggle-pr-followup` skill. ONLY invoke when the user explicitly types `mprfollowup` or `/mprfollowup` — never auto-trigger from any other phrasing.
4
+ ---
5
+
6
+ # mprfollowup — alias for muggle-pr-followup
7
+
8
+ Invoke the `muggle-pr-followup` skill via the Skill tool. Forward any user-provided arguments unchanged.
@@ -37,6 +37,7 @@ If the user intent clearly matches one command, route directly — no menu neede
37
37
  - test localhost/validate single feature/test a feature → `muggle-test-feature-local`
38
38
  - build/implement from request/end-to-end → `muggle-do`
39
39
  - post results to PR/attach walkthrough/visual evidence on PR → `muggle-pr-visual-walkthrough`
40
+ - watch my PR for reviews/follow up on PR reviews/babysit PR review thread → `muggle-pr-followup`
40
41
  - give feedback on a run/the test was wrong/step N didn't work/show my feedback/delete feedback → `muggle-feedback`
41
42
 
42
43
  If intent is ambiguous, use `AskUserQuestion` with the most likely options rather than asking the user to type a clarification.
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: muggle-do-task
2
+ name: muggle-browser-task
3
3
  description: Run a browser automation task on a website using natural language. Finds or creates the Muggle Test project, use case, test case, and script, then executes locally via the electron app. Use when the user wants to perform an action on a website (post, fill a form, click through a flow) rather than implement a code change.
4
4
  ---
5
5
 
@@ -25,32 +25,51 @@ Runs an autonomous dev cycle from requirements to PR. **Fire and review:** user
25
25
 
26
26
  Stage 7 dispatches one watcher per opened PR as its last action.
27
27
 
28
+ ## Execution protocol (non-negotiable)
29
+
30
+ The pipeline table lists **pointers, not summaries**. Open each stage's file and execute from it — running a stage off its one-line row here is how tests, E2E, and session state get silently skipped. If you have not read a stage's file this run, you have not run that stage.
31
+
32
+ **Bootstrap before any code, in order:**
33
+ 1. Emit telemetry — [`../_shared/telemetry-emit.md`](../_shared/telemetry-emit.md), `skillName: "muggle-do"`.
34
+ 2. Create `~/.muggle-ai/muggle-do/sessions/<slug>/` with `state.md` + `iterations/001.md` (pre-flight owns this; do it even when running unattended).
35
+ 3. `TodoWrite` one item per stage 1–8 — these stages are the checklist; never swap in your own decomposition.
36
+
37
+ **Per stage:** read the file → execute it → append a marker to `iterations/<NNN>.md` citing the evidence that file requires (jest exit code, E2E verdict + `runId`, screenshot path). A stage is done only when its evidence is written, never on recollection.
38
+
39
+ ### "Autonomous" / "without my intervention" collapses exactly one thing
40
+ Best-effort the Stage-1 questionnaire and don't ask. It does **not** license skipping telemetry, session artifacts, requirements, unit tests, E2E (`autoE2ETest` defaults to `always`), browser verification, the gate below, or the watcher hand-off. Run the whole pipeline silently — never a shortcut.
41
+
42
+ ### Definition of Done — gate before Stage 7
43
+ Do not create or update a PR until each line holds, or is waived by a one-line reason written into `state.md` (silence is not a waiver):
44
+ - `requirements.md` written (forward runs)
45
+ - Build clean — typecheck + lint on changed files
46
+ - New/changed logic carries unit tests (authored in Stage 3; Stage 5 only runs the suite)
47
+ - Unit suite run, PASS recorded
48
+ - E2E verdict recorded with `runId` per `autoE2ETest` — or `[E2E FAILING]` / `SKIPPED` + reason
49
+ - UI changes verified in a real browser with evidence (screenshot path or muggle `runId`); `curl` + `grep` is not verification
50
+
51
+ Opening a PR with an unchecked, unwaived line is a cycle failure.
52
+
28
53
  ## Address-reviews flow
29
54
 
30
55
  When invoked with the directive (PR URL + slug + review ids), routes to [`../do/address-reviews.md`](../do/address-reviews.md). Shares stages 3–6 + walkthrough with the forward pipeline; skips pre-flight, requirements, and PR creation. See the orchestrator for the cycle's exact step order, classification rules, and respawn logic.
31
56
 
32
57
  ## Input routing
33
58
 
34
- Inspect `$ARGUMENTS` in this order:
35
-
36
- 1. **Address-reviews** — input contains a `github.com/.../pull/<n>` URL **and** one or more integers ≥ 100000000 (review id shape) → [`../do/address-reviews.md`](../do/address-reviews.md). Programmatic; never ask.
37
- 2. **Empty / `help` / `menu` / `?`** → menu + session selector.
38
- 3. **Task automation** (perform an action on a website) → `muggle:muggle-do-task`.
39
- 4. **Otherwise** → forward pipeline at Stage 1.
40
-
41
- When in doubt between #3 and #4, ask one question.
59
+ `/muggle-do` serves one interactive mode (the forward pipeline, from a fresh task) and three programmatic modes the watcher dispatches (address-reviews, fix-ci, post-merge cleanup). Resolve `$ARGUMENTS` to a mode per [`../do/input-routing.md`](../do/input-routing.md) before doing anything else.
42
60
 
43
61
  ## Preferences
44
62
 
45
63
  | Preference | Gate |
46
64
  | :--------- | :--- |
47
65
  | `autoE2ETest` | Stage 6 — run E2E every cycle (default `always`), or fold into pre-flight |
66
+ | `autoResolveConflicts` | On rebase conflict — resolve autonomously behind a verify-or-rollback gate (opt-in), or abort + escalate (default `never`) |
48
67
 
49
- `autoUseWorktree`, `autoRebase`, `autoCreatePR`, `autoCleanup` fire from per-stage files.
68
+ `autoUseWorktree`, `autoRebase`, `autoResolveConflicts`, `autoCreatePR`, `autoCleanup` fire from per-stage files.
50
69
 
51
70
  ## Session model
52
71
 
53
- `.muggle-do/sessions/<slug>/`. Schemas: [`../muggle-pr-followup/state-schemas.md`](../muggle-pr-followup/state-schemas.md).
72
+ `~/.muggle-ai/muggle-do/sessions/<slug>/`. Schemas: [`../muggle-pr-followup/state-schemas.md`](../muggle-pr-followup/state-schemas.md).
54
73
 
55
74
  | File | Owner |
56
75
  | :--- | :---- |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: muggle-feedback
3
- description: Capture feedback on a generated Muggle Test action script — either step-level or whole-script — and submit it so the system can analyze it and regenerate affected scripts. Use when the user has just run a Muggle Test (local or remote) and wants to flag what went wrong, when they paste a Muggle dashboard URL with a test script or run, or when they want to view or delete previously submitted feedback. Triggers on: '/muggle-feedback', 'give feedback on this run', 'the test was wrong', 'step N didn't work', 'the script clicked the wrong button', 'flag this run', 'the summary is wrong', 'show my feedback', 'list feedback', 'delete that feedback'. Skill auto-detects the run context from a recent local run, a remote run, or a Muggle dashboard URL in the prompt.
3
+ description: Use when the user wants to flag that a generated Muggle Test action script — or one specific step in it — did the wrong thing, and have it captured so Muggle can analyze and regenerate affected scripts. Covers any report that a script or step is wrong, broken, or misbehaving (clicked the wrong element, bad summary, "step N didn't work", "broken at the submit step"), whether the user just ran a test locally or remotely or pastes a Muggle dashboard run/script URL and points at what failed. Also use to view, list, or delete previously submitted feedback. Triggers on '/muggle-feedback', 'give feedback on this run', 'the test was wrong', 'flag this run', 'show/list/delete my feedback'. Auto-detects run context from a recent local run, a remote run, or a dashboard URL in the prompt.
4
4
  ---
5
5
 
6
6
  # Muggle Test Feedback
@@ -1,6 +1,6 @@
1
1
  # muggle-pr-followup — folder TOC
2
2
 
3
- This folder holds the watcher loop for PR review follow-ups. The watcher is a **dumb pipe**: it polls for new submitted reviews and dispatches `/muggle-do` when there are any. Cycle execution, classification, replies, and escalation all live in `/muggle-do`'s address-reviews mode — see [stage-8 design](../../../../muggle-ai-brain/architecture/2026-05-08-muggle-do-pr-comment-loop-design.md) for the architectural rationale.
3
+ This folder holds the watcher loop for PR review follow-ups. The watcher is a **dumb pipe**: it polls for new submitted reviews and CI checks and dispatches `/muggle-do` when there's review feedback or fixable red CI. Cycle execution, classification, replies, and escalation all live in `/muggle-do`'s address-reviews mode — see [stage-8 design](../../../../muggle-ai-brain/architecture/2026-05-08-muggle-do-pr-comment-loop-design.md) for the architectural rationale.
4
4
 
5
5
  ## Files in this folder
6
6
 
@@ -8,6 +8,8 @@ This folder holds the watcher loop for PR review follow-ups. The watcher is a **
8
8
  - [`auto-track.md`](auto-track.md) — the no-args procedure: discovers PRs pushed this session (any repo) and seeds one poll-only watcher each. Seeds no E2E context — the watcher only watches.
9
9
  - [`bootstrap.md`](bootstrap.md) — the bootstrap procedure (asks once for the E2E validation context, seeds state, dispatches the first watcher).
10
10
  - [`contract.md`](contract.md) — the watcher per-tick procedure (poll → dispatch → exit).
11
+ - [`finalize.md`](finalize.md) — shared termination sequence for a terminal PR (mark terminal, `result.md`, log/telemetry, unschedule cron, post-merge cleanup handoff). Called by `contract.md` and `reconcile.md`.
12
+ - [`reconcile.md`](reconcile.md) — sweep that finalizes slots whose PR went terminal while polling lapsed; runs at the top of auto-track and on demand.
11
13
  - [`state-schemas.md`](state-schemas.md) — canonical JSON shapes of session state files.
12
14
  - [`output-templates.md`](output-templates.md) — TOC of message templates; per-group files in `output-templates/`.
13
15
 
@@ -21,7 +23,4 @@ Shared with other skills, under `../_shared/`:
21
23
  - [`telemetry-events.md`](../_shared/telemetry-events.md) — TOC of canonical event shapes; per-event files in `_shared/telemetry-events/`.
22
24
  - [`github-cli-recipes.md`](../_shared/github-cli-recipes.md) — TOC of reusable `gh` / `git` snippets; per-recipe files in `_shared/github-cli-recipes/`.
23
25
 
24
- Caller-specific, under `../do/`:
25
-
26
- - [`open-prs.md`](../do/open-prs.md) — TOC for the create-or-update PR stage; per-mode files in `do/open-prs/`.
27
- - [`resolve-reminder.md`](../do/resolve-reminder.md) — `/muggle-do`'s per-round stage that nudges the reviewer to resolve addressed-but-still-open threads.
26
+ Callers (e.g. `/muggle-do`) reference this folder, not the reverse — see [`../CLAUDE.md`](../CLAUDE.md) for the one-way-dependency rule.
@@ -1,14 +1,13 @@
1
1
  ---
2
2
  name: muggle-pr-followup
3
- description: Watcher loop for PR review follow-ups. Polls one PR for new submitted reviews and dispatches `/muggle-do` (address-reviews mode) when there are any. A dumb pipe — no classification, no cycle execution, no replies. Run it with no args to auto-track every PR you pushed this session (poll-only watchers, any repo). Use `/loop 1m /muggle:muggle-pr-followup <slug> <pr-number>` for ongoing polling, or `/muggle:muggle-pr-followup <pr-url>` to bootstrap a fresh watcher on an existing PR (asks once for the E2E validation context, then runs unattended).
4
- disable-model-invocation: true
3
+ description: Use this skill when the user wants a pull request's incoming review feedback handled for them — it watches one PR's review thread and, each time a reviewer submits new comments, dispatches the work to address them. Engage on PR-review-follow-up intent: "watch my PR and address review comments as they come in", "keep an eye on PR #123 and respond to reviewer feedback", "follow up on my PR's reviews", "babysit my PR's review thread", "auto-handle reviews on the PR I just opened", "I'm stepping away — handle my PR's reviews while I'm gone". Run with no args to track every PR you pushed this session (any repo); pass a PR URL to start watching a specific one. This is PR-review-specific automation: when the recurring thing the user wants handled is a PR's review comments, use this — not the generic `loop` skill. It only watches and dispatches; the actual edits and replies are `muggle-do`. Not for posting test results to a PR (use muggle-pr-visual-walkthrough).
5
4
  ---
6
5
 
7
6
  # muggle-pr-followup
8
7
 
9
8
  > Telemetry first step: see [`../_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-pr-followup"`.
10
9
 
11
- A watcher that babysits one open PR's review thread. Polls for new submitted reviews; when any land, hands them off to `/muggle-do` and exits. `/muggle-do` is the executor — it classifies the reviews, runs the work, pushes, replies per comment, and respawns the watcher.
10
+ A watcher that babysits one open PR's review thread and CI. Polls for new submitted reviews and check-run state; when review feedback lands or CI goes red, hands the work to `/muggle-do` and exits. On merge, it hands off post-merge cleanup to `/muggle-do` the same way. `/muggle-do` is the executor — it classifies the reviews or fixes the failing checks, pushes, replies per comment, and respawns the watcher.
12
11
 
13
12
  **The watcher is a dumb pipe.** It does not classify reviews, iterate cycles, post replies, or escalate. All of that lives in `/muggle-do`. See [stage-8 design](../../../../muggle-ai-brain/architecture/2026-05-08-muggle-do-pr-comment-loop-design.md) for the rationale.
14
13
 
@@ -27,6 +26,9 @@ The skill recognizes its mode by inspecting `$ARGUMENTS` and falling back to on-
27
26
  | `<pr-number>` alone | zero or multiple matches | **error:** ambiguous; list candidates and exit |
28
27
  | empty | — | **auto-track** → [`auto-track.md`](auto-track.md) |
29
28
  | `help` / `?` | — | **help:** list active loops per [`output-templates/help.md`](output-templates/help.md) |
29
+ | `reconcile` / `sweep` (optional `<slug>`) | — | **reconcile** → [`reconcile.md`](reconcile.md) |
30
+
31
+ Auto-track runs **reconcile** first, so a no-arg invocation also finalizes any slot whose PR merged or closed while its watcher was down (expired cron, ended session). Reconcile never re-arms a watcher.
30
32
 
31
33
  Bootstrap accepts three optional trailing flags:
32
34
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  The procedure for the **auto-track mode** of `muggle-pr-followup` — invoked when the skill is dispatched with **no arguments**. Routing is in [`SKILL.md`](SKILL.md#routing).
4
4
 
5
- Auto-track discovers the PRs you pushed or opened during this Claude Code session — across **any repo** — and starts one **poll-only watcher** per PR. The watcher only watches: it seeds nothing about E2E. Running and posting E2E is `/muggle-do`'s job; a watcher with no validation context yields a `SKIPPED` E2E verdict when `/muggle-do` runs — see [`../do/e2e-acceptance.md`](../do/e2e-acceptance.md) Step 0.
5
+ Auto-track discovers the PRs you pushed or opened during this Claude Code session — across **any repo** — and starts one **poll-only watcher** per PR. The watcher only watches: it seeds nothing about E2E. Running and posting E2E is `/muggle-do`'s job; a watcher with no validation context yields a `SKIPPED` E2E verdict when `/muggle-do` runs.
6
6
 
7
7
  ## Turn preamble
8
8
 
@@ -16,6 +16,10 @@ Auto-track discovers the PRs you pushed or opened during this Claude Code sessio
16
16
 
17
17
  ## Procedure
18
18
 
19
+ ### Step 0 — Reconcile existing slots
20
+
21
+ Run [`reconcile.md`](reconcile.md) first. A no-arg invocation is the natural moment to finalize any slot whose PR merged or closed while its watcher was down — an expired `/loop` cron or an ended session leaves termination un-run (see reconcile's rationale). Then continue discovering new PRs below.
22
+
19
23
  ### Step 1 — Discover candidate PRs from session context
20
24
 
21
25
  A PR counts as **pushed this session** if, earlier in this conversation, you:
@@ -37,11 +37,13 @@ Per [`../_shared/github-cli-recipes/verify-working-tree.md`](../_shared/github-c
37
37
 
38
38
  ### Step 4 — Resolve the slug
39
39
 
40
- Default: `<repo>-pr<n>` (e.g. `muggle-ai-works-pr154`). Override: `--slug=<name>`. Session dir is `.muggle-do/sessions/<slug>/` relative to the caller's working tree.
40
+ Default: `<repo>-pr<n>` (e.g. `muggle-ai-works-pr154`). Override: `--slug=<name>`. Session dir is `~/.muggle-ai/muggle-do/sessions/<slug>/` (under the user's home, shared across repos; the slug's repo-pr<n> prefix keeps it unique).
41
41
 
42
42
  ### Step 5 — Idempotency check
43
43
 
44
- If `.muggle-do/sessions/<slug>/` exists:
44
+ **Legacy-slot migration.** Pre-move sessions lived at the repo-relative `.muggle-do/sessions/<slug>/` ([`state-schemas.md`](state-schemas.md#legacy-location)). If the new home-dir slot is absent but `<working-tree>/.muggle-do/sessions/<slug>/` exists (working tree from Step 3), move it to the new location first — this carries an in-flight watcher's cursor, `escalated_review_ids`, and `pushed_shas` across the upgrade. Bootstrap is the only stage that performs this: it is the one entry point that knows the old repo-relative path (the cwd), and it is the natural re-entry point after a plugin upgrade. A slot that fails to migrate loses nothing durable — GitHub holds the reviews, so a fresh bootstrap (cursor `0`) re-processes them.
45
+
46
+ If `~/.muggle-ai/muggle-do/sessions/<slug>/` exists (including a slot just migrated above):
45
47
 
46
48
  - Without `--resume` → exit with the slot-conflict abort. Both remedies (delete + re-run, or pass `--resume`) are spelled out in the message.
47
49
  - With `--resume` → refresh `prs.json[0].head_sha` to the current `headRefOid` from Step 2; leave `last_seen.json` and the cursor untouched. If `state.md` already has a `## Pre-flight answers` block, skip to Step 8; if not (older session), run Step 6.5 to backfill it, then skip to Step 8.
@@ -61,7 +63,7 @@ Capture the fields for Step 7. Do **not** run E2E now — the first watcher tick
61
63
 
62
64
  Identify the loop user once per [`../_shared/github-cli-recipes/loop-user-identity.md`](../_shared/github-cli-recipes/loop-user-identity.md); cache in `state.md`.
63
65
 
64
- Write under `.muggle-do/sessions/<slug>/`:
66
+ Write under `~/.muggle-ai/muggle-do/sessions/<slug>/`:
65
67
 
66
68
  **`prs.json`** — see [`state-schemas.md`](state-schemas.md#prsjson). One entry, `state` = `"open"`, `head_sha` from Step 2's `headRefOid`.
67
69
 
@@ -1,6 +1,6 @@
1
1
  # Watcher Per-Tick Contract
2
2
 
3
- The procedure for the **tick mode** of `muggle-pr-followup` — one polling iteration scoped to one PR. The watcher is a dumb pipe: it polls for new submitted reviews, dispatches `/muggle-do` if there are any, and exits. It does not classify, amend requirements, post replies, run cycles, or escalate.
3
+ The procedure for the **tick mode** of `muggle-pr-followup` — one polling iteration scoped to one PR. The watcher is a dumb pipe: it polls for new submitted reviews and CI checks, dispatches `/muggle-do` if there's review feedback or fixable red CI, and exits. It does not classify, fix, amend requirements, post replies, run cycles, or escalate.
4
4
 
5
5
  Routing into this mode is documented in [`SKILL.md`](SKILL.md#routing). The architectural rationale lives in the brain doc `architecture/2026-05-08-muggle-do-pr-comment-loop-design.md`.
6
6
 
@@ -16,7 +16,7 @@ Routing into this mode is documented in [`SKILL.md`](SKILL.md#routing). The arch
16
16
 
17
17
  ## Inputs from disk
18
18
 
19
- Read these from `.muggle-do/sessions/<slug>/`:
19
+ Read these from `~/.muggle-ai/muggle-do/sessions/<slug>/`:
20
20
 
21
21
  - `prs.json` — see [`state-schemas.md`](state-schemas.md#prsjson). The watcher touches the single entry whose `number` matches the dispatched PR number.
22
22
  - `last_seen.json` — see [`state-schemas.md`](state-schemas.md#last_seenjson). Keyed by `"<owner>/<repo>#<n>"`.
@@ -33,25 +33,22 @@ Per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recip
33
33
 
34
34
  If `state` is `MERGED` or `CLOSED`:
35
35
 
36
- 1. Mark the entry terminal in `prs.json`.
37
- 2. Write `result.md` per [`state-schemas.md`](state-schemas.md#resultmd).
38
- 3. Append a terminal line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
39
- 4. Emit a `tick` event with `terminal: true` per [`../_shared/telemetry-events/pr-followup-tick.md`](../_shared/telemetry-events/pr-followup-tick.md).
40
- 5. **Cancel the cron schedule that fires this watcher.** `/loop 1m ...` from bootstrap was registered via `CronCreate`; a fixed-interval cron keeps firing regardless of whether the skill re-dispatches. Call `CronList`, find any job whose command ends with `/muggle:muggle-pr-followup <slug> <pr-number>` (exact two-arg match), and `CronDelete` it. No-op if none matches — the tick may have been invoked manually rather than via `/loop`.
41
- 6. Exit. The watcher has now unscheduled itself; no future ticks will fire for this PR.
36
+ 1. Finalize the slot per [`finalize.md`](finalize.md) — mark terminal, write `result.md`, log + telemetry, unschedule this watcher's cron.
37
+ 2. **If `MERGED`**, hand off post-merge cleanup as the last action of the turn (skip on `CLOSED` — unmerged, leave the branch and any worktree intact):
42
38
 
43
- ### Step 3 — Fetch new submitted reviews
39
+ ```
40
+ /muggle-do post-merge cleanup slug=<slug>
41
+ ```
42
+
43
+ `/muggle-do` owns the worktree/branch knowledge and honors the `autoCleanup` gate. This is a runtime dispatch, not a doc dependency on `/muggle-do` — see the one-way rule in [`../CLAUDE.md`](../CLAUDE.md).
44
+ 3. Exit. The watcher has unscheduled itself; no future ticks fire for this PR.
44
45
 
45
- Per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md). **Also exclude review ids that appear in `last_seen.escalated_review_ids`** — those have already been escalated and the watcher must not re-dispatch them.
46
46
 
47
- ### Step 4 — If zero new reviews → idle
47
+ ### Step 3 — Fetch new submitted reviews
48
48
 
49
- 1. Increment `last_seen.idle_tick_count`.
50
- 2. Append an idle line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
51
- 3. Emit a `tick` event with `idle: true`, `reviews_seen: 0`, `dispatched_review_ids: []`.
52
- 4. Exit. The next tick fires in 1 min via `/loop`.
49
+ Per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md). **Also exclude review ids that appear in `last_seen.escalated_review_ids`** — those have already been escalated and the watcher must not re-dispatch them.
53
50
 
54
- ### Step 5 — If one or more new reviews → dispatch
51
+ ### Step 4 — If one or more new reviews → dispatch (reviews preempt CI)
55
52
 
56
53
  The watcher does **not** classify. Classification, batching, replying, escalation, and cycle execution all live in `/muggle-do`. The watcher's job is to hand over the list of new review ids and exit.
57
54
 
@@ -67,7 +64,27 @@ The watcher does **not** classify. Classification, batching, replying, escalatio
67
64
  ```
68
65
  3. Append a dispatching line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md).
69
66
  4. Emit a `tick` event with `reviews_seen: <count>`, `dispatched_review_ids: [<id>, ...]`.
70
- 5. Exit. The cron schedule from bootstrap keeps firing the watcher every minute, so the next tick still arrives even though this turn dispatched `/muggle-do`. The watcher only self-unschedules in Step 2 (terminal).
67
+ 5. Exit. **Reviews preempt CI** — when reviews land, this tick dispatches address-reviews and never polls CI. The cron keeps firing; the next tick still arrives. The watcher only self-unschedules in Step 2 (terminal).
68
+
69
+ ### Step 5 — No new reviews → poll CI for the head SHA
70
+
71
+ Fetch the check-run rollup for `prs.json[0].head_sha` per [`../_shared/github-cli-recipes/pr-checks.md`](../_shared/github-cli-recipes/pr-checks.md), then:
72
+
73
+ - **Any check still pending** (`bucket == "pending"`) → idle (wait for checks to settle).
74
+ - **All checks green / skipped, or no checks** → idle (green path).
75
+ - **One or more checks red** (`bucket == "fail"`), **and** `ci_fix_attempts[head_sha] < 3`, **and** `head_sha` ∉ `ci_escalated_shas` → dispatch and exit:
76
+ 1. Reset `last_seen.idle_tick_count` to 0.
77
+ 2. Dispatch `/muggle-do` with a *fix-ci* directive carrying the PR URL, slug, and the red check names (no review ids):
78
+ ```
79
+ /muggle-do fix ci <check-1> <check-2> ... on <pr-url> slug=<slug>
80
+ ```
81
+ 3. Append a dispatching line to `followup.log`; emit a `tick` event with `checks_red: <count>`, `dispatched_ci_fix: true`.
82
+ 4. Exit. The next tick re-checks CI on the new head SHA — CI itself is the verify loop.
83
+ - **One or more red, but `ci_fix_attempts[head_sha] >= 3` or `head_sha` ∈ `ci_escalated_shas`** → idle. The fix budget is spent; `/muggle-do`'s fix-ci stage already recorded the escalation. The watcher does not re-dispatch.
84
+
85
+ ### Step 6 — Idle
86
+
87
+ Any idle branch (Steps 4–5 that did not dispatch): increment `last_seen.idle_tick_count`, append an idle line to `followup.log` per [`output-templates/watcher-log.md`](output-templates/watcher-log.md), emit a `tick` event with `idle: true`, `reviews_seen: 0`, `dispatched_review_ids: []`, `checks_red: <count or 0>`, `dispatched_ci_fix: false`. Exit. The next tick fires in 1 min via `/loop`.
71
88
 
72
89
  ## Output
73
90
 
@@ -0,0 +1,29 @@
1
+ # Finalize a Terminal PR
2
+
3
+ The shared, **pure** termination sequence for a follow-up slot whose PR is `MERGED` or `CLOSED`. Called by [`contract.md`](contract.md) Step 2 (a tick observed the transition) and [`reconcile.md`](reconcile.md) (a sweep found a slot whose polling lapsed before the transition). One slot, run once.
4
+
5
+ This step only finalizes — marks the slot terminal, writes the record, unschedules the cron. It **dispatches nothing**. Post-merge cleanup is a separate, caller-owned concern: the tick ([`contract.md`](contract.md)) hands it off; a reconcile backfill skips it.
6
+
7
+ ## Inputs
8
+
9
+ - `<slug>`, `<owner>/<repo>`, `<n>` — the slot's PR.
10
+ - `state` — `MERGED` or `CLOSED`, from a fresh [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md).
11
+ - `mergeCommit` + `mergedAt` when `MERGED`.
12
+
13
+ ## Procedure
14
+
15
+ ### Step 1 — Mark the slot terminal
16
+
17
+ Rewrite `prs.json[0].state` to `merged` / `closed` ([`state-schemas.md`](state-schemas.md#prsjson)). That state plus the `result.md` written next are the terminal marker — there is no separate flag.
18
+
19
+ ### Step 2 — Write `result.md`
20
+
21
+ Once, per [`state-schemas.md`](state-schemas.md#resultmd). Pull `cycles_completed`, `pushed_shas`, and `escalated_review_ids` from `last_seen.json`.
22
+
23
+ ### Step 3 — Log and telemetry
24
+
25
+ Append the terminal line per [`output-templates/watcher-log.md`](output-templates/watcher-log.md). Emit one `tick` event with `terminal: true` per [`../_shared/telemetry-events/pr-followup-tick.md`](../_shared/telemetry-events/pr-followup-tick.md).
26
+
27
+ ### Step 4 — Unschedule the cron
28
+
29
+ Call `CronList`, find any job whose command ends with `/muggle:muggle-pr-followup <slug> <n>` (exact two-arg match), and `CronDelete` it. No-op when none matches — a manually-run tick, or a cron that already expired. Recurring `/loop` crons auto-expire after 7 days; that lapse is the gap [`reconcile.md`](reconcile.md) exists to catch.