canary-lab-run
Use when running or healing an EXISTING Canary Lab feature locally — "run <feature>", "fix the failing run", "rerun 7cvh", "drive the heal loop" — through the repair MCP tools (start_run, wait_for_heal_task, signal_run, get_heal_context, pause_run, cancel_heal, abort_run). Fix failing runs by editing app/service code, not tests. For end-to-end onboarding of a new repo use canary-lab (flight); for deployed-environment checks use canary-lab-verify.
- License 许可
- MIT
- 最近更新
- 2026-11-05
- Stars
- ★ 4
- Forks
- 0
01 前言 Front Matter
- name
- canary-lab-run
- type
- skill
- description
- Use when running or healing an EXISTING Canary Lab feature locally — "run <feature>", "fix the failing run", "rerun 7cvh", "drive the heal loop" — through the repair MCP tools (start_run, wait_for_heal_task, signal_run, get_heal_context, pause_run, cancel_heal, abort_run). Fix failing runs by editing app/service code, not tests. For end-to-end onboarding of a new repo use canary-lab (flight); for deployed-environment checks use canary-lab-verify.
03 SKILL.md 正文
Canary Lab — Run + Heal Loop
User input through MCP 2.0
Use the native Canary connector in the requesting chat so SDK 2.0 elicitation
(input_required) reaches the human there. Do not substitute a shell MCP client,
answer a form yourself, or recreate the question in chat. Existing explicit
instructions and autopilot choices still apply without another ask.
Form decisions have one shared record. The native form links to the same approval
in Canary Notifications, also surfaced above the Flight page. On needs-input
with approvalId and reviewUrl, show that link and call wait_for_approval with
the ID; repeat on still_waiting. The human answers once in either surface.
A browser answer resolves the server decision; some clients keep their native
form visible until the human dismisses it. Dismissal then returns the stored
result. Client decline/cancel alone does not represent a human decision.
Without an approvalId, leave needs-input pending after decline/cancel, stale
input, or an unfinished UI action; do not automatically retry or repeat the
question. Setup/reconnection can use chat while MCP is unavailable. Never collect
passwords, API keys, or access tokens in chat or form elicitation; use the returned
Canary UI URL for secret entry.
MCP Invocation
Setup and the plugin expose one public Canary Lab MCP tool: exec (usually
rendered as mcp__Canary_Lab__exec). Every
Canary Lab tool name below is the exact command value, not a separate public
tool. For a feature-scoped command, replace both placeholders in this shape:
{"command":"<exact_tool_name>","arguments":{"feature":"<feature_name>"}}
This is the envelope shape, not every command's complete schema. Add the
fields that command declares inside arguments; call describe_tool when a
field is uncertain.
Never invent a wrapper verb such as learn or call, embed JSON in a command
string, or turn arguments into flags. Keep fields such as confirm: true inside
arguments. Use list_tools, search_tools, or describe_tool as the
command when discovery is needed. A deliberately selected focused or full
profile still exposes atomic tools for debugging; the setup-installed path is
compact + exec.
Canary Lab owns the run verdicts and artifacts; this client applies the
fixes. These tools arrive via the Canary Lab MCP server. If this client is
already connected (the plugin connects with compact), skip this step. To
configure the same connection manually: npx canary-lab mcp --profile compact.
Arguments
An invocation argument (/canary-lab-run <suite> — the Getting Started
guide's "Repair a Broken Suite" card emits exactly this shape) is a suite
(feature) name in the connected workspace: pass it to start_run directly.
Workspace Bootstrap
- Find the LIVE server first: read
~/.canary-lab/active-servers.json, which recordsprojectRoot,portandpidfor every UI that registered. A stopped server's entry LINGERS — the file is only rewritten when the next server registers — so an entry is a candidate, not proof: the health check below is what confirms it. One entry → that is your server and itsport. Several → take the one whoseprojectRootis the workspace the user means. None → fall back to~/.canary-lab/workspaces.json(Windows:%USERPROFILE%\.canary-lab\workspaces.json): one workspace → use it, several → ask which, none → ask the user to runnpx canary-lab setup. Do NOT start from a guessed port. - Then CONFIRM it is the right server:
curl -s http://127.0.0.1:<port>/mcp/healthand check thatprojectRootis the workspace you intended. A healthy response does not settle the question on its own — a stale UI left behind by a demo or a tarball smoke test answers a port just as convincingly as the right one, and that is how a flight ends up running in someone's throwaway workspace.projectRootmatches what you intended → continue and tell the user which workspace. It names a DIFFERENT workspace → this is the wrong server; go back to step 1 rather than adopting it. It is under a temp directory (/tmp,/private/var/folders,%TEMP%) → never auto-select it; those are throwaway demo workspaces, so use one only when the user names it explicitly. Only when no live server serves the workspace you want does one need starting. - If the health check fails, start
npx canary-lab uifrom the workspace in a visible long-running terminal; if this client cannot run long-lived commands, ask the user to runnpx canary-lab uifrom the workspace and confirm when it's up. - A healthy
/mcp/healthmeans the server is live. On the setup-installedcompactprofile, atomic names such asget_feature_coverageare deliberately absent fromtools/list; onlyexecis public. Callexecwith{"command":"list_tools","arguments":{}}before concluding the connection is missing. Only an unknown-tool error forexecmeans this session is not connected — ask the user to runnpx canary-lab setup --forceand reconnect/restart the client, then retry. Never drive/mcpwith a hand-written HTTP/JSON-RPC client (curl included; the health check above is the only direct HTTP use): a custom client bypasses client detection and reconnect handling.
Keep ownership until an explicit outcome
A successful heal claim makes this run your unfinished task. Claiming does not start a background repair agent.
- After
start_runreturns an ordinary run with your heal claim, orclaim_healsucceeds, your next run action iswait_for_heal_taskwith thatrunIdand the samesession_id. If you needed to load this skill orget_workflow_guide(workflow: "repair"), make that call immediately after reading it. A promise to wait is not the call. - On
still_waiting, call the bounded wait again. Onneeds_heal, work on this run's repair, thensignal_runonce and wait again. Give progress updates between calls; do not end the turn with “done while waiting” or switch to suite authoring, coverage mapping, or another run while this duty is unresolved. - The wait sends heartbeats only while its call is open. During a long repair,
use the run-specific
heartbeatwithstatus: "healing"at work milestones before the claim goes stale. Chat, unrelated tool calls, andget_run_actionsdo not supervise this run. Do not send heartbeats merely to keep an abandoned task appearing active. - If a tool fails, distinguish a retryable call error from a permission denial or missing connection. Correct an invalid argument and retry the same run; never bypass a denied action through shell commands or a different API. If you cannot continue, tell the user the run ID, last confirmed state, exact blocker, and the action needed to resume or stop. Do not claim it is paused, cancelled, or supervised unless a tool result confirms that outcome.
- Before yielding to unrelated work or ending with an active run, resolve who
will drive it or follow the user's stop instruction. To stop an in-flight
heal when the user authorizes stopping repair, call
cancel_healand check its result; it ends the run as failed. Do not substituteabort_runfor this heal action or claim there is no direct stop tool without checkingcancel_heal. Anabort_rundenial does not provecancel_healis unavailable, but a denied stop action is not permission to try alternate tools for the same effect.abort_runis for a user-requested full abort and requires the human stop form.pause_runenters heal mode, andrelease_healonly releases ownership: neither parks nor cancels the run. If stopping is blocked or needs user input, report that the run is still active and needs attention.
External Run Loop
If start_run returns type: "getting_started_busy", a Getting Started demo already owns the workspace. Follow the returned active target (a run, Flight, coverage job, draft, portify, or export) in its current owner; do not start another workflow.
-
Call
list_featuresand choose the requested feature. Then pick the mode from the target: a run boots the suite's services from its repos and repairs that code. When the target is a deployed, staging or live host the suite does not boot ("the staging run", "check prod"), use canary-lab-verify instead — a repair cycle cannot change a remote deployment, so the only "fix" left would be editing the test. -
Call
start_runwithclaim_heal: true, a stablesession_id, and a usefulconversation_name. Do not passclient_kind— the MCP bridge auto-detects it from the connection; guessing it yourself can mis-set it and suppress heal claim. Heal claiming is open to interactive Claude/Codex clients (Desktop or CLI alike) — only runner-spawned PTY agents are blocked — so an ordinary CLI session like this one can own the heal loop. For requests like "rerun 7cvh", passrun_ref: "7cvh". Before a fresh run, stale test-to-requirement coverage opens a human elicitation: update coverage first, or run now with stale coverage. Never answer it yourself. Update-first returnstype: "coverage_update_required"and starts nothing: respectactiveJobId/flightIdownership, complete the returned coverage next steps, confirm freshness, then retrystart_run. Run-now is diagnostic;coverageStale: truemeans the historical percentage is still not current. Decline/cancel starts nothing. Reusing an active run or restarting a failed/aborted run withrun_refcontinues its recorded suite without this gate. Before a fresh run, a suite that boots no services and whose envset names a deployed host opens a human elicitation: verify the deployed target, or run with repair anyway. It is asked before coverage. Never answer it yourself. Verify returnstype: "verify_instead"with the deployedtargetOriginsand starts nothing — continue with canary-lab-verify (list_verification_configs→execute_verification). Only if the fallbacktype: "remote_target_requires_choice"reaches you, ask the user; only after they choose run-anyway re-callstart_runwithremote_target: "run". Never pass it on your own. -
A run boots the commit the feature's repo checkout is sitting on — not the branch's latest. If the user wants the current upstream tip ("run against latest main", "pull first"), pass
update_repos: true: before the worktree is cut, Canary Lab doesgit fetch+git merge --ff-onlyon each pinned repo. A repo declared withtrack: 'upstream'infeature.config.cjsdoes this on every run without the flag;update_repos: falseboots the checkout as-is. Ifstart_runreturnstype: "repo_update_refused", nothing started:repos[]says per repo why (dirty,diverged,detached,wrong-branch,fetch-failed,in-use). Tell the user which repo and why and let them reconcile — never stash, reset, or discard their work to make the update go through — then re-callstart_run(or re-call withupdate_repos: falseto boot the checked-out commit anyway).get_feature_repo_statusreportsbehindUpstream/aheadUpstreamso you can say how stale a checkout is before starting. Ifstart_runreturnstype: "repo_collision_requires_choice", another run is using the same app/repo. The tool requests this choice through elicitation when supported. Only if this fallback result reaches you, ask the user whether to run this one isolated in a per-run git worktree (runs now, concurrently) or queue it until the other run finishes, then re-callstart_runwithisolation: "worktree"orisolation: "queue". Do not guess. Ifstart_runreturnsqueued: true, tell the user the run is parked (queueReason) and will start automatically when capacity frees;wait_for_heal_taskstill blocks until it starts and needs fixes. -
If
start_runreturns an active run, continue that run. But if it returnstype: "boot_session"(orexecutionType: "boot"), the run is a held boot-only session — services are up, no tests run, and there is no heal task. Do not claim heal or callwait_for_heal_task; report that services are ready and that the user can stop them through theabort_runhuman confirmation form when done. A service that fails its readiness probe is marked failed (its status showstimeout) but the session stays held — boot never self-aborts on a health-check failure, so report which services came up and which failed; onlyabort_runtears it down. -
If
start_runreportsalready-claimed, stop and tell the user which session owns the run. If it returnsclaimSuppressed: true, this session is a runner-spawned PTY agent (the benchmark/portify sessions Canary Lab launches itself) and cannot own the heal loop — interactive clients are not suppressed, so you normally won't hit this. The run still runs in External-client heal mode (it does not fall back to the project's configured heal agent — it waits for a drive); do not callwait_for_heal_task. Report the run id and tell the user to drive heal from an interactive Claude/Codex client or the web UI. -
Handle user interrupts explicitly: "pause", "intercept", or "pause and heal" means call
pause_run; "stop heal" or "cancel repair" means callcancel_heal; "abort", "kill the run", or "stop everything" means callabort_runonly with the required confirmation. -
Call
wait_for_heal_taskwith therunIdfromstart_runand the samesession_id. It blocks for a short bounded window and heartbeats for you. If it returnstype: "still_waiting", the run is still active and the window just elapsed — this is not terminal: immediately callwait_for_heal_taskagain with the samerunId+session_id. Loop onstill_waitinguntil you getneeds_heal/passed/failed. (If it ever returnstype: "boot_session", the run is a held boot-only session — report services are up and stop here; do not wait again.) -
If it returns
passed, summarize usingresult.counts.statusLineand stop. -
If it returns
failed, report the terminal status usingresult.counts.statusLineand relevant failure summary.- If
result.newRunRequiredis present, the suite's one external-effect attempt was already claimed. The app repair is captured but unverified. Review/promote its Changes patch, obtain the suite's required approval, and start a fresh run withoutrun_ref. Do not restart or hand off the spent run. - If
result.serverExitedis present, the Canary Lab server driving the run stopped mid-run, so its services and heal loop stopped too and the run is settledaborted— no verdict, nothing left to signal.signal_run,pause_runandcancel_healon such a run answerserver-exitedthe same way. RelayserverExited.message, then restart it withstart_runandrun_refset to its run id; its recorded suite and journal carry over. - If the result carries
dirtyTests(a test file changed since the last green run — can appear onpassed,failed, orneeds_heal), relayresult.dirtyTests.messageto the user verbatim (e.g. "⚠️ Tests have been modified, please review.") alongside the outcome. Do not block, gate, re-run, revert, or edit the test files to "fix" it — it's an awareness signal so the user can review or commit the change, not an error to act on. - If the result carries
specEdits(test files changed after this run started — can appear onpassed,failed, orneeds_heal), the run used the tests recorded at run start, so the changed files were not tested and the result says nothing about them. Relayresult.specEdits.messageand followresult.specEdits.nextSteps: call get_test_review(runId), show the exact patch (read patchPath if needed), then call review_test_changes(runId, review_revision) WITHOUT wait_for_decision. The human choosesAccept & commitorRestore recorded files; cancel/decline leaves pending. Acceptance binds approval to the displayed revision, commits every reviewed file including helpers/fixtures/config, and returns a durable receipt with Git and execution outcomes. For an active run continue with wait_for_heal_task and do not signal twice; for an ended passed/failed/aborted run call start_run without run_ref when the receipt saysnew-run-required. Acceptance preserves the old result and is never a pass. reviewUrl is optional side-by-side inspection, never a required operational step. If elicitation is unavailable or the client declines without a recorded decision, say no human decision was recorded; with a blocked request_id use the browser watcher rule below. For other reviews, use a capable client or the human-chosen browser fallback. A Git commit, clean tree, restart, or chat statement is not a persisted review receipt; only the explicit decision creates one. Changed revisions require a fresh review. No MCP tool can self-approve a test-file change, and apassedrun with pendingspecEditsis a pass of the recorded tests — never report the changed tests as passed.result.specEdits.hintsis the advisory check: akind: "weaker"hint means an assertion was removed or loosened relative to the test that ran — restore it, a weaker assertion is never a repair;kind: "cannot-classify"means review by hand. QuotespecEdits.disclosurewith any hint you quote.
- If
-
If it returns
needs_heal, treat the returned heal context as the compact first-stop packet — which part of it matters depends on the situation:-
context.singleAttempt.claimedtrue: the suite's receipt says this run used its one external-effect attempt. Fix app/service code, thensignal_runonce with the journal fields. Canary finalizes this run failed/unverified and captures its patch; it does not restart services or rerun Playwright. Callwait_for_heal_taskfor the terminal result. A fresh approved run with a new ID is required to verify the promoted fix. -
context.failedTestsnon-empty, first cycle (context.healPromptpresent): inspectcontext.healPrompt.startHerefirst, then usecontext.healPrompt.resources, current failures, and the checked-out source code. The packet is slim —context.healIndexandcontext.journalare paths (Readthem when needed), and eachcontext.failedTests[]entry carries afailureIdplus pointer dirs (errorPath,traceDir,playwrightMcpDir). -
cycle ≥ 2 (
context.guidancepresent, nocontext.healPrompt):context.healPromptandcontext.nextStepsare sent on the firstneeds_healonly — on repeat cycles the context carries just the changed failure packet plus acontext.guidancebreadcrumb. Reuse the cycle-1 map, or callget_heal_contextto re-fetch it. -
context.escalationpresent: the same tests failed 3+ cycles running — you're stuck. Readcontext.escalation.readFirstand followcontext.escalation.tactics(change tactic — revert or build on the prior diff, don't fire a fresh unrelated hypothesis) instead of repeating the last fix. -
context.failedTestsempty ANDcontext.bootFailureset: a service failed to boot — no tests ran. Inspect its reason/classification, command/cwd, exit/signal, and bounded redacted excerpt beforeReading the full logPath.classification: "underlying-cause-not-preserved"means an outer wrapper did not preserve the underlying rejection or child-process failure: do not guess a root cause; fix that product wrapper to log and rethrow. Then fix the service/app code andsignal_runkind: "restart"(context.nextStepsalready reflects this). -
context.serviceFailureset: a required service failed after readiness. Playwright may have partial results; do not infer failures or passes for tests that did not run. Inspect the recorded kind, excerpt, and service log, fix the service/app code, thensignal_runkind: "restart". This failure enters healing automatically;signal_runmeans the fix is ready for runner verification. -
context.dependencyBlockerspresent: startup is blocked by incompatible dependencies. Each record names the repository, all affected services, a stablecause,requiredAction,worktreePath, andlogPathwhen available. Repair deterministic in-scope problems without elicitation. Ask only for a genuine user choice or missing authority, such as changing another shared checkout. Never offer continue-anyway, mark-compatible, or a revision change as a bypass; different generator inputs do not prove that generated output differs. Fix app/service dependencies, not tests or the validator. Thensignal_runkind: "restart"on the same run. Both restart and rerun perform a fresh dependency preflight and persist its evidence before any service spawn or test verification. These blockers remain in repeat waits;get_heal_contextrecovers them after reconnect.
Call
get_run_snapshotonly when you need the verbose raw summary, full counts, or deeper debugging fields. -
-
Follow the run diagnosis policy in
context.nextStepsor its heal prompt. The default is parent-only: read the failure index yourself, diagnose every failure in the parent, and do not spawn diagnosis sub-agents. Keep a failure-ID ledger — each failure with its evidence, candidate cause, and addressed or explicitly unresolved status; similar symptoms or a shared service log alone do not prove a common cause. If contradictory evidence or a failed verification cycle needs delegation, record the escalation (failure IDs + reason) in your hypothesis first; escalated children are read-only and return evidence plus a proposed patch. An explicitper-failureoradaptivepolicy overrides this default for that run. Underper-failure, when several tests fail, dispatch one read-only sub-agent per failure in a single parallel round (up to 5 at once), hand each thefailureId, and have it callget_failure_detail(runId, failureId)to investigate just that slice and report back a hypothesis plus a concrete proposed patch (the exact file edits / unified diff). Under every policy, sub-agents are read-only — they must not touch the working tree or callsignal_run— and you apply all fixes yourself, serially, reconciling by hand if two touch the same file, thensignal_runonce. Applying and signalling stay single-threaded. A sub-agent that comes back empty, or a failure you could not explain, has not been cleared — say so in the hypothesis rather than signalling as though its test were addressed. -
Fix app/service code, not tests, unless the test is provably wrong.
- Edit where the run actually booted. When the heal context carries
context.worktrees(repo name → path), this run is isolated and the services under test were booted from those per-run git worktrees — every portified feature runs this way, and so does any run the user isolated after a collision. Apply your fix under thecontext.worktreespath.context.repoBranches[].pathis the product repo, which an isolated run never reads (repoBranches[].shais the commit the run booted, andupdatedFromUpstreamsays when the start pulled to get there): patch only that and the rerun comes back byte-identical, which reads as "my fix did not work" when the fix was right and simply never loaded. The worktree edits are captured at teardown, so nothing is lost. Whencontext.worktreesis absent, the run boots the repos in place andrepoBranches[].pathis the edit target.
- Edit where the run actually booted. When the heal context carries
-
Call
signal_runonce per cycle withkind: "rerun"for test-only/app-code fixes that do not need service restart, orkind: "restart"when services or env need restarting. IncludehypothesisandfixDescription; Canary Lab writes the journal from that signal and its observed git diff. One accountable signal per cycle, even when you fixed several failures. -
Do not call a separate journal-writing tool; the runner records failing tests, changed files, signal, outcome, and diff.
-
Repeat from
wait_for_heal_task(looping onstill_waiting) until the run passes or reaches terminal failure.
wait_for_heal_task result types
| Result | Action |
|---|---|
still_waiting |
Not terminal — re-call with the same runId + session_id. |
needs_heal |
Fix (see step 10), signal_run once, then wait again. |
passed |
Report result.counts.statusLine, plus what happened to your fix (see below), then stop. |
failed |
Report result.counts.statusLine + failure summary, stop. |
boot_session |
Report which services came up, stop — never wait again. |
What happens to your fix when the run passes
Your edits are never left only in your head or only on disk. At teardown Canary Lab diffs the
run's working copy, saves the result as a patch per repo, and — unless the workspace turned it
off — opens a draft pull request from it. So on passed:
- Do not open a pull request yourself, and do not push a branch. The run does it, on a branch named per feature + repo, so healing the same feature again updates that same pull request instead of opening a second one.
- Report what the run reports: the pull request URL when there is one, or the per-repo reason
there isn't (gh not signed in, no push rights, the patch no longer applies). Both live on the
run's
prAttempt; the diff itself is on the run's Changes tab in the Canary Lab UI. - A run that ends red, or that gives up after its cycle cap, opens nothing — a fix that didn't make the tests pass is not a fix to propose.
Guardrails
- Envset values belong in
features/<feature>/envsets/<env>/<slot>in the selected workspace. A suite.envis a materialized consumer target, not a second source. Never create pointer-only envsets or target.runtime/envsets, an envset source, or a personal source checkout merely because an old variable points there. If the user authorizes an envset repair, readget_workflow_guide(workflow:"author")and trace source → target → consumer before updating the values and consumer together. Otherwise report the mapping problem; repair permission for app code does not authorize a suite migration. session_idrecipe: generate one id at the start of the conversation (any unique string) and pass that identical value in every tool call for the rest of the conversation.- When a blocked start returns
request_id, carry it intoget_test_reviewandreview_test_changes. On an accepted receipt, resume withstart_run(feature, request_id, session_id)in the original external client; Restore recorded files cancels that external request, so stop without starting. Canary resumes internal requests itself. Never create a replacement request or switch owners. If the form is unavailable or the client declines without a recorded human decision, show reviewUrl and keep waiting: spawn exactly one background agent for this request if supported, otherwise wait in this turn. The watcher callsget_test_reviewin its own MCP session for a fresh read-onlybrowser_wait_token, then repeatsreview_test_changeswithwait_for_decision:true. It stops on restored/cancelled or changed revision. After reconnect, get a fresh token and read the same durable request. A wait, transport notification, Git commit, or agent-written argument never approves changes. - A FLIGHT can hand you a run via an
external-workcheckpoint carrying arunId: the run was started in external-heal mode UNCLAIMED for you —claim_healit with your ownsession_idand drive this exact loop, then re-callget_flightand release withrespond_flight_checkpoint(flightId, choice: "submit")once the run is terminal (a failed run is a valid terminal answer; Canary reads the verdict from the run record). If that re-check carriescheckpoint.data.takeoverRequestedAt, stop your repair work and release withchoice: "run-internally"instead — do not submit. Neverabort_runa flight-owned run to escape it, and never start another run for that feature while the flight owns it. The flight will wait on you indefinitely — a parked hand-off has no deadline — so do not end your turn with it open; after 45 minutes with noget_flightcontact the read reportshandOffIdleon it. heartbeatis a low-level liveness refresh for long local repair stretches.wait_for_heal_taskheartbeats while waiting, andsignal_runandget_heal_contextrefresh liveness, so call explicitheartbeatonly before or after a long stretch of localRead/Edit/Write/Bashwork.start_runis the single entrypoint for start/resume/restart intent. A fresh run pauses for a human choice when coverage mapping is stale; no agent flag bypasses that gate. A matching active run is continued even withforce_new:true; intentional concurrent runs of the same feature start from the Run panel. Across different features, a same-app collision returnsrepo_collision_requires_choice(resolve withisolation: "worktree"or"queue"); over the resource budget, the run isqueuedand starts automatically.- For requests like "rerun 7cvh",
start_runresolves the run suffix and restarts that same failed/aborted run in remaining-test mode. Canary Lab reruns failed tests first, then skipped tests, then pending/not-run tests; do not tell the user no test filter exists. - To re-execute a run, reuse it: prefer this rerun (
start_runwithrun_ref) overabort_run+ a fresh start — rerun re-executes only the failed/skipped/pending tests and avoids the abort + repo-collision dance. The rerun already re-runs skipped and pending tests, so it is complete — do notforce_newjust to avoid "skipped" tests. On a portified feature,force_newspins a brand-new per-run worktree and resets the heal journal to Iteration 1, discarding the prior cycles. Start a fresh full run only when prior passes are genuinely invalidated (e.g. a global data/state change), and you rarely need toabort_runfirst to do so. - After changing code or tests, never call
start_runto verify. The signal requests runner verification; it is not a claim that the fix already passes. Do not start services or run Playwright, smoke, end-to-end, or other runtime checks yourself. Canary Lab owns affected-service restart, health checks, and targeted Playwright verification after the signal. If an edit command failed or syntax is uncertain, run at most one fast non-network static check before signalling. Verification meanssignal_runwithhypothesisandfixDescription, thenwait_for_heal_taskon the samerunId. wait_for_heal_taskwaits while a submitted signal is pending and while a live runner transitions from a test failure into healing. Only a finalized run returns a terminal result; keep waiting on this run.- During normal healing, omit
run_ref/force_newsostart_runcontinues the active run.force_newcannot replace an active run. Pending suite changes block fresh starts untilget_test_reviewthenreview_test_changesrecords the human'sAccept & commitorRestore recorded filesdecision for the exact revision. The acceptance receipt says whether the active run reran or a new run is required; start the latter withoutrun_ref. Restarting preserves recorded tests and review history but cannot turn acceptance into tested evidence. - Environment exclusions must be declared in the recorded suite before execution with the
canary:environmentsannotation.counts.notApplicablestays part ofcounts.skipped, nevercounts.passed; other skips and not-run tests still block completion. Never add an exclusion to evade a failure. Changing applicability during a repair requires the same human test review as any other test edit. - Never compute passed count as
summary.total - summary.failed.length. Useresult.counts.statusLine,result.counts.passed, orsummary.passedfor pass counts. Treat tests absent frompassedNames,failed, andskippedNamesas not run, not passed. - Do not call
abort_rununless the user asks. Its human form must be accepted; agent-writtenconfirm:trueis not authorization. If forms are unavailable, the human uses Stop in the Run panel. Never answer that form yourself. - Prefer compact
get_heal_contextwhen you need to refresh failure artifacts outside the wait loop. Useget_run_snapshotonly for verbose fallback/debugging context. - Read responses are slim by default to protect your context, but the full data is always one step away — pull it whenever a failure needs deeper detail (just never in a wait loop):
get_runomits the rawlifecycleEvents/playwrightArtifacts/playbackEvents(call it again withincludeRaw:trueto inline them);get_run_snapshotreturns the heal-index and journal as paths toRead;list_runsreturns the newest 20 (raiselimit). - On any terminal run, recommend the exact next skill invocation
/canary-lab-export <runId>, replacing the placeholder with the terminal run's returned ID. Do not substitutenpx canary-lab export; the export skill uses the connected MCP server and preserves the exact run selection. - Record concise, factual journal notes. Do not paste raw transcripts.
- When the run is waiting for external heal, Canary Lab is the source of truth for status, artifacts, and rerun/restart signals.
04 同仓库更多 Skills
off-by-one
暂无简介
multi-failure-cascade
暂无简介
broken-delete-contract
暂无简介
canary-lab
Use when the user wants Canary Lab to take a product repo end to end — "test this app", "onboard this repo", "run a flight", "evaluate what I just built" — through the flight pipeline (start_flight / get_flight / respond_flight_checkpoint over MCP). One conducted pipeline continues a configured suite or takes bare repo(s) to a green, covered, healed run and publishes a downloadable Report; Parallel setup continues as Canary-owned background work. Use a focused skill only when the user asks for that single capability without asking for a Flight or /canary-lab.
canary-lab-verify
Use when verifying a Canary Lab feature against a RUNNING target — a deployed environment ("verify checkout on staging", "run the saved verify config", "check the deployed app") or a locally booted app ("verify a running app") — through the verify MCP tools (list/get/create/update_verification_config, boot_services, execute_verification, get_verification_result). No heal loop. For run + heal use canary-lab-run; for end-to-end onboarding use canary-lab (flight).
canary-lab-repair-discovery
Repair Playwright test discovery for an existing Canary Lab suite, reporting live progress to the Tests column through MCP. Use when the test list cannot load or Canary offers an In your agent discovery-repair command. Does not execute tests or repair a failing test run.