cl_async-task-ux
Use when adding a long-running background task to Canary Lab (anything that shouldn't block a REST request or the UI) — coverage generation, port-ification, spec/eval generation.
- License 许可
- MIT
- 最近更新
- 2026-11-05
- Stars
- ★ 4
- Forks
- 0
01 前言 Front Matter
- name
- cl_async-task-ux
- description
- Use when adding a long-running background task to Canary Lab (anything that shouldn't block a REST request or the UI) — coverage generation, port-ification, spec/eval generation.
03 SKILL.md 正文
Canary Lab Async-Task UX
Long-running work (agent runs, multi-second generation, double-boot verification) must NOT block a REST handler or freeze the UI. Canary models it as a background job: start returns immediately, the job persists to disk, the UI/MCP poll it, and a server restart recovers it. Get this contract right by copying an existing impl — don't invent a new lifecycle.
Reference implementations
| Subsystem | Store | Runner / lifecycle |
|---|---|---|
| Verified Coverage jobs | apps/web-server/src/features/coverage/logic/coverage/jobs/store.ts |
…/jobs/runner.ts (startCoverageJob) |
| Port-ification | apps/web-server/src/features/portify/logic/runtime/store.ts |
…/portify/* + src/features/portify/routes/portify.ts |
Coverage jobs are the smallest complete example — read those two files first.
The five-part contract
- Non-blocking. The start endpoint validates input, creates a
runningmanifest, kicks off the work detached (noawaiton the driver), and returns promptly with the manifest. Coverage returns202; Portify currently returns200. The driver streams progress into the manifest and flips it todone/failedwhen it settles. - Persistent. State lives in a file-backed store (
<logs>/<kind>/<id>/…json- an
index.json), never only in memory. The coverage store uses the sharedFileBackedTaskStore; itssave()writes atomically (tmp + rename) then emits achangedevent (the WS/poll push point). Reads come straight off disk so a fresh process sees history.
- an
- Recoverable. On server boot, call
store.reconcileInterrupted(now)to flip any job leftrunningby the dead process toaborted— otherwise it shows as live forever AND wedges the single-flight lock. Wire this next to the other store reconciles inserver.ts. - Re-openable. Status is a pure read of the manifest by id plus a list
endpoint (
GET /api/coverage/jobs/:jobIdandGET /api/features/:name/coverage/jobsfor coverage;GET /api/portify/:workflowIdandGET /api/portifyfor Portify). The dialog/pill re-attaches to a running job by polling that id — closing the UI never kills the work. - Server-side single-flight. The guard is on the START path, keyed on the
real identity (e.g.
feature + kind):store.activeFor(...)→ throw a typed conflict (409). UI disabling is cosmetic, never the guard — two tabs, an agent, and the UI all hit the same on-disk index, so the server must be the lock.
Dual-surface parity
Every async capability ships on BOTH the UI (REST) and MCP, against the same store
(see cl_add-mcp-tool). Start + poll + list at minimum; accept/reject-style
follow-ups if the job parks for human input. MCP tools may construct a fresh store
over the same logsDir — the lock is the on-disk index, not the instance.
Common mistakes
| Mistake | Consequence |
|---|---|
await-ing the driver in the start handler |
Request blocks — the whole point is lost |
| Single-flight enforced only by disabling the button | A second tab / an agent / a restart races a duplicate job |
Skipping reconcileInterrupted on boot |
Crashed jobs show as live forever and hold the lock |
| In-memory-only state | A restart loses history and re-openability |
| Non-atomic manifest writes | A crash mid-write corrupts the job; readers throw |
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-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.