@yemi33/minions 0.1.2448 → 0.1.2449
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.
- package/bin/cli-api-client.js +1 -1
- package/bin/install-internal-minions.js +1382 -44
- package/bin/install-layout.js +150 -0
- package/bin/minions.js +460 -167
- package/dashboard/docs/typography.md +65 -12
- package/dashboard/js/command-center.js +58 -4
- package/dashboard/js/detail-panel.js +36 -0
- package/dashboard/js/memory-panel.js +59 -12
- package/dashboard/js/qa.js +179 -20
- package/dashboard/js/refresh.js +148 -12
- package/dashboard/js/render-dispatch.js +3 -4
- package/dashboard/js/render-inbox.js +2 -2
- package/dashboard/js/render-other.js +3 -3
- package/dashboard/js/render-pipelines.js +14 -0
- package/dashboard/js/render-plans.js +57 -9
- package/dashboard/js/render-prd.js +132 -23
- package/dashboard/js/render-prs.js +195 -166
- package/dashboard/js/render-schedules.js +63 -3
- package/dashboard/js/render-utils.js +3 -3
- package/dashboard/js/render-watches.js +19 -3
- package/dashboard/js/render-work-items.js +238 -30
- package/dashboard/js/settings.js +205 -54
- package/dashboard/js/utils.js +51 -1
- package/dashboard/pages/home.html +1 -1
- package/dashboard/pages/qa.html +1 -16
- package/dashboard/pages/work.html +40 -0
- package/dashboard/shared/cc-limits.js +79 -0
- package/dashboard/shared/pr-filters.js +21 -38
- package/dashboard/shared/project-git-summary.js +1 -1
- package/dashboard/shared/record-filters.js +169 -0
- package/dashboard/shared/watches-source.js +1 -1
- package/dashboard/shared/welcome-popup.js +1 -1
- package/dashboard/shared/wi-filters.js +302 -0
- package/dashboard/slim/body.html +1 -0
- package/dashboard/slim/js/command-send.js +26 -0
- package/dashboard/slim/js/modals-tiles.js +380 -39
- package/dashboard/slim/js/status.js +13 -21
- package/dashboard/slim/layout.html +1 -0
- package/dashboard/slim/panel-bootstrap.js +6 -2
- package/dashboard/slim/styles.css +38 -0
- package/dashboard/styles.css +159 -55
- package/dashboard-build.js +13 -2
- package/dashboard.js +956 -423
- package/docs/README.md +11 -6
- package/docs/api-errors.md +2 -2
- package/docs/architecture-review-2026-07-09.md +1 -1
- package/docs/architecture.excalidraw +2 -2
- package/docs/auto-discovery.md +18 -9
- package/docs/branch-derivation.md +4 -4
- package/docs/capture-demos.js +39 -2
- package/docs/ci-runner-canary.md +123 -0
- package/docs/claude-md-propagation.md +2 -2
- package/docs/cloud-agent-dispatch.md +204 -0
- package/docs/command-center.md +7 -7
- package/docs/completion-reports.md +43 -20
- package/docs/constants.md +10 -3
- package/docs/constellation-bridge.md +134 -6
- package/docs/constellation-style-telemetry.md +4 -4
- package/docs/contracts/capability-protocol.v1.json +165 -0
- package/docs/cooldown-merge-semantics.md +12 -12
- package/docs/copilot-cli-schema.md +7 -7
- package/docs/cross-repo-plans.md +10 -10
- package/docs/dead-code-audit-retractions.md +5 -5
- package/docs/default-branch-ci.md +173 -0
- package/docs/deprecated.json +31 -31
- package/docs/design-inbox-entries-schema.md +3 -3
- package/docs/design-language.md +1051 -0
- package/docs/design-state-storage.md +11 -11
- package/docs/diagnostics-crash-reports.md +9 -9
- package/docs/diagnostics-memory.md +5 -5
- package/docs/documentation-audit-2026-07-09.md +7 -7
- package/docs/engine-restart.md +90 -5
- package/docs/harness-mode.md +1 -1
- package/docs/internal-install.md +338 -39
- package/docs/kb-dedup-duplicate-pair-investigation.md +5 -5
- package/docs/kb-pr3223-cascade-archiving.md +1 -1
- package/docs/kb-pr696-merge-conflict-docs.md +6 -6
- package/docs/kb-sweep.md +35 -35
- package/docs/keep-processes.md +1 -1
- package/docs/live-checkout-mode.md +30 -30
- package/docs/managed-spawn.md +18 -14
- package/docs/named-agents.md +7 -7
- package/docs/plan-lifecycle.md +69 -2
- package/docs/pr-author-identity.md +114 -0
- package/docs/pr-auto-fix-dispatch.md +19 -4
- package/docs/pr-comment-followup.md +6 -6
- package/docs/pr-review-fix-loop.md +59 -10
- package/docs/process-termination.md +40 -0
- package/docs/proposals/repo-pool-for-live-checkout.md +13 -13
- package/docs/qa-runbook-lifecycle.md +367 -17
- package/docs/qa-runbooks.md +3 -3
- package/docs/rfc-completion-json.md +18 -18
- package/docs/runtime-adapters.md +26 -21
- package/docs/security.md +6 -6
- package/docs/self-improvement.md +4 -4
- package/docs/shared-lifecycle-module-map.md +473 -472
- package/docs/skills.md +52 -3
- package/docs/slim-ux/concepts.md +121 -116
- package/docs/specs/agent-configurability.md +18 -18
- package/docs/specs/agent-rename.md +18 -18
- package/docs/team-memory.md +38 -21
- package/docs/timeouts-and-liveness.md +118 -10
- package/docs/tutorials/01-install-and-connect.md +1 -1
- package/docs/watches.md +40 -39
- package/docs/workspace-manifests.md +4 -4
- package/docs/worktree-lifecycle.md +293 -14
- package/engine/README.md +46 -0
- package/engine/{ado-comment.js → ado/comment.js} +8 -8
- package/engine/{ado-git-auth.js → ado/git-auth.js} +4 -4
- package/engine/{ado.js → ado/index.js} +417 -63
- package/engine/{ado-status.js → ado/status.js} +6 -8
- package/engine/{ado-token.js → ado/token.js} +1 -1
- package/engine/{acp-transport.js → agents/acp-transport.js} +62 -22
- package/engine/{agent-worker-pool.js → agents/agent-worker-pool.js} +17 -8
- package/engine/{cc-worker-pool.js → agents/cc-worker-pool.js} +16 -6
- package/engine/{claude-md-context.js → agents/claude-md-context.js} +5 -5
- package/engine/{harness-context.js → agents/harness-context.js} +5 -5
- package/engine/{harness.js → agents/harness.js} +3 -3
- package/engine/{llm.js → agents/llm.js} +18 -14
- package/engine/{model-discovery.js → agents/model-discovery.js} +2 -2
- package/engine/{playbook.js → agents/playbook.js} +155 -22
- package/engine/{pooled-agent-process.js → agents/pooled-agent-process.js} +14 -12
- package/engine/{preflight.js → agents/preflight.js} +29 -10
- package/engine/{spawn-agent.js → agents/spawn-agent.js} +25 -14
- package/engine/{spawn-phase-watchdog.js → agents/spawn-phase-watchdog.js} +16 -7
- package/engine/{steering.js → agents/steering.js} +5 -5
- package/engine/{tools-inventory.js → agents/tools-inventory.js} +2 -2
- package/engine/{agent-api-validation.js → api/agent-api-validation.js} +2 -2
- package/engine/{api-validation.js → api/api-validation.js} +1 -1
- package/engine/api/bridge.js +787 -0
- package/engine/{cc-api-validation.js → api/cc-api-validation.js} +1 -1
- package/engine/api/companion.js +560 -0
- package/engine/{content-api-validation.js → api/content-api-validation.js} +2 -2
- package/engine/{pr-issue-validation.js → api/pr-issue-validation.js} +33 -6
- package/engine/{settings-validation.js → api/settings-validation.js} +32 -4
- package/engine/api-contracts/agent-content.js +4 -4
- package/engine/api-contracts/capability-manifest.js +236 -0
- package/engine/api-contracts/capability-protocol.js +333 -0
- package/engine/api-contracts/cc-ops.js +1 -1
- package/engine/api-contracts/config-runtime.js +5 -0
- package/engine/api-contracts/core.js +28 -1
- package/engine/api-contracts/index.js +100 -0
- package/engine/api-contracts/orchestration.js +18 -5
- package/engine/api-contracts/pull-requests.js +37 -6
- package/engine/api-contracts/qa-process.js +29 -6
- package/engine/api-contracts/work-plan-prd.js +21 -1
- package/engine/cloud/contract.js +212 -0
- package/engine/cloud/index.js +159 -0
- package/engine/{execution-model.js → core/execution-model.js} +1 -1
- package/engine/{features.js → core/features.js} +4 -4
- package/engine/{operator-identity.js → core/operator-identity.js} +1 -1
- package/engine/{queries.js → core/queries.js} +201 -36
- package/engine/{safe-expr.js → core/safe-expr.js} +1 -1
- package/engine/{shared.js → core/shared.js} +1637 -175
- package/engine/{stdio-timestamps.js → core/stdio-timestamps.js} +1 -1
- package/engine/{untrusted-fence.js → core/untrusted-fence.js} +3 -3
- package/engine/db/index.js +11 -2
- package/engine/db/migrations/002-dispatches.js +3 -3
- package/engine/db/migrations/003-work-items.js +1 -1
- package/engine/db/migrations/004-pull-requests.js +1 -1
- package/engine/db/migrations/006-metrics.js +1 -1
- package/engine/db/migrations/007-watches.js +2 -2
- package/engine/db/migrations/008-small-state.js +1 -1
- package/engine/db/migrations/009-qa.js +1 -1
- package/engine/db/migrations/010-pr-links.js +1 -1
- package/engine/db/migrations/011-remaining-state.js +1 -1
- package/engine/db/migrations/012-steering-deliveries.js +2 -2
- package/engine/db/migrations/013-backfill-broken-note-links.js +1 -1
- package/engine/db/migrations/014-pr-fix-target-prefs.js +2 -2
- package/engine/db/migrations/015-plans-prds.js +0 -0
- package/engine/db/migrations/018-sql-only-cutover.js +2 -2
- package/engine/db/migrations/021-archived-work-items.js +1 -1
- package/engine/db/migrations/022-global-cc-session.js +1 -1
- package/engine/db/migrations/023-engine-state.js +1 -1
- package/engine/db/migrations/025-malformed-work-item-phantoms.js +1 -1
- package/engine/db/migrations/027-review-learning-lifecycle.js +1 -1
- package/engine/db/migrations/029-repair-reused-versions.js +20 -0
- package/engine/db/migrations/031-pr-author-identity.js +137 -0
- package/engine/{consolidation.js → memory/consolidation.js} +6 -6
- package/engine/{kb-sweep-runner.js → memory/kb-sweep-runner.js} +2 -2
- package/engine/{kb-sweep.js → memory/kb-sweep.js} +9 -7
- package/engine/{memory-retrieval.js → memory/memory-retrieval.js} +46 -4
- package/engine/{memory-store.js → memory/memory-store.js} +3 -3
- package/engine/{promotion.js → memory/promotion.js} +3 -3
- package/engine/{review-learning-backfill.js → memory/review-learning-backfill.js} +6 -6
- package/engine/{review-learning.js → memory/review-learning.js} +10 -5
- package/engine/{diagnostics-memory.js → observability/diagnostics-memory.js} +1 -1
- package/engine/{logs-store.js → observability/logs-store.js} +5 -5
- package/engine/{metrics-store.js → observability/metrics-store.js} +4 -4
- package/engine/{check-status.js → operations/check-status.js} +3 -3
- package/engine/{cli.js → operations/cli.js} +271 -113
- package/engine/{distribution.js → operations/distribution.js} +5 -6
- package/engine/{cleanup.js → orchestration/cleanup.js} +72 -45
- package/engine/{cooldown.js → orchestration/cooldown.js} +5 -5
- package/engine/{dispatch-events.js → orchestration/dispatch-events.js} +2 -2
- package/engine/{dispatch.js → orchestration/dispatch.js} +129 -36
- package/engine/orchestration/failed-scheduled-cleanup.js +274 -0
- package/engine/{lifecycle.js → orchestration/lifecycle.js} +198 -90
- package/engine/{meeting.js → orchestration/meeting.js} +6 -16
- package/engine/{pipeline.js → orchestration/pipeline.js} +12 -12
- package/engine/{pre-dispatch-eval.js → orchestration/pre-dispatch-eval.js} +10 -9
- package/engine/{routing.js → orchestration/routing.js} +3 -3
- package/engine/{schedule-bootstrap.js → orchestration/schedule-bootstrap.js} +4 -4
- package/engine/{scheduler.js → orchestration/scheduler.js} +38 -8
- package/engine/{timeout.js → orchestration/timeout.js} +158 -109
- package/engine/{db-events.js → persistence/db-events.js} +2 -2
- package/engine/{dispatch-store.js → persistence/dispatch-store.js} +7 -7
- package/engine/{inbox-store.js → persistence/inbox-store.js} +2 -2
- package/engine/{note-link-backfill.js → persistence/note-link-backfill.js} +4 -4
- package/engine/{pr-fix-target-store.js → persistence/pr-fix-target-store.js} +8 -8
- package/engine/{pull-requests-store.js → persistence/pull-requests-store.js} +21 -7
- package/engine/{small-state-store.js → persistence/small-state-store.js} +31 -31
- package/engine/persistence/state-operations.js +350 -0
- package/engine/{steering-store.js → persistence/steering-store.js} +6 -6
- package/engine/{issues.js → planning/issues.js} +2 -2
- package/engine/{plan-prd-validation.js → planning/plan-prd-validation.js} +8 -2
- package/engine/planning/prd-result-sidecar.js +190 -0
- package/engine/{prd-store.js → planning/prd-store.js} +17 -17
- package/engine/{project-discovery.js → planning/project-discovery.js} +5 -5
- package/engine/{projects.js → planning/projects.js} +10 -10
- package/engine/{resolve-area.js → planning/resolve-area.js} +1 -1
- package/engine/{work-item-validation.js → planning/work-item-validation.js} +39 -3
- package/engine/{work-items-store.js → planning/work-items-store.js} +29 -21
- package/engine/{keep-process-sweep.js → processes/keep-process-sweep.js} +57 -17
- package/engine/{managed-spawn-launcher.js → processes/managed-spawn-launcher.js} +3 -3
- package/engine/{managed-spawn.js → processes/managed-spawn.js} +97 -46
- package/engine/{process-utils.js → processes/process-utils.js} +599 -55
- package/engine/{abandoned-pr-reconciliation.js → providers/abandoned-pr-reconciliation.js} +17 -7
- package/engine/{comment-classifier.js → providers/comment-classifier.js} +85 -17
- package/engine/{comment-format.js → providers/comment-format.js} +5 -5
- package/engine/{gh-comment.js → providers/gh-comment.js} +15 -15
- package/engine/{gh-token.js → providers/gh-token.js} +4 -4
- package/engine/{github.js → providers/github.js} +131 -54
- package/engine/{pr-action.js → providers/pr-action.js} +13 -12
- package/engine/{pr-clone-keep.js → providers/pr-clone-keep.js} +7 -7
- package/engine/{pr-devbox.js → providers/pr-devbox.js} +6 -6
- package/engine/{pr-fix-target.js → providers/pr-fix-target.js} +13 -13
- package/engine/{pr-remote-patch.js → providers/pr-remote-patch.js} +4 -4
- package/engine/{pr-resolve.js → providers/pr-resolve.js} +7 -7
- package/engine/{pr-temp-clone.js → providers/pr-temp-clone.js} +5 -5
- package/engine/{pr-track.js → providers/pr-track.js} +11 -13
- package/engine/{shared-branch-pr-reconcile.js → providers/shared-branch-pr-reconcile.js} +4 -4
- package/engine/qa/auto-prd-qa.js +313 -0
- package/engine/{qa-from-prd.js → qa/from-prd.js} +42 -12
- package/engine/qa/prd-session.js +240 -0
- package/engine/{qa-process-validation.js → qa/process-validation.js} +14 -9
- package/engine/{qa-runbooks.js → qa/runbooks.js} +1 -1
- package/engine/{qa-runs.js → qa/runs.js} +286 -15
- package/engine/{qa-sessions.js → qa/sessions.js} +595 -49
- package/engine/qa/visual-journey.js +654 -0
- package/engine/{qa-runners.js → qa-runners/index.js} +7 -7
- package/engine/qa-runners/maestro.js +3 -3
- package/engine/qa-runners/playwright.js +2 -2
- package/engine/{restart-health.js → recovery/restart-health.js} +48 -4
- package/engine/recovery/stop-stack.js +607 -0
- package/engine/{supervisor.js → recovery/supervisor.js} +105 -175
- package/engine/{watchdog.js → recovery/watchdog.js} +136 -13
- package/engine/runtimes/claude.js +14 -12
- package/engine/runtimes/codex.js +8 -6
- package/engine/runtimes/copilot.js +17 -16
- package/engine/{watch-actions.js → watches/actions.js} +13 -13
- package/engine/{watches.js → watches/index.js} +43 -32
- package/engine/{watches-store.js → watches/store.js} +4 -4
- package/engine/{create-pr-worktree.js → worktrees/create-pr.js} +1 -1
- package/engine/{worktree-gc.js → worktrees/gc.js} +70 -22
- package/engine/worktrees/inventory.js +671 -0
- package/engine/{live-checkout.js → worktrees/live-checkout.js} +4 -4
- package/engine/{worktree-pool.js → worktrees/pool.js} +2 -2
- package/engine/{worktree-preflight.js → worktrees/preflight.js} +1 -0
- package/engine/worktrees/quarantine-refs.js +173 -0
- package/engine.js +1137 -208
- package/minions.js +147 -77
- package/package.json +10 -6
- package/playbooks/_pr-description-audit.md +110 -78
- package/playbooks/build-fix-complex.md +2 -0
- package/playbooks/fix.md +16 -12
- package/playbooks/implement-shared.md +2 -0
- package/playbooks/implement.md +19 -20
- package/playbooks/plan-to-prd.md +18 -3
- package/playbooks/qa-session-draft.md +136 -1
- package/playbooks/qa-session-execute.md +80 -2
- package/playbooks/qa-session-setup.md +17 -1
- package/playbooks/qa-validate.md +1 -1
- package/playbooks/setup.md +2 -0
- package/playbooks/shared-rules.md +25 -32
- package/playbooks/templates/followup-dispatch.md +4 -3
- package/playbooks/verify.md +1 -1
- package/prompts/cc-system.md +19 -27
- package/watch-plugins/README.md +92 -0
- package/watch-plugins/ado-author-prs.js +336 -0
- package/watch-plugins/gh-author-prs.js +375 -0
- package/watch-plugins/http.js +474 -0
- package/watch-plugins/teams-channel.js +869 -0
- package/docs/dev-composite-workflow.md +0 -101
- package/docs/pr-screenshots/pr-886/after-single-header.png +0 -0
- package/docs/pr-screenshots/pr-886/before-duplicate-header.png +0 -0
- package/docs/pr-screenshots/pr-895/01-cancellation-reason-detail.png +0 -0
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-901/projects-tab-default.png +0 -0
- package/docs/pr-screenshots/pr-901/projects-tab-fmf-selected.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-AFTER-crop.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-BEFORE-crop.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-dropdown-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
- package/docs/visual-evidence-ci.md +0 -103
- package/engine/bridge.js +0 -379
- package/engine/quarantine-refs.js +0 -103
- package/engine/state-operations.js +0 -178
- /package/engine/{steering-constraints.js → agents/steering-constraints.js} +0 -0
package/playbooks/fix.md
CHANGED
|
@@ -75,9 +75,11 @@ Before editing, split the feedback into:
|
|
|
75
75
|
|
|
76
76
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{pr_branch}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
77
77
|
|
|
78
|
+
An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
|
|
79
|
+
|
|
78
80
|
### Branch-mismatch guard (issue #2999)
|
|
79
81
|
|
|
80
|
-
If your task description, `references[]`, or the PR thread clearly identifies an existing PR but your checkout branch does **not** match the PR's source branch — for example you are on `work/W-…` while the task references PR
|
|
82
|
+
If your task description, `references[]`, or the PR thread clearly identifies an existing PR but your checkout branch does **not** match the PR's source branch — for example you are on `work/W-…` while the task references a PR whose source branch is `<pr-source-branch>` — **stop immediately**. Do not branch off master, do not replay the PR's commits onto a fresh branch, and do not open a duplicate PR. Emit a non-retryable completion (`failure_class: "branch-mismatch"`, `retryable: false`) with the referenced PR id and the actual branch you found, so the engine and the operator can re-dispatch on the correct branch.
|
|
81
83
|
|
|
82
84
|
## Working Style
|
|
83
85
|
|
|
@@ -168,22 +170,24 @@ After you push commits to the PR's source branch and BEFORE you mark the work it
|
|
|
168
170
|
- Azure DevOps: `az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`. If the body exceeds ~4 KB, fall back to `az rest --method patch` against `…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
|
|
169
171
|
7. GET-verify the description post-patch by re-running step 1 and confirming the body matches what you sent.
|
|
170
172
|
|
|
171
|
-
**
|
|
173
|
+
**Visual evidence handling — screenshots + recordings (introduce AND refresh for visual changes)**
|
|
174
|
+
|
|
175
|
+
Visual evidence is a **default behavior for UI changes on ANY project**, not minions-only. For a PR that contains a **meaningful visual/UI change** (web front-ends, dashboards, mobile webviews, any rendered surface a user sees), proactively CAPTURE evidence and EMBED it directly in the PR description — do NOT rely only on the OPG `Visual evidence capture` CI bot (it stays as-is and is minions-specific; this is additive PR-body evidence). Decide "is this visual?" from whether the diff changes a rendered UI surface, NOT from repo-specific paths. Capture BEFORE/AFTER screenshots (AFTER-only for new UI) AND a screen recording/video for interactive, animated, or multi-step flows. When the description already embeds `` refs for a view this dispatch touched, refresh them the same way.
|
|
172
176
|
|
|
173
|
-
|
|
177
|
+
**How to capture — resolution order.** (1) **Harness first:** consult the TARGET repo's own instructions for how it runs its UI and captures evidence — `AGENTS.md`, `CLAUDE.md`, `README`/`CONTRIBUTING`, a project-local playbook under `projects/<name>/playbooks/`, or a project-embedded skill under `.claude/skills` / `.github/skills` / `.agents/skills` (the engine surfaces this plumbing read-only via `engine/agents/harness-context.js` and `GET /api/harness/diagnostics`). (2) **Fall back** to Minions' project-agnostic Playwright skill `capture-web-evidence` (`.claude/skills/capture-web-evidence/SKILL.md`) when the repo has no visual-evidence instructions.
|
|
174
178
|
|
|
175
|
-
**MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
|
|
179
|
+
**MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). This is the minions instance of the cross-project default above and is NOT weakened by it. For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
|
|
176
180
|
|
|
177
|
-
**Scope guard — which changes get
|
|
181
|
+
**Scope guard — which changes get visual evidence.** Only meaningful visual/UI changes: dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS, and the equivalent rendered surfaces of other projects. Skip backend-only, engine-logic, text/prose-only, analysis, and docs changes — those get NO screenshots or recordings (they add no signal). BEFORE/AFTER pair for layout/visual FIXES; AFTER-only for NEW UI; add a recording only for interactive/animated flows.
|
|
178
182
|
|
|
179
|
-
1.
|
|
180
|
-
2. Drive Playwright
|
|
183
|
+
1. Detect the project's run command generically — from the repo harness or a `package.json` script named `dev`, `start`, or `serve` (or the repo's documented preview command); do NOT hardcode a per-repo build command. With Playwright available, spin up the dev/preview server with a detached handoff per `shared-rules.md` → "Long-Running Commands" (record PID + log path + URL + stop command).
|
|
184
|
+
2. Drive Playwright to the changed route/view at a normal desktop viewport (and, for mobile webviews, also at a mobile device-emulation viewport, e.g. `devices['iPhone 13']`) and screenshot the section that changed. For interactive flows, enable video recording, drive the interaction, then save the video. Save raw PNGs/videos to `agents/<id>/screenshots/` ONLY (recordings under a `recordings/` subdir). **NEVER `git add` a PNG** or video — committing captured evidence is a release-blocker bug. Stop the dev server with the recorded stop command when done.
|
|
181
185
|
3. Upload + embed:
|
|
182
|
-
- **GitHub (release-asset CDN recipe):**
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
- Embed as `` and patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
|
|
186
|
-
- **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL in the description (now for newly-introduced screenshots too).
|
|
186
|
+
- **GitHub (release-asset CDN recipe):** resolve and GET-verify the current PR's `<owner>/<repo>`. Enumerate configured `gh` accounts, select one with push permission by probing that exact slug through a per-command `GH_TOKEN`, and fail closed if none qualifies. **NEVER run `gh auth switch` or hardcode an operator login.**
|
|
187
|
+
- Query the exact `pr-<num>-visual` tag with `gh release view` first. Upload the explicitly listed current PNGs/videos with `gh release upload ... --clobber` only when that tag exists; create it only after a verified not-found response. Never treat an arbitrary create failure as authorization to overwrite.
|
|
188
|
+
- Resolve URLs via `gh api repos/<owner>/<repo>/releases/tags/pr-<num>-visual --jq '.assets[]|select(.name=="after.png")|.browser_download_url'`.
|
|
189
|
+
- Embed images as `` and recordings as `[<view> (recording)](<url>)`, then patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
|
|
190
|
+
- **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG/video bytes, then reference the returned URL in the description (now for newly-introduced screenshots and recordings too).
|
|
187
191
|
4. Degrade gracefully: if the dev server won't start, the route 404s, Playwright is unavailable, or the upload fails → SKIP without failing the work item and record the skip + reason in `meta.descriptionAudit` (e.g. `result: "screenshots-skipped (dev-server-unavailable)"`).
|
|
188
192
|
|
|
189
193
|
**Out-of-scope guardrails**
|
|
@@ -47,6 +47,8 @@ Do ALL work in the worktree.
|
|
|
47
47
|
|
|
48
48
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{branch_name}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
49
49
|
|
|
50
|
+
An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
|
|
51
|
+
|
|
50
52
|
## Working Style
|
|
51
53
|
|
|
52
54
|
Use subagents only for genuinely parallel, independent tasks. For sequential work, single-file edits, searches, and file reads, work directly — do not spawn subagents.
|
package/playbooks/implement.md
CHANGED
|
@@ -10,16 +10,11 @@ TEAM ROOT: {{team_root}}
|
|
|
10
10
|
Repository ID is injected as `{{ado_project}}` and `{{repo_name}}` template variables.
|
|
11
11
|
Repo: {{repo_name}} | Org: {{ado_org}} | Project: {{ado_project}}
|
|
12
12
|
|
|
13
|
-
## Branch
|
|
14
|
-
Branch format: `user/<loginname>/{{item_id}}-<slug>` — see the canonical "Branch Naming Convention" section in shared-rules above.
|
|
13
|
+
## Branch ownership
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- `user/yemi33/M001-hr-agent`
|
|
20
|
-
- `user/yemishin/M013-multimodal-input`
|
|
21
|
-
|
|
22
|
-
The engine pre-creates your worktree on a branch matching this convention. The branch is already injected as `{{branch_name}}` — push to that branch as-is; do not create or rename branches.
|
|
15
|
+
The engine pre-created this worktree on `{{branch_name}}`. Push that branch
|
|
16
|
+
as-is; do not derive a branch from a user or platform account, and do not create
|
|
17
|
+
or rename branches.
|
|
23
18
|
|
|
24
19
|
## Your Task
|
|
25
20
|
|
|
@@ -40,6 +35,8 @@ If this feature spans multiple projects, inspect the relevant repos, make change
|
|
|
40
35
|
|
|
41
36
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch. If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
42
37
|
|
|
38
|
+
An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
|
|
39
|
+
|
|
43
40
|
## Working Style
|
|
44
41
|
|
|
45
42
|
Use subagents only for genuinely parallel, independent tasks (e.g., editing files in unrelated modules simultaneously). For sequential work, single-file edits, searches, and file reads, work directly — do not spawn subagents.
|
|
@@ -140,22 +137,24 @@ After you push commits to the PR's source branch and BEFORE you mark the work it
|
|
|
140
137
|
- Azure DevOps: `az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`. If the body exceeds ~4 KB, fall back to `az rest --method patch` against `…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
|
|
141
138
|
7. GET-verify the description post-patch by re-running step 1 and confirming the body matches what you sent.
|
|
142
139
|
|
|
143
|
-
**
|
|
140
|
+
**Visual evidence handling — screenshots + recordings (introduce AND refresh for visual changes)**
|
|
141
|
+
|
|
142
|
+
Visual evidence is a **default behavior for UI changes on ANY project**, not minions-only. For a PR that contains a **meaningful visual/UI change** (web front-ends, dashboards, mobile webviews, any rendered surface a user sees), proactively CAPTURE evidence and EMBED it directly in the PR description — do NOT rely only on the OPG `Visual evidence capture` CI bot (it stays as-is and is minions-specific; this is additive PR-body evidence). Decide "is this visual?" from whether the diff changes a rendered UI surface, NOT from repo-specific paths. Capture BEFORE/AFTER screenshots (AFTER-only for new UI) AND a screen recording/video for interactive, animated, or multi-step flows. When the description already embeds `` refs for a view this dispatch touched, refresh them the same way.
|
|
144
143
|
|
|
145
|
-
|
|
144
|
+
**How to capture — resolution order.** (1) **Harness first:** consult the TARGET repo's own instructions for how it runs its UI and captures evidence — `AGENTS.md`, `CLAUDE.md`, `README`/`CONTRIBUTING`, a project-local playbook under `projects/<name>/playbooks/`, or a project-embedded skill under `.claude/skills` / `.github/skills` / `.agents/skills` (the engine surfaces this plumbing read-only via `engine/agents/harness-context.js` and `GET /api/harness/diagnostics`). (2) **Fall back** to Minions' project-agnostic Playwright skill `capture-web-evidence` (`.claude/skills/capture-web-evidence/SKILL.md`) when the repo has no visual-evidence instructions.
|
|
146
145
|
|
|
147
|
-
**MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
|
|
146
|
+
**MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). This is the minions instance of the cross-project default above and is NOT weakened by it. For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
|
|
148
147
|
|
|
149
|
-
**Scope guard — which changes get
|
|
148
|
+
**Scope guard — which changes get visual evidence.** Only meaningful visual/UI changes: dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS, and the equivalent rendered surfaces of other projects. Skip backend-only, engine-logic, text/prose-only, analysis, and docs changes — those get NO screenshots or recordings (they add no signal). BEFORE/AFTER pair for layout/visual FIXES; AFTER-only for NEW UI; add a recording only for interactive/animated flows.
|
|
150
149
|
|
|
151
|
-
1.
|
|
152
|
-
2. Drive Playwright
|
|
150
|
+
1. Detect the project's run command generically — from the repo harness or a `package.json` script named `dev`, `start`, or `serve` (or the repo's documented preview command); do NOT hardcode a per-repo build command. With Playwright available, spin up the dev/preview server with a detached handoff per `shared-rules.md` → "Long-Running Commands" (record PID + log path + URL + stop command).
|
|
151
|
+
2. Drive Playwright to the changed route/view at a normal desktop viewport (and, for mobile webviews, also at a mobile device-emulation viewport, e.g. `devices['iPhone 13']`) and screenshot the section that changed. For interactive flows, enable video recording, drive the interaction, then save the video. Save raw PNGs/videos to `agents/<id>/screenshots/` ONLY (recordings under a `recordings/` subdir). **NEVER `git add` a PNG** or video — committing captured evidence is a release-blocker bug. Stop the dev server with the recorded stop command when done.
|
|
153
152
|
3. Upload + embed:
|
|
154
|
-
- **GitHub (release-asset CDN recipe):**
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
- Embed as `` and patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
|
|
158
|
-
- **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL in the description (now for newly-introduced screenshots too).
|
|
153
|
+
- **GitHub (release-asset CDN recipe):** resolve and GET-verify the current PR's `<owner>/<repo>`. Enumerate configured `gh` accounts, select one with push permission by probing that exact slug through a per-command `GH_TOKEN`, and fail closed if none qualifies. **NEVER run `gh auth switch` or hardcode an operator login.**
|
|
154
|
+
- Query the exact `pr-<num>-visual` tag with `gh release view` first. Upload the explicitly listed current PNGs/videos with `gh release upload ... --clobber` only when that tag exists; create it only after a verified not-found response. Never treat an arbitrary create failure as authorization to overwrite.
|
|
155
|
+
- Resolve URLs via `gh api repos/<owner>/<repo>/releases/tags/pr-<num>-visual --jq '.assets[]|select(.name=="after.png")|.browser_download_url'`.
|
|
156
|
+
- Embed images as `` and recordings as `[<view> (recording)](<url>)`, then patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
|
|
157
|
+
- **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG/video bytes, then reference the returned URL in the description (now for newly-introduced screenshots and recordings too).
|
|
159
158
|
4. Degrade gracefully: if the dev server won't start, the route 404s, Playwright is unavailable, or the upload fails → SKIP without failing the work item and record the skip + reason in `meta.descriptionAudit` (e.g. `result: "screenshots-skipped (dev-server-unavailable)"`).
|
|
160
159
|
|
|
161
160
|
**Out-of-scope guardrails**
|
package/playbooks/plan-to-prd.md
CHANGED
|
@@ -17,6 +17,16 @@ A user has provided a plan. Analyze it against the codebase and produce a struct
|
|
|
17
17
|
|
|
18
18
|
{{retry_context}}
|
|
19
19
|
|
|
20
|
+
{{#revision_feedback}}
|
|
21
|
+
## Revision Requested
|
|
22
|
+
|
|
23
|
+
This run is a **revision** of the existing PRD below, not a fresh conversion. An operator reviewed that PRD and asked for these changes:
|
|
24
|
+
|
|
25
|
+
{{revision_feedback}}
|
|
26
|
+
|
|
27
|
+
Apply this feedback on top of the "Reusing an Existing PRD" rules — preserve item IDs and `done` statuses for everything the feedback does not touch, and re-emit the PRD with the requested changes applied. Addressing every point above is the acceptance bar for this run.
|
|
28
|
+
|
|
29
|
+
{{/revision_feedback}}
|
|
20
30
|
## Instructions
|
|
21
31
|
|
|
22
32
|
1. **Read the plan carefully** — understand the goals, scope, and requirements
|
|
@@ -38,12 +48,15 @@ The sidecar must be an envelope with the exact pre-generated filename:
|
|
|
38
48
|
```json
|
|
39
49
|
{
|
|
40
50
|
"filename": "{{prd_filename}}",
|
|
51
|
+
"work_item": "{{item_id}}",
|
|
41
52
|
"prd": {
|
|
42
53
|
"...": "the PRD object described below"
|
|
43
54
|
}
|
|
44
55
|
}
|
|
45
56
|
```
|
|
46
57
|
|
|
58
|
+
`filename` and `work_item` are the engine's authoritative contract for THIS dispatch — copy them verbatim from this playbook. If a `prd-result.json` from a previous attempt is already on disk, OVERWRITE it; never reuse or trust a filename, work item id, or PRD body found in it. The engine rejects a sidecar that declares any other filename or work item.
|
|
59
|
+
|
|
47
60
|
The engine validates and imports this one-shot sidecar into SQLite when the dispatch completes, then deletes it. Do not write runtime state under `prd/`.
|
|
48
61
|
|
|
49
62
|
```json
|
|
@@ -115,12 +128,14 @@ Choose one of the following strategies based on how the items relate to each oth
|
|
|
115
128
|
{{branch_strategy_hint}}
|
|
116
129
|
|
|
117
130
|
When using `shared-branch`:
|
|
118
|
-
- Generate a
|
|
131
|
+
- Generate a repository-neutral `feature_branch` as
|
|
132
|
+
`work/PL-<short-kebab-description>` (≤ 120 chars, lowercase). Do not embed a
|
|
133
|
+
user, agent, or platform account name.
|
|
119
134
|
- Use `depends_on` to express the ordering — items execute in dependency order
|
|
120
135
|
- Each item should be able to build on the prior items' work
|
|
121
136
|
|
|
122
137
|
When using `parallel`:
|
|
123
|
-
- Omit `feature_branch` (the engine derives
|
|
138
|
+
- Omit `feature_branch` (the engine derives each item as `work/<wi-id>`)
|
|
124
139
|
- `depends_on` is still respected but items can dispatch concurrently if no deps
|
|
125
140
|
|
|
126
141
|
Rules for items:
|
|
@@ -196,7 +211,7 @@ If the task description contains `mode: diff-aware-update`, you are updating an
|
|
|
196
211
|
## Important
|
|
197
212
|
|
|
198
213
|
- Write ONLY the single result sidecar at `{{team_root}}/agents/{{agent_id}}/prd-result.json`
|
|
199
|
-
- Wrap the PRD object in `{ "filename": "{{prd_filename}}", "prd": { ... } }`
|
|
214
|
+
- Wrap the PRD object in `{ "filename": "{{prd_filename}}", "work_item": "{{item_id}}", "prd": { ... } }`
|
|
200
215
|
- Do NOT create a git branch, worktree, or PR — this playbook writes minions-internal state only
|
|
201
216
|
- Do NOT modify any files in the project repo
|
|
202
217
|
- The engine will dispatch implementation agents automatically once the sidecar is imported
|
|
@@ -31,8 +31,25 @@ natural-language flows into a runner-native test file.
|
|
|
31
31
|
- **Managed-spawn target:** `{{managed_spawn_name}}` (live — query
|
|
32
32
|
`{{managed_spawn_lookup_url}}`
|
|
33
33
|
for the freshest port / base URL / health).
|
|
34
|
+
- **Session services (JSON):** `{{session_services_json}}`
|
|
34
35
|
- **Test output directory (absolute):** `{{qa_test_dir}}`
|
|
35
36
|
|
|
37
|
+
### Session services — every entry is a real, separately-reachable origin
|
|
38
|
+
|
|
39
|
+
`{{session_services_json}}` lists **every** managed-spawn this session owns, as
|
|
40
|
+
`[{ "name", "project", "primary", "health", "baseUrl", "ports" }]`. On a
|
|
41
|
+
multi-project session the engine started one service per project, and each one
|
|
42
|
+
is a **real, separately-reachable origin** — a distinct process listening on its
|
|
43
|
+
own `baseUrl` / `ports`, not a route on the primary. Address a co-service by
|
|
44
|
+
**its own** `baseUrl`; never assume the primary's origin proxies it.
|
|
45
|
+
|
|
46
|
+
`managed_spawn_name` above is always the **primary** entry (`primary: true`).
|
|
47
|
+
`health` is `healthy` | `unhealthy` | `down` | `missing` at render time — treat
|
|
48
|
+
anything other than `healthy` as not-yet-usable and re-check via
|
|
49
|
+
`{{managed_spawn_lookup_url}}` (swap the name in the path) before drafting
|
|
50
|
+
against it. An empty value means this session has no service inventory (a
|
|
51
|
+
single-project session already fully described by `managed_spawn_name`).
|
|
52
|
+
|
|
36
53
|
{{additional_context}}
|
|
37
54
|
|
|
38
55
|
## What "qa-session-draft" means
|
|
@@ -81,6 +98,124 @@ Example:
|
|
|
81
98
|
}
|
|
82
99
|
```
|
|
83
100
|
|
|
101
|
+
## Visual-journey manifest (REQUIRED when capture asks for screenshots or video)
|
|
102
|
+
|
|
103
|
+
`{{capture}}` above is what the operator asked this session to capture. When it
|
|
104
|
+
contains `screenshots` or `video`, the completion report is **not** enough — you
|
|
105
|
+
must also declare **what the drafted test actually exercises** in a
|
|
106
|
+
visual-journey manifest sidecar:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
{{qa_draft_result_sidecar}}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Write it as a single JSON object before you exit. The engine consumes it
|
|
113
|
+
**exactly once** (read-then-unlink) in `engine/orchestration/lifecycle.js`,
|
|
114
|
+
validates it in `engine/qa/visual-journey.js`, and **refuses to advance the
|
|
115
|
+
session to EXECUTE** when the declaration does not cover the session. The
|
|
116
|
+
manifest is a declaration, not a scan — describe the file you wrote, honestly.
|
|
117
|
+
|
|
118
|
+
### Schema
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"sessionId": "{{session_id}}",
|
|
123
|
+
"journeys": [
|
|
124
|
+
{
|
|
125
|
+
"id": "short-stable-id",
|
|
126
|
+
"name": "One line describing the user-visible flow",
|
|
127
|
+
"kind": "browser",
|
|
128
|
+
"projects": ["web"],
|
|
129
|
+
"services": ["{{managed_spawn_name}}"],
|
|
130
|
+
"origins": ["http://localhost:7346"],
|
|
131
|
+
"steps": ["open /login", "submit credentials"],
|
|
132
|
+
"assertions": ["dashboard header is visible"],
|
|
133
|
+
"evidence": { "screenshots": ["login.png"], "video": ["login.webm"] }
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- `kind` is `browser` (drives a real rendered surface) or `api` (HTTP only).
|
|
140
|
+
- `projects` / `services` / `origins` say **which** project, managed-spawn, and
|
|
141
|
+
origin that journey touches. Take the names verbatim from
|
|
142
|
+
`{{session_services_json}}` — each entry there is a separately-reachable
|
|
143
|
+
origin, so a co-service journey names the **co-service's own** spawn and base
|
|
144
|
+
URL, never the primary's.
|
|
145
|
+
- `evidence` lists the artifact files the test is written to produce.
|
|
146
|
+
Screenshots must be planned as `.png`, video as `.webm`.
|
|
147
|
+
- Journeys, list lengths, and per-entry sizes are capped
|
|
148
|
+
(`engine/qa/visual-journey.js` `LIMITS`). Keep it to what the test covers.
|
|
149
|
+
|
|
150
|
+
### What the gate rejects
|
|
151
|
+
|
|
152
|
+
When `{{capture}}` includes `screenshots` or `video`, DRAFT fails with
|
|
153
|
+
`failure_class: qa-session-draft-visual-coverage` — the session goes to
|
|
154
|
+
`failed`, EXECUTE is never queued — if any of these holds:
|
|
155
|
+
|
|
156
|
+
| Rejection | Fix |
|
|
157
|
+
|---|---|
|
|
158
|
+
| No manifest at all | Write the sidecar above. |
|
|
159
|
+
| No journey with `"kind": "browser"` | An API-only draft cannot produce screenshots or video. Draft a real browser flow. |
|
|
160
|
+
| A project in the session is in no journey's `projects` | Cover every project the session declared. |
|
|
161
|
+
| A managed-spawn the session owns is in no journey's `services` | Cover every entry of `{{session_services_json}}`, each at its own origin. |
|
|
162
|
+
| `screenshots` requested but no `.png` planned | Plan at least one `.png` under `evidence.screenshots`. |
|
|
163
|
+
| `video` requested but no `.webm` planned | Plan at least one `.webm` under `evidence.video`. |
|
|
164
|
+
|
|
165
|
+
Each rejection message names exactly what is missing, so read
|
|
166
|
+
`session.error` before re-drafting.
|
|
167
|
+
|
|
168
|
+
### Worked example — multi-project session (`web` primary + `api` co-service)
|
|
169
|
+
|
|
170
|
+
Session `{{session_id}}` with `projects: ["web", "api"]`, primary `web`, and
|
|
171
|
+
`capture: video,screenshots`. `{{session_services_json}}` reports two live
|
|
172
|
+
services, so the manifest covers **both** origins and both projects:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"sessionId": "{{session_id}}",
|
|
177
|
+
"journeys": [
|
|
178
|
+
{
|
|
179
|
+
"id": "web-login",
|
|
180
|
+
"name": "Operator signs in on the web app and lands on the dashboard",
|
|
181
|
+
"kind": "browser",
|
|
182
|
+
"projects": ["web"],
|
|
183
|
+
"services": ["{{managed_spawn_name}}"],
|
|
184
|
+
"origins": ["http://localhost:7346"],
|
|
185
|
+
"steps": [
|
|
186
|
+
"goto http://localhost:7346/login",
|
|
187
|
+
"fill credentials and submit",
|
|
188
|
+
"wait for the dashboard route"
|
|
189
|
+
],
|
|
190
|
+
"assertions": ["dashboard header is visible", "no console errors"],
|
|
191
|
+
"evidence": { "screenshots": ["web-login.png"], "video": ["web-login.webm"] }
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"id": "api-backed-list",
|
|
195
|
+
"name": "Dashboard list renders records served by the api co-service",
|
|
196
|
+
"kind": "browser",
|
|
197
|
+
"projects": ["api"],
|
|
198
|
+
"services": ["{{managed_spawn_name}}-api"],
|
|
199
|
+
"origins": ["http://localhost:7346", "http://localhost:4000"],
|
|
200
|
+
"steps": [
|
|
201
|
+
"seed a record via POST http://localhost:4000/api/records",
|
|
202
|
+
"reload the dashboard list"
|
|
203
|
+
],
|
|
204
|
+
"assertions": ["the seeded record appears in the list"],
|
|
205
|
+
"evidence": { "screenshots": ["api-backed-list.png"], "video": [] }
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Note the second journey is still `"kind": "browser"`: it *uses* the co-service
|
|
212
|
+
origin but asserts on a rendered surface, which is what visual capture means.
|
|
213
|
+
A journey that only calls the API is `"kind": "api"` and does not satisfy the
|
|
214
|
+
browser requirement on its own.
|
|
215
|
+
|
|
216
|
+
If `{{capture}}` asks for neither screenshots nor video, the manifest is
|
|
217
|
+
optional and the session behaves exactly as before.
|
|
218
|
+
|
|
84
219
|
## No PR, no commit
|
|
85
220
|
|
|
86
221
|
`qa-session-draft` is a test-authoring task. **Do not**:
|
|
@@ -112,7 +247,7 @@ write a partial test file**. Instead, write your completion report with:
|
|
|
112
247
|
}
|
|
113
248
|
```
|
|
114
249
|
|
|
115
|
-
The `engine/qa
|
|
250
|
+
The `engine/qa/sessions.js#handleDraftComplete` hook reads `failure_class`
|
|
116
251
|
and the summary, transitions the session to `failed`, and surfaces the
|
|
117
252
|
explanation in the dashboard session card so the human knows exactly why
|
|
118
253
|
DRAFT gave up.
|
|
@@ -23,6 +23,7 @@ ingests.
|
|
|
23
23
|
- **Managed-spawn target:** `{{managed_spawn_name}}` (live — query
|
|
24
24
|
`{{managed_spawn_lookup_url}}`
|
|
25
25
|
for the freshest port / base URL / health).
|
|
26
|
+
- **Session services (JSON):** `{{session_services_json}}`
|
|
26
27
|
- **Test file (relative to `engine/qa-tests/{{session_id}}/`):** `{{test_file}}`
|
|
27
28
|
- **Flows (for context):** {{flows_raw}}
|
|
28
29
|
- **Runner hint (optional explicit runner):** `{{runner_hint}}`
|
|
@@ -30,6 +31,24 @@ ingests.
|
|
|
30
31
|
- **Mode:** `{{session_mode}}`
|
|
31
32
|
- **qa-runs record id (use this in the sidecar's `runId` field):** `{{qa_run_id}}`
|
|
32
33
|
|
|
34
|
+
### Session services — every entry is a real, separately-reachable origin
|
|
35
|
+
|
|
36
|
+
`{{session_services_json}}` lists **every** managed-spawn this session owns, as
|
|
37
|
+
`[{ "name", "project", "primary", "health", "baseUrl", "ports" }]`. On a
|
|
38
|
+
multi-project session the engine started one service per project, and each one
|
|
39
|
+
is a **real, separately-reachable origin** — a distinct process listening on its
|
|
40
|
+
own `baseUrl` / `ports`, not a route on the primary. When the drafted test
|
|
41
|
+
targets a co-service, point the run at **that entry's** `baseUrl`; never assume
|
|
42
|
+
the primary's origin proxies it.
|
|
43
|
+
|
|
44
|
+
`managed_spawn_name` above is always the **primary** entry (`primary: true`).
|
|
45
|
+
`health` is `healthy` | `unhealthy` | `down` | `missing` at render time. If a
|
|
46
|
+
service the test needs is not `healthy`, re-check it via
|
|
47
|
+
`{{managed_spawn_lookup_url}}` (swap the name in the path) before running — do
|
|
48
|
+
not start or restart it yourself, the engine owns the lifecycle. An empty value
|
|
49
|
+
means this session has no service inventory (a single-project session already
|
|
50
|
+
fully described by `managed_spawn_name`).
|
|
51
|
+
|
|
33
52
|
{{additional_context}}
|
|
34
53
|
|
|
35
54
|
## What "qa-session-execute" means
|
|
@@ -57,11 +76,21 @@ shape:
|
|
|
57
76
|
"runId": "{{qa_run_id}}",
|
|
58
77
|
"status": "passed",
|
|
59
78
|
"summary": "1 sentence rollup the dashboard will render",
|
|
79
|
+
"journeyCoverage": [
|
|
80
|
+
{
|
|
81
|
+
"journeyId": "login",
|
|
82
|
+
"status": "passed",
|
|
83
|
+
"projects": ["web"],
|
|
84
|
+
"services": ["qa-session-{{session_id}}"]
|
|
85
|
+
}
|
|
86
|
+
],
|
|
60
87
|
"artifacts": [
|
|
61
88
|
{
|
|
62
89
|
"type": "screenshot",
|
|
63
90
|
"path": "test-capture-layout/01-login-form.png",
|
|
64
91
|
"label": "Login form rendered",
|
|
92
|
+
"journeyId": "login",
|
|
93
|
+
"project": "web",
|
|
65
94
|
"capturedAt": "2026-05-20T20:42:00.000Z"
|
|
66
95
|
}
|
|
67
96
|
]
|
|
@@ -78,12 +107,61 @@ Valid `status` values:
|
|
|
78
107
|
unreachable mid-run (use this sparingly — distinguishes infra failure
|
|
79
108
|
from real product-level failure).
|
|
80
109
|
|
|
81
|
-
|
|
110
|
+
### Journey coverage (REQUIRED when this session captures screenshots or video)
|
|
111
|
+
|
|
112
|
+
`journeyCoverage` reports what the run **actually exercised**, one entry per
|
|
113
|
+
journey the DRAFT phase declared in its visual-journey manifest:
|
|
114
|
+
|
|
115
|
+
- `journeyId` — the manifest journey id, verbatim.
|
|
116
|
+
- `status` — `passed` | `failed` | `skipped`.
|
|
117
|
+
- `projects` — every project this journey produced evidence for.
|
|
118
|
+
- `services` — every managed-spawn name this journey addressed **at its own
|
|
119
|
+
origin** (see the session services block above).
|
|
120
|
+
|
|
121
|
+
{{#visual_journey_manifest_json}}
|
|
122
|
+
The DRAFT phase's **accepted manifest** is injected below. These are the exact
|
|
123
|
+
`journeyId` values the engine grades you against — copy them verbatim, one
|
|
124
|
+
`journeyCoverage` entry per journey. Do not invent, rename, merge, or drop ids;
|
|
125
|
+
an id the manifest declared that never comes back `passed` fails the session.
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{{visual_journey_manifest_json}}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The `projects` / `services` shown per journey are what DRAFT **planned** to
|
|
132
|
+
exercise. Report what your run **actually** exercised: if a journey covered
|
|
133
|
+
more, list more; if it covered less, report it honestly with the status it
|
|
134
|
+
earned and let the gate fail the session rather than overstating coverage.
|
|
135
|
+
{{/visual_journey_manifest_json}}
|
|
136
|
+
|
|
137
|
+
Per-artifact `journeyId` and `project` are optional but expected on visual
|
|
138
|
+
sessions: they are what lets the dashboard join a PNG back to the journey and
|
|
139
|
+
project it proves. Both fields are ignored on legacy `qa-validate` runs.
|
|
140
|
+
|
|
141
|
+
**The engine verifies this — it is not paperwork.** When the session requested
|
|
142
|
+
`screenshots` or `video`,
|
|
143
|
+
`engine/qa/visual-journey.js#validateEvidenceCoverage` runs before the session
|
|
144
|
+
is allowed to reach `done` and fails the session with
|
|
145
|
+
`failure_class: 'qa-session-evidence-incomplete'` when:
|
|
146
|
+
|
|
147
|
+
- a requested capture type has **no** registered artifact of that type;
|
|
148
|
+
- a registered artifact does **not exist** on disk, is zero bytes, or resolves
|
|
149
|
+
**outside** `{{qa_artifacts_dir}}`;
|
|
150
|
+
- some project in the session appears in no **passed** journey's `projects`;
|
|
151
|
+
- some managed-spawn the session owns appears in no **passed** journey's
|
|
152
|
+
`services`;
|
|
153
|
+
- a journey the DRAFT manifest declared never reported `status: "passed"`.
|
|
154
|
+
|
|
155
|
+
So: capture real files, register them with paths relative to
|
|
156
|
+
`{{qa_artifacts_dir}}`, and report coverage honestly. A `passed` run that
|
|
157
|
+
cannot show its evidence is failed by the engine, not rounded up.
|
|
158
|
+
|
|
159
|
+
The engine consumes this sidecar in `engine/orchestration/lifecycle.js` and calls
|
|
82
160
|
`qaRuns.completeRun({{qa_run_id}}, …)`. **If the sidecar is missing when
|
|
83
161
|
you exit, the engine marks the run `errored`** — always write it, even on
|
|
84
162
|
bail-out.
|
|
85
163
|
|
|
86
|
-
The `engine/qa
|
|
164
|
+
The `engine/qa/sessions.js#handleExecuteComplete` hook then reads the
|
|
87
165
|
qa-runs terminal status and transitions the session to `done` / `failed`
|
|
88
166
|
accordingly.
|
|
89
167
|
|
|
@@ -56,6 +56,22 @@ error) **fails the entire session** with `failure_class: 'qa-session-setup-faile
|
|
|
56
56
|
and a per-project error JSON in `session.error`. The primary's WI does NOT
|
|
57
57
|
get the DRAFT phase queued in that case.
|
|
58
58
|
|
|
59
|
+
### Every origin you stand up must be journey-addressable (W-msb9kgs402813a97-b)
|
|
60
|
+
|
|
61
|
+
DRAFT must declare a **visual-journey manifest** naming every managed-spawn the
|
|
62
|
+
session owns, each addressed at **its own** origin — and the engine refuses to
|
|
63
|
+
advance to EXECUTE when a spawn is uncovered
|
|
64
|
+
(`failure_class: qa-session-draft-visual-coverage`). So your spawn is only
|
|
65
|
+
useful if the next agent can actually reach and identify it:
|
|
66
|
+
|
|
67
|
+
- declare a **deterministic** port in `managed-spawn.json` `ports[]` (never a
|
|
68
|
+
random/ephemeral one) so `{{session_services_json}}` reports a stable
|
|
69
|
+
`baseUrl` DRAFT can put in a journey's `origins`;
|
|
70
|
+
- expose a healthcheck that goes green only when the service is genuinely
|
|
71
|
+
serving, because DRAFT treats anything other than `healthy` as unusable;
|
|
72
|
+
- do **not** assume the primary proxies you — a co-service is a real,
|
|
73
|
+
separately-reachable origin and is journeyed as one.
|
|
74
|
+
|
|
59
75
|
For single-project sessions (`{{co_services_json}}` empty or `[]`), ignore
|
|
60
76
|
this section — the original single-WI flow applies unchanged.
|
|
61
77
|
|
|
@@ -148,7 +164,7 @@ sidecar**. Instead, write your completion report with:
|
|
|
148
164
|
}
|
|
149
165
|
```
|
|
150
166
|
|
|
151
|
-
The `engine/qa
|
|
167
|
+
The `engine/qa/sessions.js#handleSetupComplete` hook reads `failure_class`
|
|
152
168
|
and the summary, transitions the session to `failed`, and surfaces the
|
|
153
169
|
explanation in the dashboard session card so the human knows exactly why
|
|
154
170
|
SETUP gave up.
|
package/playbooks/qa-validate.md
CHANGED
|
@@ -63,7 +63,7 @@ block above) and registered a `qaRunId`. Your job:
|
|
|
63
63
|
Valid `status` values: `passed` (all required artifacts produced and steps
|
|
64
64
|
green), `failed` (at least one expected step failed — still write the sidecar
|
|
65
65
|
with whatever artifacts you captured). The engine consumes this file in
|
|
66
|
-
`engine/lifecycle.js` and calls `qaRuns.completeRun(runId, ...)`. **If the
|
|
66
|
+
`engine/orchestration/lifecycle.js` and calls `qaRuns.completeRun(runId, ...)`. **If the
|
|
67
67
|
sidecar is missing when you exit, the engine marks the run `errored`** —
|
|
68
68
|
always write it, even on bail-out.
|
|
69
69
|
|
package/playbooks/setup.md
CHANGED
|
@@ -86,6 +86,8 @@ as in `implement`.
|
|
|
86
86
|
Before starting work, run `git status` to confirm the worktree is clean.
|
|
87
87
|
If it's dirty or on an unexpected branch, report and stop.
|
|
88
88
|
|
|
89
|
+
An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
|
|
90
|
+
|
|
89
91
|
## Working Style
|
|
90
92
|
|
|
91
93
|
Use subagents only for genuinely parallel, independent tasks. For sequential
|