[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6XCSK0JYJZRTKTYT7VMMCCV":3,"skill-same:01M6XCSK0JYJZRTKTYT7VMMCCV":83},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":58,"ownerHtmlUrl":59,"ownerBlogUrl":60,"ownerDescription":61,"updatedAt":62,"install":63,"resources":76},"01M6XCSK0JYJZRTKTYT7VMMCCV","canary-lab-author",null,"Use when creating or extending a Canary Lab feature by hand — \"create a feature for X\", \"add test cases to \u003Cfeature>\", \"capture the env files\", \"switch the feature's branch\" — through the author MCP tools (create_feature, capture_feature_env_files, write_envset, start\u002Fupdate\u002Fapply_external_draft, get_feature_repo_status, checkout_feature_repo_branch). For docs\u002FPRD\u002Fcoverage use canary-lab-coverage; for full onboarding of a bare repo use canary-lab (flight).","ferterahadi\u002Fcanary-lab","ferterahadi","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F148174839?v=4","01M6XCHCY39C7QEF3JZJ3VZGNZ","Fer Terahadi","01M6XCHD1ZE9926NBC97ZMZZRY",4,"MIT","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fagent-integrations\u002Fcodex\u002Fskills\u002Fcanary-lab-author\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"canary lab author","author","canary","lab","files","when","bare","hand","checkout","full","get","MCP","coverage","write","branch","Tools","start","update","create","status","2026-11-10 10:12:30",false,"---\nname: canary-lab-author\ndescription: Use when creating or extending a Canary Lab feature by hand — \"create a feature for X\", \"add test cases to \u003Cfeature>\", \"capture the env files\", \"switch the feature's branch\" — through the author MCP tools (create_feature, capture_feature_env_files, write_envset, start\u002Fupdate\u002Fapply_external_draft, get_feature_repo_status, checkout_feature_repo_branch). For docs\u002FPRD\u002Fcoverage use canary-lab-coverage; for full onboarding of a bare repo use canary-lab (flight).\ntype: skill\n---\n\n# Canary Lab — Feature Authoring\n\n## MCP Invocation\n\nSetup and the plugin expose one public Canary Lab MCP tool: `exec` (usually\nrendered as `mcp__Canary_Lab__exec`). Every\nCanary Lab tool name below is the exact `command` value, not a separate public\ntool. For a feature-scoped command, replace both placeholders in this shape:\n\n```json\n{\"command\":\"\u003Cexact_tool_name>\",\"arguments\":{\"feature\":\"\u003Cfeature_name>\"}}\n```\n\nThis is the envelope shape, not every command's complete schema. Add the\nfields that command declares inside `arguments`; call `describe_tool` when a\nfield is uncertain.\n\nNever invent a wrapper verb such as `learn` or `call`, embed JSON in a command\nstring, or turn arguments into flags. Keep fields such as `confirm: true` inside\n`arguments`. Use `list_tools`, `search_tools`, or `describe_tool` as the\n`command` when discovery is needed. A deliberately selected focused or `full`\nprofile still exposes atomic tools for debugging; the setup-installed path is\n`compact` + `exec`.\n\nThis client writes the specs; Canary Lab is the control plane and artifact\nstore. These tools arrive via the Canary Lab MCP server. If this client is\nalready connected (the plugin connects with `compact`), skip this step. To\nconfigure the same connection manually: `npx canary-lab mcp --profile compact`.\n\n## Arguments\n\nAn invocation argument (`\u002Fcanary-lab-author \u003Csuite>` — the Getting Started\nguide's \"Author Tests\" card emits exactly this shape) is the name of an\nEXISTING suite (feature) in the connected workspace. Follow the\n**extend-an-existing-feature** path below — never `create_feature` for it,\nand never rename it to dodge a collision.\n\n## Workspace Bootstrap\n\n1. Find the LIVE server first: read `~\u002F.canary-lab\u002Factive-servers.json`, which records `projectRoot`, `port` and `pid` for 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 its `port`. Several → take the one whose `projectRoot` is the workspace the user means. None → fall back to `~\u002F.canary-lab\u002Fworkspaces.json` (Windows: `%USERPROFILE%\\.canary-lab\\workspaces.json`): one workspace → use it, several → ask which, none → ask the user to run `npx canary-lab setup`. Do NOT start from a guessed port.\n2. Then CONFIRM it is the right server: `curl -s http:\u002F\u002F127.0.0.1:\u003Cport>\u002Fmcp\u002Fhealth` and check that `projectRoot` is 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. `projectRoot` matches 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 (`\u002Ftmp`, `\u002Fprivate\u002Fvar\u002Ffolders`, `%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.\n3. If the health check fails, start `npx canary-lab ui` from the workspace in a visible long-running terminal; if this client cannot run long-lived commands, ask the user to run `npx canary-lab ui` from the workspace and confirm when it's up.\n4. Do not reflexively call `list_features` or `list_runs` after health. For random or new feature creation, call `create_feature` directly with a unique feature name; use `list_features` only to discover or choose an existing feature.\n5. A healthy `\u002Fmcp\u002Fhealth` means the server is live. On the setup-installed `compact` profile, atomic names such as `get_feature_coverage` are deliberately absent from `tools\u002Flist`; only `exec` is public. Call `exec` with `{\"command\":\"list_tools\",\"arguments\":{}}` before concluding the connection is missing. Only an unknown-tool error for `exec` means this session is not connected — ask the user to run `npx canary-lab setup --force` and reconnect\u002Frestart the client, then retry. Never drive `\u002Fmcp` with a hand-written HTTP\u002FJSON-RPC client (curl included; the health check above is the only direct HTTP use): a custom client bypasses client detection and reconnect handling.\n\n## Create or Extend a Feature\n\n1. Pick the path by what the request names:\n   - **Extending an EXISTING feature** (\"author tests for \u003Cfeature>\", \"add a test for the missing behavior\"): do NOT call `create_feature` — the feature and its skeleton already exist. To choose WHAT to test, `get_feature_coverage(feature)` names the untested \u002F path-incomplete requirements (that IS the \"choose a gap\" step), and `list_feature_docs(feature)` points at the requirement docs behind them. Author the new spec straight into `\u003Cworkspace>\u002Ffeatures\u002F\u003Cfeature>\u002Fe2e\u002F`, and tag it with the requirement it covers — `test('…', { tag: ['@req-R2'] }, …)` — so the gap actually closes in the coverage ledger.\n   - **Creating a NEW feature**: call `create_feature` directly with a unique feature name. It creates the skeleton files and returns test-file rules, envset schema, and next-step tool hints. Do not call `list_features` just to avoid collisions; if the name you INVENTED already exists, retry `create_feature` with a different unique name — but never rename away from a feature the user asked for (that is the extending path above).\n2. If the user asks to preserve existing `.env`, `.env.dev`, `application.properties`, or similar repo config files, inspect the source repo enough to identify the files, then call `capture_feature_env_files`. Do not paste secret values into chat; Canary Lab returns redacted previews only. `write_envset` fills in or corrects individual envset values (it is confirm-gated).\n3. Author or edit specs under `\u003Cworkspace>\u002Ffeatures\u002F\u003Cfeature>\u002Fe2e\u002F` — the Canary Lab WORKSPACE, not the product repo under test.\n   **Spec selection never depends on the envset.** In the suite's\n   `playwright.config.*`, keep `testDir`, `testMatch`, `testIgnore`, `grep` and\n   `grepInvert` as constant literals — never derived from\n   `CANARY_LAB_MANIFEST_PATH`, `process.env`, or the recorded env. A test that\n   must not execute in some environment skips ITSELF at runtime:\n   `test.skip(process.env.VERIFICATION_ENV !== 'meta', 'needs the Meta sandbox')`,\n   reading the env from the envset's own values rather than the manifest. See\n   Guardrails for why.\n4. Specs must import:\n   ```ts\n   import { test, expect } from 'canary-lab\u002Ffeature-support\u002Flog-marker-fixture'\n   ```\n5. Call `start_external_draft` with a stable `session_id` and a useful `conversation_name` (do not pass `client_kind` — the bridge auto-detects it). This only creates a visible Canary Lab task so the user sees that this external agent session is authoring tests; it does not start an internal wizard agent. Carry the `draftId` it returns into every subsequent `update_external_draft_stage` \u002F `apply_external_draft` call for this draft. If it returns `type: \"getting_started_busy\"`, a Getting Started demo already owns the workspace — follow the active target it returns; do not start another workflow.\n6. After `start_external_draft` returns, tell the user you are authoring tests and they can follow along live in the Canary Lab UI: the suite's Flight page shows this work on its Test authoring & coverage stage (that view is read-only while this client drives — it monitors, you act here). Continue writing specs locally, then call `update_external_draft_stage(draftId, stage)` as work progresses: `scaffolding`, `authoring-tests`, `validating`, `ready`, `applied`, or `error`.\n7. Call `apply_external_draft` with `draftId`, `confirm: true`, and `files: [{path, content}, …]` for the externally authored files (omit `files` if you already wrote them directly under `\u003Cworkspace>\u002Ffeatures\u002F\u003Cfeature>\u002Fe2e\u002F` — it then validates what's on disk), so Canary Lab validates and records the applied draft. Do not ask Canary Lab to spawn another Claude\u002FCodex agent for MCP-created authoring. On a validation error, fix the named file and re-call `apply_external_draft`.\n8. `get_feature_repo_status` \u002F `checkout_feature_repo_branch` inspect and switch the feature's bound repo branches when the user asks to test a different branch. The status also reports where the pinned branch stands against its upstream (`upstreamSha`, `behindUpstream`, `aheadUpstream`); when it is behind, `update_feature_repo_branch(feature, repo, confirm: true)` fast-forwards the checkout to the upstream tip so the next run boots the latest commit. It refuses — and changes nothing — when the checkout is dirty, detached, on another branch, or has diverged; report the reason and let the user reconcile rather than discarding their work. A repo declared with `track: 'upstream'` in `feature.config.cjs` is fast-forwarded automatically at every run start.\n\n## Envset source and target\n\nStore actual values in the selected workspace at\n`features\u002F\u003Cfeature>\u002Fenvsets\u002F\u003Cenv>\u002F\u003Cslot>`. A suite that reads `.env` normally uses\n`envsets\u002Flocal\u002F\u003Cfeature>.env` with target\n`$CANARY_LAB_PROJECT_ROOT\u002Ffeatures\u002F\u003Cfeature>\u002F.env`. The envset file is the durable\nsource; the target is the temporary file the launcher and Playwright consume.\nThe runner applies it before startup and restores backed-up targets at teardown.\nVerify that teardown also removes targets absent before the run, keeping new\nsuite `.env` targets absent at rest. If it does not, report or fix the lifecycle\ngap within the authorized scope; preserve pre-existing user files.\n\nInspect each consumer before choosing a target. Never target `.runtime\u002Fenvsets`,\nthe envset source directory itself, or a personal source checkout merely because\nan existing environment variable points there. `capture_feature_env_files`\ndefaults an omitted target to `sourcePath`; pass an explicit consumer target when\nimporting values from elsewhere. Existing paths are evidence, not authority.\n\nNever create pointer-only envsets that outsource their values to an unmanaged env\nfile. Capture the actual values and update their launcher\u002Fconfiguration together.\nKeep separate slots for genuine file inputs (certificates, binary bundles, JSON)\nwhen their consumer requires that format; verify reference and target together.\nDo not flatten every suite into one slot or encode files as environment variables\njust for uniformity. For an all-suites request, inspect every suite and correct\nonly bad mappings, preserving the working variants and existing values.\n\nVerify source → target → consumer and teardown before declaring a migration done.\nKeep secrets out of chat, logs, and commits. Do not invent `.recovery` trees or\nduplicate credentials as a precaution; retain the original until its replacement\nworks, and let the runner manage its existing backup\u002Frestore lifecycle. The full\ncontract is also available through `get_workflow_guide(workflow:\"author\")`.\n\n## Guardrails\n\n- Write one variable declaration per statement, use descriptive names, and clearly\n  separate setup, action, and assertions. Avoid comma expressions and nested\n  conditionals. Draft acceptance splits ordinary grouped declarations and formats\n  specs; it rejects syntax errors and comma expressions and reports nested\n  conditionals for review. Preserve behavior while resolving any finding.\n- Audit existing tests with `canary-lab test-readability \u003Cfile-or-directory>`;\n  add `--fix` for safe declaration fixes and formatting, or `--rules-only` to keep\n  existing layout. Review the diff and rerun affected tests. Never weaken assertions\n  or rewrite recorded run artifacts during cleanup.\n- Keep the same `session_id` for the whole conversation.\n- Test titles are read by non-engineers in the coverage ledger and exported\n  reports: write each as a plain-English sentence naming the user-visible\n  behavior — `user can reset their password after requesting a reset link`,\n  not `POST \u002Freset-token returns 200`. Keep a technical term only when it is\n  the requirement's own vocabulary (an endpoint name in an API-contract\n  requirement stays technical).\n- Canary Lab never writes the test body for external authoring — this client does.\n- **A suite declares ONE roster of tests, and every run of it declares the same\n  one.** Playwright builds that roster by walking the suite with the config's\n  selection fields applied, before the first test starts, and that walk is the\n  run's evidence. A config that narrows it by environment does not hide tests\n  from a run — it deletes them from the record: a `meta` run of a 45-test suite\n  reports a 4-test suite, the other 41 absent rather than \"not run\", and two runs\n  of one suite can no longer be compared. `test.skip(condition, reason)` keeps\n  the roster whole; a `testMatch` filter destroys it at the source. Canary Lab\n  refuses both the draft that carries such a config and any run of the suite.\n- After authoring, the natural next steps live in sibling skills: map coverage (`canary-lab-coverage`), run + heal (`canary-lab-run`), export the evaluation (`canary-lab-export`). **Running the new test** needs `start_run`: on the setup\u002Fplugin `compact` connection, invoke it as the `exec` command and follow `canary-lab-run`. On an intentionally narrow direct `--profile author` connection it is unavailable; reconnect with `npx canary-lab mcp --profile compact` and then run.\n","# Canary Lab — Feature Authoring\n\n## MCP Invocation\n\nSetup and the plugin expose one public Canary Lab MCP tool: `exec` (usually\nrendered as `mcp__Canary_Lab__exec`). Every\nCanary Lab tool name below is the exact `command` value, not a separate public\ntool. For a feature-scoped command, replace both placeholders in this shape:\n\n```json\n{\"command\":\"\u003Cexact_tool_name>\",\"arguments\":{\"feature\":\"\u003Cfeature_name>\"}}\n```\n\nThis is the envelope shape, not every command's complete schema. Add the\nfields that command declares inside `arguments`; call `describe_tool` when a\nfield is uncertain.\n\nNever invent a wrapper verb such as `learn` or `call`, embed JSON in a command\nstring, or turn arguments into flags. Keep fields such as `confirm: true` inside\n`arguments`. Use `list_tools`, `search_tools`, or `describe_tool` as the\n`command` when discovery is needed. A deliberately selected focused or `full`\nprofile still exposes atomic tools for debugging; the setup-installed path is\n`compact` + `exec`.\n\nThis client writes the specs; Canary Lab is the control plane and artifact\nstore. These tools arrive via the Canary Lab MCP server. If this client is\nalready connected (the plugin connects with `compact`), skip this step. To\nconfigure the same connection manually: `npx canary-lab mcp --profile compact`.\n\n## Arguments\n\nAn invocation argument (`\u002Fcanary-lab-author \u003Csuite>` — the Getting Started\nguide's \"Author Tests\" card emits exactly this shape) is the name of an\nEXISTING suite (feature) in the connected workspace. Follow the\n**extend-an-existing-feature** path below — never `create_feature` for it,\nand never rename it to dodge a collision.\n\n## Workspace Bootstrap\n\n1. Find the LIVE server first: read `~\u002F.canary-lab\u002Factive-servers.json`, which records `projectRoot`, `port` and `pid` for 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 its `port`. Several → take the one whose `projectRoot` is the workspace the user means. None → fall back to `~\u002F.canary-lab\u002Fworkspaces.json` (Windows: `%USERPROFILE%\\.canary-lab\\workspaces.json`): one workspace → use it, several → ask which, none → ask the user to run `npx canary-lab setup`. Do NOT start from a guessed port.\n2. Then CONFIRM it is the right server: `curl -s http:\u002F\u002F127.0.0.1:\u003Cport>\u002Fmcp\u002Fhealth` and check that `projectRoot` is 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. `projectRoot` matches 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 (`\u002Ftmp`, `\u002Fprivate\u002Fvar\u002Ffolders`, `%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.\n3. If the health check fails, start `npx canary-lab ui` from the workspace in a visible long-running terminal; if this client cannot run long-lived commands, ask the user to run `npx canary-lab ui` from the workspace and confirm when it's up.\n4. Do not reflexively call `list_features` or `list_runs` after health. For random or new feature creation, call `create_feature` directly with a unique feature name; use `list_features` only to discover or choose an existing feature.\n5. A healthy `\u002Fmcp\u002Fhealth` means the server is live. On the setup-installed `compact` profile, atomic names such as `get_feature_coverage` are deliberately absent from `tools\u002Flist`; only `exec` is public. Call `exec` with `{\"command\":\"list_tools\",\"arguments\":{}}` before concluding the connection is missing. Only an unknown-tool error for `exec` means this session is not connected — ask the user to run `npx canary-lab setup --force` and reconnect\u002Frestart the client, then retry. Never drive `\u002Fmcp` with a hand-written HTTP\u002FJSON-RPC client (curl included; the health check above is the only direct HTTP use): a custom client bypasses client detection and reconnect handling.\n\n## Create or Extend a Feature\n\n1. Pick the path by what the request names:\n   - **Extending an EXISTING feature** (\"author tests for \u003Cfeature>\", \"add a test for the missing behavior\"): do NOT call `create_feature` — the feature and its skeleton already exist. To choose WHAT to test, `get_feature_coverage(feature)` names the untested \u002F path-incomplete requirements (that IS the \"choose a gap\" step), and `list_feature_docs(feature)` points at the requirement docs behind them. Author the new spec straight into `\u003Cworkspace>\u002Ffeatures\u002F\u003Cfeature>\u002Fe2e\u002F`, and tag it with the requirement it covers — `test('…', { tag: ['@req-R2'] }, …)` — so the gap actually closes in the coverage ledger.\n   - **Creating a NEW feature**: call `create_feature` directly with a unique feature name. It creates the skeleton files and returns test-file rules, envset schema, and next-step tool hints. Do not call `list_features` just to avoid collisions; if the name you INVENTED already exists, retry `create_feature` with a different unique name — but never rename away from a feature the user asked for (that is the extending path above).\n2. If the user asks to preserve existing `.env`, `.env.dev`, `application.properties`, or similar repo config files, inspect the source repo enough to identify the files, then call `capture_feature_env_files`. Do not paste secret values into chat; Canary Lab returns redacted previews only. `write_envset` fills in or corrects individual envset values (it is confirm-gated).\n3. Author or edit specs under `\u003Cworkspace>\u002Ffeatures\u002F\u003Cfeature>\u002Fe2e\u002F` — the Canary Lab WORKSPACE, not the product repo under test.\n   **Spec selection never depends on the envset.** In the suite's\n   `playwright.config.*`, keep `testDir`, `testMatch`, `testIgnore`, `grep` and\n   `grepInvert` as constant literals — never derived from\n   `CANARY_LAB_MANIFEST_PATH`, `process.env`, or the recorded env. A test that\n   must not execute in some environment skips ITSELF at runtime:\n   `test.skip(process.env.VERIFICATION_ENV !== 'meta', 'needs the Meta sandbox')`,\n   reading the env from the envset's own values rather than the manifest. See\n   Guardrails for why.\n4. Specs must import:\n   ```ts\n   import { test, expect } from 'canary-lab\u002Ffeature-support\u002Flog-marker-fixture'\n   ```\n5. Call `start_external_draft` with a stable `session_id` and a useful `conversation_name` (do not pass `client_kind` — the bridge auto-detects it). This only creates a visible Canary Lab task so the user sees that this external agent session is authoring tests; it does not start an internal wizard agent. Carry the `draftId` it returns into every subsequent `update_external_draft_stage` \u002F `apply_external_draft` call for this draft. If it returns `type: \"getting_started_busy\"`, a Getting Started demo already owns the workspace — follow the active target it returns; do not start another workflow.\n6. After `start_external_draft` returns, tell the user you are authoring tests and they can follow along live in the Canary Lab UI: the suite's Flight page shows this work on its Test authoring & coverage stage (that view is read-only while this client drives — it monitors, you act here). Continue writing specs locally, then call `update_external_draft_stage(draftId, stage)` as work progresses: `scaffolding`, `authoring-tests`, `validating`, `ready`, `applied`, or `error`.\n7. Call `apply_external_draft` with `draftId`, `confirm: true`, and `files: [{path, content}, …]` for the externally authored files (omit `files` if you already wrote them directly under `\u003Cworkspace>\u002Ffeatures\u002F\u003Cfeature>\u002Fe2e\u002F` — it then validates what's on disk), so Canary Lab validates and records the applied draft. Do not ask Canary Lab to spawn another Claude\u002FCodex agent for MCP-created authoring. On a validation error, fix the named file and re-call `apply_external_draft`.\n8. `get_feature_repo_status` \u002F `checkout_feature_repo_branch` inspect and switch the feature's bound repo branches when the user asks to test a different branch. The status also reports where the pinned branch stands against its upstream (`upstreamSha`, `behindUpstream`, `aheadUpstream`); when it is behind, `update_feature_repo_branch(feature, repo, confirm: true)` fast-forwards the checkout to the upstream tip so the next run boots the latest commit. It refuses — and changes nothing — when the checkout is dirty, detached, on another branch, or has diverged; report the reason and let the user reconcile rather than discarding their work. A repo declared with `track: 'upstream'` in `feature.config.cjs` is fast-forwarded automatically at every run start.\n\n## Envset source and target\n\nStore actual values in the selected workspace at\n`features\u002F\u003Cfeature>\u002Fenvsets\u002F\u003Cenv>\u002F\u003Cslot>`. A suite that reads `.env` normally uses\n`envsets\u002Flocal\u002F\u003Cfeature>.env` with target\n`$CANARY_LAB_PROJECT_ROOT\u002Ffeatures\u002F\u003Cfeature>\u002F.env`. The envset file is the durable\nsource; the target is the temporary file the launcher and Playwright consume.\nThe runner applies it before startup and restores backed-up targets at teardown.\nVerify that teardown also removes targets absent before the run, keeping new\nsuite `.env` targets absent at rest. If it does not, report or fix the lifecycle\ngap within the authorized scope; preserve pre-existing user files.\n\nInspect each consumer before choosing a target. Never target `.runtime\u002Fenvsets`,\nthe envset source directory itself, or a personal source checkout merely because\nan existing environment variable points there. `capture_feature_env_files`\ndefaults an omitted target to `sourcePath`; pass an explicit consumer target when\nimporting values from elsewhere. Existing paths are evidence, not authority.\n\nNever create pointer-only envsets that outsource their values to an unmanaged env\nfile. Capture the actual values and update their launcher\u002Fconfiguration together.\nKeep separate slots for genuine file inputs (certificates, binary bundles, JSON)\nwhen their consumer requires that format; verify reference and target together.\nDo not flatten every suite into one slot or encode files as environment variables\njust for uniformity. For an all-suites request, inspect every suite and correct\nonly bad mappings, preserving the working variants and existing values.\n\nVerify source → target → consumer and teardown before declaring a migration done.\nKeep secrets out of chat, logs, and commits. Do not invent `.recovery` trees or\nduplicate credentials as a precaution; retain the original until its replacement\nworks, and let the runner manage its existing backup\u002Frestore lifecycle. The full\ncontract is also available through `get_workflow_guide(workflow:\"author\")`.\n\n## Guardrails\n\n- Write one variable declaration per statement, use descriptive names, and clearly\n  separate setup, action, and assertions. Avoid comma expressions and nested\n  conditionals. Draft acceptance splits ordinary grouped declarations and formats\n  specs; it rejects syntax errors and comma expressions and reports nested\n  conditionals for review. Preserve behavior while resolving any finding.\n- Audit existing tests with `canary-lab test-readability \u003Cfile-or-directory>`;\n  add `--fix` for safe declaration fixes and formatting, or `--rules-only` to keep\n  existing layout. Review the diff and rerun affected tests. Never weaken assertions\n  or rewrite recorded run artifacts during cleanup.\n- Keep the same `session_id` for the whole conversation.\n- Test titles are read by non-engineers in the coverage ledger and exported\n  reports: write each as a plain-English sentence naming the user-visible\n  behavior — `user can reset their password after requesting a reset link`,\n  not `POST \u002Freset-token returns 200`. Keep a technical term only when it is\n  the requirement's own vocabulary (an endpoint name in an API-contract\n  requirement stays technical).\n- Canary Lab never writes the test body for external authoring — this client does.\n- **A suite declares ONE roster of tests, and every run of it declares the same\n  one.** Playwright builds that roster by walking the suite with the config's\n  selection fields applied, before the first test starts, and that walk is the\n  run's evidence. A config that narrows it by environment does not hide tests\n  from a run — it deletes them from the record: a `meta` run of a 45-test suite\n  reports a 4-test suite, the other 41 absent rather than \"not run\", and two runs\n  of one suite can no longer be compared. `test.skip(condition, reason)` keeps\n  the roster whole; a `testMatch` filter destroys it at the source. Canary Lab\n  refuses both the draft that carries such a config and any run of the suite.\n- After authoring, the natural next steps live in sibling skills: map coverage (`canary-lab-coverage`), run + heal (`canary-lab-run`), export the evaluation (`canary-lab-export`). **Running the new test** needs `start_run`: on the setup\u002Fplugin `compact` connection, invoke it as the `exec` command and follow `canary-lab-run`. On an intentionally narrow direct `--profile author` connection it is unavailable; reconnect with `npx canary-lab mcp --profile compact` and then run.\n",{"name":5,"type":52,"description":7},"skill","main","2c85305cab69e5f773d59ea79a64a0b049a98345","agent-integrations\u002Fcodex\u002Fskills\u002Fcanary-lab-author",0,"https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab","https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fcanary-lab","https:\u002F\u002Fgithub.com\u002Fferterahadi","https:\u002F\u002Fgithub.com\u002Fferterahadi-oddle","Shipping well-tested, production-ready, vibe-coded code using today’s latest form of engineering - harness, agentic, loop, graph, or whatever drops next","2026-11-05 11:59:56",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add ferterahadi\u002Fcanary-lab --skill canary-lab-author",{"tool":69,"command":70},"bunx","bunx skills add ferterahadi\u002Fcanary-lab --skill canary-lab-author",{"tool":72,"command":73},"pnpm","pnpm dlx skills add ferterahadi\u002Fcanary-lab --skill canary-lab-author","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fagent-integrations\u002Fcodex\u002Fskills\u002Fcanary-lab-author\u002FSKILL.md",true,[77],{"path":78,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":81,"sourceHtmlUrl":82},"agents\u002Fopenai.yaml","REFERENCE","参考文档",205,"https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fagent-integrations\u002Fcodex\u002Fskills\u002Fcanary-lab-author\u002Fagents\u002Fopenai.yaml",[84,93,103,120,142,158],{"skillNo":85,"name":86,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":91,"publishedAt":47},"01M6XCWFJ75NNVF0N8C0XGNC17","off-by-one","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fapps\u002Fweb-server\u002Fprompts\u002Fsabotage-skills\u002Foff-by-one\u002Fskill.md",[89,90],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[92],"off by one",{"skillNo":94,"name":95,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":100,"publishedAt":47},"01M6XCWBYW1QHVFKSDQCCRRRDT","multi-failure-cascade","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fapps\u002Fweb-server\u002Fprompts\u002Fsabotage-skills\u002Fmulti-failure-cascade\u002Fskill.md",[98,99],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[101,102],"multi","multi failure cascade",{"skillNo":104,"name":105,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":115,"publishedAt":47},"01M6XCW8XA7QY74Q18D9PGFFMD","broken-delete-contract","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fapps\u002Fweb-server\u002Fprompts\u002Fsabotage-skills\u002Fbroken-delete-contract\u002Fskill.md",[108,109,110],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":111,"categoryName":112,"taxonomyType":113,"taxonomyTypeDesc":114},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[116,117,118,119],"delete","broken","contract","broken delete contract",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":128,"publishedAt":47},"01M6XCW439KA486AN2QZACNYTC","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 \u002F get_flight \u002F 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 \u002Fcanary-lab.","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fagent-integrations\u002Fplugin\u002Fcanary-lab\u002Fskills\u002Fcanary-lab\u002FSKILL.md",[126,127],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[30,29,129,130,131,132,133,134,135,37,136,137,138,139,140,33,32,43,38,141],"canary lab","capability","pipeline","work","only","take","green","end","app","respond","suite","product","run",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":150,"publishedAt":47},"01M6XCVYQ31KC4ZXCD5QMRKXEE","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\u002Fget\u002Fcreate\u002Fupdate_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).","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fagent-integrations\u002Fplugin\u002Fcanary-lab\u002Fskills\u002Fcanary-lab-verify\u002FSKILL.md",[148,149],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[29,151,30,152,129,37,38,153,45,141,44,154,42,155,156,136,137,35,157,32],"verify","canary lab verify","config","verification","loop","list","result",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":169,"publishedAt":47},"01M6XCVSWW705CN3C69FQMPZXN","canary-lab-run","Use when running or healing an EXISTING Canary Lab feature locally — \"run \u003Cfeature>\", \"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\u002Fservice code, not tests. For end-to-end onboarding of a new repo use canary-lab (flight); for deployed-environment checks use canary-lab-verify.","https:\u002F\u002Fgithub.com\u002Fferterahadi\u002Fcanary-lab\u002Fblob\u002Fmain\u002Fagent-integrations\u002Fplugin\u002Fcanary-lab\u002Fskills\u002Fcanary-lab-run\u002FSKILL.md",[164,165,166],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":167,"categoryName":168,"taxonomyType":113,"taxonomyTypeDesc":114},"01JBSEEDCAT000000000000030","开发工程师",[170,129,141,29,30,136,37,171,172,155,42,43,173,38,32,174,175,137,176,177],"canary lab run","fix","context","code","rerun","wait","new repo","failing"]