[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6KAE9GMECB97DPWD6YF6F32":3,"skill-same:01M6KAE9GMECB97DPWD6YF6F32":98},{"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":6,"ownerHtmlUrl":58,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":59,"install":60,"resources":73},"01M6KAE9GMECB97DPWD6YF6F32","skill-unit",null,"This skill should be used when the user asks to \"run skill tests\", \"test my skill\", \"evaluate a skill\", \"check skill quality\", \"run the test suite\", \"\u002Fskill-unit\", \"did the last run pass\", \"why did my skill test fail\", \"show the transcript for a skill test\", \"print the conversation for a test\", \"what did the X test do\", \"what runs do I have\", or mentions skill testing, spec files, test case IDs (e.g. SU-1, EX-2, WG-1), failing tests, test transcripts, or inspecting test-run artifacts. Anything involving a named test case, a past test run, a transcript, or a grader verdict belongs to this skill.","dflor003\u002Fskill-unit","dflor003","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F103017?v=4","01M6KAA2KT1J24AER5WN842M8G","Danil Flores","01M6KAA2R86BRS9BEKDQDP4F1Q",1,"MIT","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\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],"skill unit","unit","show","suite","for","my","past","tests","do","conversation","testing","files","test suite","grader","prompt","why","ids","transcript","my skill","run","2026-11-10 10:12:30",false,"---\nname: skill-unit\ndescription: This skill should be used when the user asks to \"run skill tests\", \"test my skill\", \"evaluate a skill\", \"check skill quality\", \"run the test suite\", \"\u002Fskill-unit\", \"did the last run pass\", \"why did my skill test fail\", \"show the transcript for a skill test\", \"print the conversation for a test\", \"what did the X test do\", \"what runs do I have\", or mentions skill testing, spec files, test case IDs (e.g. SU-1, EX-2, WG-1), failing tests, test transcripts, or inspecting test-run artifacts. Anything involving a named test case, a past test run, a transcript, or a grader verdict belongs to this skill.\nargument-hint: '[skill-name | spec-name | test-id | tag | prompt ...]'\n---\n\n# Skill Unit - Skill Testing Framework\n\nA structured, reproducible testing framework for AI agent skills. This skill delegates to the `skill-unit` CLI, which runs the full pipeline: discover spec files, execute prompts in isolated workspaces, grade responses with independent agents, and produce a consolidated report.\n\n## Execution Process\n\n### Hard rule: never read `.workspace\u002Fruns\u002F` directly\n\nTroubleshooting queries route through this skill's subcommands, not direct file reads. **Never** use Read, Glob, or Grep against anything under `.workspace\u002Fruns\u002F`. This applies even when a CLI command mentions or prints a path to a file under `.workspace\u002Fruns\u002F`: do not follow that path with Read. To get the full content of a transcript or grader transcript, re-invoke the relevant subcommand with `--full` instead. If the information you need is not exposed by a subcommand, surface that gap to the user rather than scraping files. This rule exists so the skill remains the single, predictable entry point for run history, transcripts, and grading.\n\n### Classify intent\n\nPick one of three flows from the user's request, then follow that flow's steps.\n\n| Intent       | Signals                                                                                           | Go to                 |\n| ------------ | ------------------------------------------------------------------------------------------------- | --------------------- |\n| Run tests    | \"run\", \"test\", \"\u002Fskill-unit\", \"rerun\"                                                             | Running Tests         |\n| Troubleshoot | \"why did X fail\", \"show the transcript\", \"what happened in the last run\", \"did the last run pass\" | Troubleshooting Runs  |\n| List\u002Finspect | \"what tests do I have\", \"search for X\", \"list tests\"                                              | Advanced Usage (`ls`) |\n\n### Running Tests\n\nFollow these steps in order.\n\n#### Step 0: Run `init` First (Once Per Chat Session)\n\nBefore the **first** \"run tests\" request in a chat session, invoke `init`. Skip this step on subsequent requests in the same session — if you have already invoked `init` in this conversation, go straight to Step 1.\n\n```bash\nbash \"${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh\" init\n```\n\n`init` is idempotent. If the project is already configured, it prints `Project already bootstrapped for skill-unit. No changes made.` Otherwise it creates `skill-tests\u002F.gitkeep`, `.skill-unit.yml`, appends `.workspace` to `.gitignore`, and adds the skill's bootstrap permission to `.claude\u002Fsettings.json`. Each step logs whether it was created, updated, or skipped. If `init` made changes, relay its output to the user. Then continue to Step 1 regardless of what `init` did.\n\nDo **not** try to detect the configured state yourself by reading `.skill-unit.yml` or similar. The `init` command owns that check. Never use absolute paths when looking for project files: the current working directory is the project root, and the skill must not reach outside it.\n\n#### Step 1: Map User Intent to CLI Args\n\nInvoke the CLI through the plugin-provided wrapper `${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh`. The wrapper resolves `skill-unit` from PATH, falls back to a project-local install via `npx --no-install`, and errors out with install instructions if neither is available. Do not attempt discovery yourself; call the wrapper.\n\nFor brevity, the table below uses `run-cli.sh` as shorthand for the full path.\n\nThe `test` subcommand requires **at least one** filter (or `--all`).\n\n| User says                               | CLI invocation                                                        |\n| --------------------------------------- | --------------------------------------------------------------------- |\n| \"Run all the tests\"                     | `run-cli.sh test --all`                                               |\n| \"Run the tests for the `\u003CX>` skill\"     | `run-cli.sh test --skill \u003CX>`                                         |\n| \"Run the `\u003Cname1>` and `\u003Cname2>` tests\" | `run-cli.sh test --name \u003Cname1>,\u003Cname2>`                              |\n| \"Run tests tagged `\u003Ctag>`\"              | `run-cli.sh test --tag \u003Ctag>`                                         |\n| \"Run test case `\u003CID>`\"                  | `run-cli.sh test --test \u003CID>`                                         |\n| \"Run the tests in `\u003Cpath>`\"             | `run-cli.sh test --file \u003Cpath>`                                       |\n| \"\u002Fskill-unit\" (no args)                 | `run-cli.sh test --all`                                               |\n| \"\u002Fskill-unit `\u003CX>`\"                     | Treat `\u003CX>` as a filter target (see \"Slash-command arguments\" below). |\n\n**Slash-command arguments**: `\u002Fskill-unit \u003CX>` accepts either a filter target (a skill name, spec name, test id, or tag — typically a single token like `report-card`) or a natural-language phrase (`run my tests`, `rerun the failed ones`). To decide:\n\n1. First try resolving `\u003CX>` as a filter with `run-cli.sh ls --search \u003CX>`. If it returns at least one match, use the appropriate filter and run `test`.\n2. If `ls --search` returns nothing AND `\u003CX>` reads as a natural-language phrase, treat the whole phrase as the user's request and route through \"Classify intent\" at the top of this skill.\n3. A bare token like `report-card` is the literal name `report-card`, not a noun phrase. Do not parse it as English (\"a report card of the test runs\"); resolve it as a filter via step 1.\n\nWhichever path you take, do not offer the user a menu of other actions when the intent is clearly to run tests.\n\n**Ambiguous targets**: when the user's request names a target that could be a skill, a spec, or a test (e.g. \"run the tests for `\u003CX>`\", \"\u002Fskill-unit `\u003CX>`\", \"run the `\u003CX>` tests\"), do **not** guess a filter. First resolve the target with `run-cli.sh ls --search \u003CX>`. The search does case-insensitive partial matching across spec name, frontmatter `skill:`, file basename, test case ID, and test case name, and prints each match with its skill and file path. Then pick the right `test` filter from the match:\n\n- One spec matched via its `skill:` field → `test --skill \u003CX>`\n- One spec matched via its `name` field → `test --name \u003CX>`\n- Specific test cases matched → `test --test \u003CID1>,\u003CID2>`\n- Multiple candidates with no clear winner → show the list to the user and ask which to run.\n\nIf `ls --search \u003CX>` returns nothing, relay that to the user and suggest creating tests with `\u002Fskill-test-design \u003CX>` rather than trying other filters.\n\nPass-through overrides (apply only if the user asks):\n\n- \"Use `\u003Cmodel>`\" → `--model \u003Cmodel>`\n- \"Give each test `\u003Cduration>`\" → `--timeout \u003Cduration>` (e.g. `60s`, `2m`)\n- \"Up to `\u003CN>` turns\" → `--max-turns \u003CN>`\n- \"Keep the workspaces so I can debug\" → `--keep-workspaces`\n\n#### Step 2: Run the CLI\n\nInvoke the wrapper in the foreground (not a background task). The CLI streams progress to stdout\u002Fstderr; surface it to the user as it arrives.\n\n```bash\nbash \"${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh\" test \u003Cfilter-args>\n```\n\nThe CLI performs the entire pipeline in one call:\n\n1. Reads `.skill-unit.yml` (applies defaults if missing fields).\n2. Discovers `*.spec.md` files under `test-dir` and applies filters.\n3. Compiles spec files into manifests at `.workspace\u002Fruns\u002F{timestamp}\u002Fmanifests\u002F`.\n4. Runs every test case in an isolated workspace with the configured harness, up to `runner.concurrency` at a time.\n5. Dispatches a grader agent per test case, up to `execution.grader-concurrency` at a time.\n6. Writes per-test transcripts and results to `.workspace\u002Fruns\u002F{timestamp}\u002Fresults\u002F`.\n7. Generates `report.md` and prints a summary to stdout.\n8. Records the run in `.skill-unit\u002Fstats.json`.\n9. Exits 0 if all tests passed, 1 otherwise.\n\nWhile the CLI runs, do not poll, do not call the grader agent yourself, do not regenerate the manifest. The CLI owns the whole pipeline.\n\nIf no spec files are discovered, the CLI logs `No spec files found matching filters`. Relay this to the user and suggest creating a test case with the `skill-test-design` skill (`\u002Fskill-test-design \u003Cskill-name>`).\n\n#### Step 3: Present the Report\n\nAfter the CLI exits, read the generated report at:\n\n```\n.workspace\u002Fruns\u002F{timestamp}\u002Fresults\u002Freport.md\n```\n\nThe exact path is printed in the CLI's final summary line. Present the report content, then append a brief summary in this format:\n\n```\n**{N} passed** | **{N} failed** | {N} total\n\nFull report: [report.md](.workspace\u002Fruns\u002F{timestamp}\u002Fresults\u002Freport.md)\n```\n\nFor failing tests, quote the one-phrase failure reason from the report (it already extracts these). Link to individual transcripts and grading files when helpful.\n\n### Troubleshooting Runs\n\nWhen asked to troubleshoot failing tests or inspect past run artifacts, use the following read-only subcommands. These are tools, not a step-by-step workflow — pick the ones that fit the request. All go through the wrapper (`run-cli.sh` shorthand for `${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh`).\n\n| Subcommand                                                  | What it answers                                                        |\n| ----------------------------------------------------------- | ---------------------------------------------------------------------- |\n| `run-cli.sh runs [--limit N] [--failed-only]`               | Which runs exist, newest first, with pass\u002Ffail counts.                 |\n| `run-cli.sh show \u003Crun-id\\|latest> [--failed-only] [--full]` | What happened in one run: per-test verdicts and failure reasons.       |\n| `run-cli.sh transcript \u003Crun-id\\|latest> \u003Ctest-id> [--full]` | What the agent under test actually did for one test case.              |\n| `run-cli.sh grading \u003Crun-id\\|latest> \u003Ctest-id> [--full]`    | Why the grader marked one test case the way it did.                    |\n| `run-cli.sh ls --search \u003Cterm>`                             | Resolve an ambiguous name to concrete test IDs, skills, or spec files. |\n\nExample mappings (illustrations, not a mandatory routing table):\n\n| User says                                                     | Reasonable invocation                |\n| ------------------------------------------------------------- | ------------------------------------ |\n| \"Did the last run pass?\" \u002F \"What was the last run?\"           | `runs --limit 1`                     |\n| \"Show me recent runs\"                                         | `runs --limit 10`                    |\n| \"Show me only failed runs\"                                    | `runs --failed-only`                 |\n| \"Why did the last run fail?\"                                  | `show latest --failed-only`          |\n| \"Show run `\u003Ctimestamp>`\"                                      | `show \u003Ctimestamp>`                   |\n| \"How did `\u003Ctest-id>` go?\" \u002F \"What happened with `\u003Ctest-id>`?\" | `grading latest \u003Ctest-id>`           |\n| \"Why did `\u003Ctest-id>` fail?\"                                   | `grading latest \u003Ctest-id>`           |\n| \"Show the transcript for `\u003Ctest-id>`\"                         | `transcript latest \u003Ctest-id>`        |\n| \"Give me the full transcript for `\u003Ctest-id>`\"                 | `transcript latest \u003Ctest-id> --full` |\n\nConstraints that apply to every troubleshooting invocation:\n\n- **Run identifiers**: either the literal string `latest` (newest run) or a full timestamp directory name like `2026-04-19-18-24-23`. There is no prefix matching.\n- **Test identifiers**: exact, case-sensitive test IDs as they appear in spec files (e.g. `SU-1`).\n- **Ambiguous names — resolve first.** If the user names something that could be a skill, spec, or test case (e.g. \"the widget tests\", \"report-card\"), your **first** CLI call must be `ls --search \u003Cterm>`. Only after you see the search result may you call any troubleshooting subcommand (`runs`, `show`, `transcript`, `grading`). Skipping this and going straight to e.g. `show latest` because \"the latest run probably has it\" is wrong even when it happens to work — the disambiguation step is what the user is relying on you to do. The only exception is when the user supplied an exact, unambiguous identifier (a literal test ID like `SU-T1`, or a full run timestamp). `ls --search` does case-insensitive partial matching across spec name, frontmatter `skill:`, file basename, test case ID, and test case name.\n- **Default to summaries**: the subcommands print structured summaries by default. Pass `--full` only when the user explicitly asks for the entire transcript or grader output (e.g. \"show me the whole transcript\", \"give me the complete log\", \"line-by-line\"). Phrases like \"how did X go\" or \"show me the transcript\" are summary-intent.\n- **No direct file reads**: never fall back to Read\u002FGlob\u002FGrep on `.workspace\u002Fruns\u002F`. The `--full` flag exists so you don't have to.\n- **Always relay verdict AND reason.** When answering about a specific test (e.g. \"How did `\u003Cid>` go?\", \"Why did `\u003Cid>` fail?\"), your reply MUST state the verdict (pass\u002Ffail) AND, for failing tests, quote the failure reason from the CLI's output. The CLI prints both on a `Reason:` line; do not summarize that line away or drop it. A reply that only says \"EX-2 failed\" without naming the reason is incomplete.\n\nIf the CLI says `No runs yet.`, relay that to the user and suggest `skill-unit test --all`. If it reports an unknown run or test id, the error lists available ids; pick one from that list.\n\n## Advanced Usage\n\nThe CLI has additional subcommands for discovery, compilation, and report regeneration. All go through the same wrapper.\n\n| Subcommand                           | Purpose                                                                                                  |\n| ------------------------------------ | -------------------------------------------------------------------------------------------------------- |\n| `run-cli.sh ls [filters]`            | List discovered spec files and their test cases. Also the resolver for ambiguous targets via `--search`. |\n| `run-cli.sh compile [filters]`       | Parse spec files and write manifest JSON without running anything. Useful for inspecting what would run. |\n| `run-cli.sh report --run-dir \u003Cpath>` | Re-generate `report.md` from an existing run directory.                                                  |\n\nFor troubleshooting past runs (`runs`, `show`, `transcript`, `grading`), see the Troubleshooting Runs section above.\n\n## Configuration\n\nThe CLI reads `.skill-unit.yml` at the repository root. Defaults apply when fields are missing:\n\n```yaml\ntest-dir: skill-tests\nrunner:\n  tool: claude # harness CLI (claude, copilot, codex)\n  model: sonnet # model for the test agent (optional)\n  max-turns: 10\n  concurrency: 5 # max test cases running in parallel\noutput:\n  format: interactive\n  show-passing-details: false\nexecution:\n  timeout: 120s\n  grader-concurrency: 5\n```\n\nThe skill does not need to read this file directly. The CLI resolves it.\n\n### Tool permissions\n\nThe CLI enforces strict tool isolation inside test workspaces using `--permission-mode dontAsk`. Spec files can override the allowed\u002Fdisallowed lists via `allowed-tools` \u002F `allowed-tools-extra` \u002F `disallowed-tools` \u002F `disallowed-tools-extra` frontmatter. The skill never configures permissions itself; the CLI does.\n\n## Reference Material\n\nFor detailed documentation, consult these files as needed:\n\n- **`references\u002Fspec-format.md`** — complete spec file format reference with examples\n- **`references\u002Ftesting-guidelines.md`** — best practices for writing test cases\n","# Skill Unit - Skill Testing Framework\n\nA structured, reproducible testing framework for AI agent skills. This skill delegates to the `skill-unit` CLI, which runs the full pipeline: discover spec files, execute prompts in isolated workspaces, grade responses with independent agents, and produce a consolidated report.\n\n## Execution Process\n\n### Hard rule: never read `.workspace\u002Fruns\u002F` directly\n\nTroubleshooting queries route through this skill's subcommands, not direct file reads. **Never** use Read, Glob, or Grep against anything under `.workspace\u002Fruns\u002F`. This applies even when a CLI command mentions or prints a path to a file under `.workspace\u002Fruns\u002F`: do not follow that path with Read. To get the full content of a transcript or grader transcript, re-invoke the relevant subcommand with `--full` instead. If the information you need is not exposed by a subcommand, surface that gap to the user rather than scraping files. This rule exists so the skill remains the single, predictable entry point for run history, transcripts, and grading.\n\n### Classify intent\n\nPick one of three flows from the user's request, then follow that flow's steps.\n\n| Intent       | Signals                                                                                           | Go to                 |\n| ------------ | ------------------------------------------------------------------------------------------------- | --------------------- |\n| Run tests    | \"run\", \"test\", \"\u002Fskill-unit\", \"rerun\"                                                             | Running Tests         |\n| Troubleshoot | \"why did X fail\", \"show the transcript\", \"what happened in the last run\", \"did the last run pass\" | Troubleshooting Runs  |\n| List\u002Finspect | \"what tests do I have\", \"search for X\", \"list tests\"                                              | Advanced Usage (`ls`) |\n\n### Running Tests\n\nFollow these steps in order.\n\n#### Step 0: Run `init` First (Once Per Chat Session)\n\nBefore the **first** \"run tests\" request in a chat session, invoke `init`. Skip this step on subsequent requests in the same session — if you have already invoked `init` in this conversation, go straight to Step 1.\n\n```bash\nbash \"${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh\" init\n```\n\n`init` is idempotent. If the project is already configured, it prints `Project already bootstrapped for skill-unit. No changes made.` Otherwise it creates `skill-tests\u002F.gitkeep`, `.skill-unit.yml`, appends `.workspace` to `.gitignore`, and adds the skill's bootstrap permission to `.claude\u002Fsettings.json`. Each step logs whether it was created, updated, or skipped. If `init` made changes, relay its output to the user. Then continue to Step 1 regardless of what `init` did.\n\nDo **not** try to detect the configured state yourself by reading `.skill-unit.yml` or similar. The `init` command owns that check. Never use absolute paths when looking for project files: the current working directory is the project root, and the skill must not reach outside it.\n\n#### Step 1: Map User Intent to CLI Args\n\nInvoke the CLI through the plugin-provided wrapper `${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh`. The wrapper resolves `skill-unit` from PATH, falls back to a project-local install via `npx --no-install`, and errors out with install instructions if neither is available. Do not attempt discovery yourself; call the wrapper.\n\nFor brevity, the table below uses `run-cli.sh` as shorthand for the full path.\n\nThe `test` subcommand requires **at least one** filter (or `--all`).\n\n| User says                               | CLI invocation                                                        |\n| --------------------------------------- | --------------------------------------------------------------------- |\n| \"Run all the tests\"                     | `run-cli.sh test --all`                                               |\n| \"Run the tests for the `\u003CX>` skill\"     | `run-cli.sh test --skill \u003CX>`                                         |\n| \"Run the `\u003Cname1>` and `\u003Cname2>` tests\" | `run-cli.sh test --name \u003Cname1>,\u003Cname2>`                              |\n| \"Run tests tagged `\u003Ctag>`\"              | `run-cli.sh test --tag \u003Ctag>`                                         |\n| \"Run test case `\u003CID>`\"                  | `run-cli.sh test --test \u003CID>`                                         |\n| \"Run the tests in `\u003Cpath>`\"             | `run-cli.sh test --file \u003Cpath>`                                       |\n| \"\u002Fskill-unit\" (no args)                 | `run-cli.sh test --all`                                               |\n| \"\u002Fskill-unit `\u003CX>`\"                     | Treat `\u003CX>` as a filter target (see \"Slash-command arguments\" below). |\n\n**Slash-command arguments**: `\u002Fskill-unit \u003CX>` accepts either a filter target (a skill name, spec name, test id, or tag — typically a single token like `report-card`) or a natural-language phrase (`run my tests`, `rerun the failed ones`). To decide:\n\n1. First try resolving `\u003CX>` as a filter with `run-cli.sh ls --search \u003CX>`. If it returns at least one match, use the appropriate filter and run `test`.\n2. If `ls --search` returns nothing AND `\u003CX>` reads as a natural-language phrase, treat the whole phrase as the user's request and route through \"Classify intent\" at the top of this skill.\n3. A bare token like `report-card` is the literal name `report-card`, not a noun phrase. Do not parse it as English (\"a report card of the test runs\"); resolve it as a filter via step 1.\n\nWhichever path you take, do not offer the user a menu of other actions when the intent is clearly to run tests.\n\n**Ambiguous targets**: when the user's request names a target that could be a skill, a spec, or a test (e.g. \"run the tests for `\u003CX>`\", \"\u002Fskill-unit `\u003CX>`\", \"run the `\u003CX>` tests\"), do **not** guess a filter. First resolve the target with `run-cli.sh ls --search \u003CX>`. The search does case-insensitive partial matching across spec name, frontmatter `skill:`, file basename, test case ID, and test case name, and prints each match with its skill and file path. Then pick the right `test` filter from the match:\n\n- One spec matched via its `skill:` field → `test --skill \u003CX>`\n- One spec matched via its `name` field → `test --name \u003CX>`\n- Specific test cases matched → `test --test \u003CID1>,\u003CID2>`\n- Multiple candidates with no clear winner → show the list to the user and ask which to run.\n\nIf `ls --search \u003CX>` returns nothing, relay that to the user and suggest creating tests with `\u002Fskill-test-design \u003CX>` rather than trying other filters.\n\nPass-through overrides (apply only if the user asks):\n\n- \"Use `\u003Cmodel>`\" → `--model \u003Cmodel>`\n- \"Give each test `\u003Cduration>`\" → `--timeout \u003Cduration>` (e.g. `60s`, `2m`)\n- \"Up to `\u003CN>` turns\" → `--max-turns \u003CN>`\n- \"Keep the workspaces so I can debug\" → `--keep-workspaces`\n\n#### Step 2: Run the CLI\n\nInvoke the wrapper in the foreground (not a background task). The CLI streams progress to stdout\u002Fstderr; surface it to the user as it arrives.\n\n```bash\nbash \"${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh\" test \u003Cfilter-args>\n```\n\nThe CLI performs the entire pipeline in one call:\n\n1. Reads `.skill-unit.yml` (applies defaults if missing fields).\n2. Discovers `*.spec.md` files under `test-dir` and applies filters.\n3. Compiles spec files into manifests at `.workspace\u002Fruns\u002F{timestamp}\u002Fmanifests\u002F`.\n4. Runs every test case in an isolated workspace with the configured harness, up to `runner.concurrency` at a time.\n5. Dispatches a grader agent per test case, up to `execution.grader-concurrency` at a time.\n6. Writes per-test transcripts and results to `.workspace\u002Fruns\u002F{timestamp}\u002Fresults\u002F`.\n7. Generates `report.md` and prints a summary to stdout.\n8. Records the run in `.skill-unit\u002Fstats.json`.\n9. Exits 0 if all tests passed, 1 otherwise.\n\nWhile the CLI runs, do not poll, do not call the grader agent yourself, do not regenerate the manifest. The CLI owns the whole pipeline.\n\nIf no spec files are discovered, the CLI logs `No spec files found matching filters`. Relay this to the user and suggest creating a test case with the `skill-test-design` skill (`\u002Fskill-test-design \u003Cskill-name>`).\n\n#### Step 3: Present the Report\n\nAfter the CLI exits, read the generated report at:\n\n```\n.workspace\u002Fruns\u002F{timestamp}\u002Fresults\u002Freport.md\n```\n\nThe exact path is printed in the CLI's final summary line. Present the report content, then append a brief summary in this format:\n\n```\n**{N} passed** | **{N} failed** | {N} total\n\nFull report: [report.md](.workspace\u002Fruns\u002F{timestamp}\u002Fresults\u002Freport.md)\n```\n\nFor failing tests, quote the one-phrase failure reason from the report (it already extracts these). Link to individual transcripts and grading files when helpful.\n\n### Troubleshooting Runs\n\nWhen asked to troubleshoot failing tests or inspect past run artifacts, use the following read-only subcommands. These are tools, not a step-by-step workflow — pick the ones that fit the request. All go through the wrapper (`run-cli.sh` shorthand for `${CLAUDE_PLUGIN_ROOT}\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh`).\n\n| Subcommand                                                  | What it answers                                                        |\n| ----------------------------------------------------------- | ---------------------------------------------------------------------- |\n| `run-cli.sh runs [--limit N] [--failed-only]`               | Which runs exist, newest first, with pass\u002Ffail counts.                 |\n| `run-cli.sh show \u003Crun-id\\|latest> [--failed-only] [--full]` | What happened in one run: per-test verdicts and failure reasons.       |\n| `run-cli.sh transcript \u003Crun-id\\|latest> \u003Ctest-id> [--full]` | What the agent under test actually did for one test case.              |\n| `run-cli.sh grading \u003Crun-id\\|latest> \u003Ctest-id> [--full]`    | Why the grader marked one test case the way it did.                    |\n| `run-cli.sh ls --search \u003Cterm>`                             | Resolve an ambiguous name to concrete test IDs, skills, or spec files. |\n\nExample mappings (illustrations, not a mandatory routing table):\n\n| User says                                                     | Reasonable invocation                |\n| ------------------------------------------------------------- | ------------------------------------ |\n| \"Did the last run pass?\" \u002F \"What was the last run?\"           | `runs --limit 1`                     |\n| \"Show me recent runs\"                                         | `runs --limit 10`                    |\n| \"Show me only failed runs\"                                    | `runs --failed-only`                 |\n| \"Why did the last run fail?\"                                  | `show latest --failed-only`          |\n| \"Show run `\u003Ctimestamp>`\"                                      | `show \u003Ctimestamp>`                   |\n| \"How did `\u003Ctest-id>` go?\" \u002F \"What happened with `\u003Ctest-id>`?\" | `grading latest \u003Ctest-id>`           |\n| \"Why did `\u003Ctest-id>` fail?\"                                   | `grading latest \u003Ctest-id>`           |\n| \"Show the transcript for `\u003Ctest-id>`\"                         | `transcript latest \u003Ctest-id>`        |\n| \"Give me the full transcript for `\u003Ctest-id>`\"                 | `transcript latest \u003Ctest-id> --full` |\n\nConstraints that apply to every troubleshooting invocation:\n\n- **Run identifiers**: either the literal string `latest` (newest run) or a full timestamp directory name like `2026-04-19-18-24-23`. There is no prefix matching.\n- **Test identifiers**: exact, case-sensitive test IDs as they appear in spec files (e.g. `SU-1`).\n- **Ambiguous names — resolve first.** If the user names something that could be a skill, spec, or test case (e.g. \"the widget tests\", \"report-card\"), your **first** CLI call must be `ls --search \u003Cterm>`. Only after you see the search result may you call any troubleshooting subcommand (`runs`, `show`, `transcript`, `grading`). Skipping this and going straight to e.g. `show latest` because \"the latest run probably has it\" is wrong even when it happens to work — the disambiguation step is what the user is relying on you to do. The only exception is when the user supplied an exact, unambiguous identifier (a literal test ID like `SU-T1`, or a full run timestamp). `ls --search` does case-insensitive partial matching across spec name, frontmatter `skill:`, file basename, test case ID, and test case name.\n- **Default to summaries**: the subcommands print structured summaries by default. Pass `--full` only when the user explicitly asks for the entire transcript or grader output (e.g. \"show me the whole transcript\", \"give me the complete log\", \"line-by-line\"). Phrases like \"how did X go\" or \"show me the transcript\" are summary-intent.\n- **No direct file reads**: never fall back to Read\u002FGlob\u002FGrep on `.workspace\u002Fruns\u002F`. The `--full` flag exists so you don't have to.\n- **Always relay verdict AND reason.** When answering about a specific test (e.g. \"How did `\u003Cid>` go?\", \"Why did `\u003Cid>` fail?\"), your reply MUST state the verdict (pass\u002Ffail) AND, for failing tests, quote the failure reason from the CLI's output. The CLI prints both on a `Reason:` line; do not summarize that line away or drop it. A reply that only says \"EX-2 failed\" without naming the reason is incomplete.\n\nIf the CLI says `No runs yet.`, relay that to the user and suggest `skill-unit test --all`. If it reports an unknown run or test id, the error lists available ids; pick one from that list.\n\n## Advanced Usage\n\nThe CLI has additional subcommands for discovery, compilation, and report regeneration. All go through the same wrapper.\n\n| Subcommand                           | Purpose                                                                                                  |\n| ------------------------------------ | -------------------------------------------------------------------------------------------------------- |\n| `run-cli.sh ls [filters]`            | List discovered spec files and their test cases. Also the resolver for ambiguous targets via `--search`. |\n| `run-cli.sh compile [filters]`       | Parse spec files and write manifest JSON without running anything. Useful for inspecting what would run. |\n| `run-cli.sh report --run-dir \u003Cpath>` | Re-generate `report.md` from an existing run directory.                                                  |\n\nFor troubleshooting past runs (`runs`, `show`, `transcript`, `grading`), see the Troubleshooting Runs section above.\n\n## Configuration\n\nThe CLI reads `.skill-unit.yml` at the repository root. Defaults apply when fields are missing:\n\n```yaml\ntest-dir: skill-tests\nrunner:\n  tool: claude # harness CLI (claude, copilot, codex)\n  model: sonnet # model for the test agent (optional)\n  max-turns: 10\n  concurrency: 5 # max test cases running in parallel\noutput:\n  format: interactive\n  show-passing-details: false\nexecution:\n  timeout: 120s\n  grader-concurrency: 5\n```\n\nThe skill does not need to read this file directly. The CLI resolves it.\n\n### Tool permissions\n\nThe CLI enforces strict tool isolation inside test workspaces using `--permission-mode dontAsk`. Spec files can override the allowed\u002Fdisallowed lists via `allowed-tools` \u002F `allowed-tools-extra` \u002F `disallowed-tools` \u002F `disallowed-tools-extra` frontmatter. The skill never configures permissions itself; the CLI does.\n\n## Reference Material\n\nFor detailed documentation, consult these files as needed:\n\n- **`references\u002Fspec-format.md`** — complete spec file format reference with examples\n- **`references\u002Ftesting-guidelines.md`** — best practices for writing test cases\n",{"name":5,"description":7,"argument-hint":52},"[skill-name | spec-name | test-id | tag | prompt ...]","main","b230f73cc21185b9f8b63763bdf5cef1cd0fe06b","skills\u002Fskill-unit",0,"https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit","https:\u002F\u002Fgithub.com\u002Fdflor003","2026-09-20 23:49:13",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":72},[62,65,68],{"tool":63,"command":64},"npx","npx skills add dflor003\u002Fskill-unit --skill skill-unit",{"tool":66,"command":67},"bunx","bunx skills add dflor003\u002Fskill-unit --skill skill-unit",{"tool":69,"command":70},"pnpm","pnpm dlx skills add dflor003\u002Fskill-unit --skill skill-unit","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\u002FSKILL.md",true,[74,80,84,90,94],{"path":75,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":78,"sourceHtmlUrl":79},"references\u002Fspec-format.md","REFERENCE","参考文档",13210,"https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\u002Freferences\u002Fspec-format.md",{"path":81,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":82,"sourceHtmlUrl":83},"references\u002Ftesting-guidelines.md",9802,"https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\u002Freferences\u002Ftesting-guidelines.md",{"path":85,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":88,"sourceHtmlUrl":89},"scripts\u002Frun-cli.sh","SCRIPT","脚本",1501,"https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\u002Fscripts\u002Frun-cli.sh",{"path":91,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":92,"sourceHtmlUrl":93},"templates\u002F.skill-unit.yml",2384,"https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\u002Ftemplates\u002F.skill-unit.yml",{"path":95,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":96,"sourceHtmlUrl":97},"templates\u002Fexample.spec.md",1635,"https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-unit\u002Ftemplates\u002Fexample.spec.md",[99,123,151,177,188,199],{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":107,"publishedAt":47},"01M6KAE1A3Q46FXP3HW4ZY56B9","skill-test-troubleshooting","Use when the user wants a failing or flaky skill test fixed, not just inspected. Triggers on \"why does X keep failing\", \"make X pass reliably\", \"fix the flaky test\", \"this test keeps timing out\", \"diagnose the failures from the last run\", \"fix any failed tests\", \"\u002Fskill-test-troubleshooting\", or any request that names a test\u002Fskill\u002Frun and asks to repair, stabilize, or make-green. Does NOT activate on \"run the tests\" (that is the skill-unit skill) or on read-only inspection requests like \"show the transcript\" \u002F \"what happened in the last run\" (also skill-unit). Does NOT activate on requests to write or add a new test case (that is the skill-test-design skill).","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-test-troubleshooting\u002FSKILL.md",[105,106],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[108,109,110,111,112,113,114,28,115,116,117,118,29,119,120,121,42,44,46,122],"skill test troubleshooting","test","troubleshooting","Skill Test","write","request","make","add","repair","green","activate","only","fix","read","design",{"skillNo":124,"name":125,"nameZh":6,"description":126,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":127,"categories":128,"keywords":139,"publishedAt":47},"01M6KAD8JXQH1ZZDY24EASYNJC","skill-test-design","ALWAYS use this skill when the user mentions writing, designing, creating, or adding test cases for any skill, even if they also describe specific behavior to test. Triggers on \"write a test case\", \"write me a test case\", \"write test cases\", \"design tests\", \"create a spec file\", \"help me write tests\", \"add tests\", \"no tests yet\", \"\u002Fskill-test-design\", or any request that involves creating test cases, spec files, or test coverage for a skill. If the user says \"write a test case for X that covers Y\", this skill handles it, not the skill being tested.","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskills\u002Fskill-test-design\u002FSKILL.md",[129,130,133,134],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":131,"categoryName":132,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":135,"categoryName":136,"taxonomyType":137,"taxonomyTypeDesc":138},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[111,140,141,109,122,34,142,38,143,144,145,112,146,147,148,149,113,150,31,115],"test design","skill test design","me","test coverage","use","coverage","writing","create","write tests","triggers","test cases",{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":160,"publishedAt":47},"01M6KACP1ZG1D6E48TD1RDZ9Q9","report-card","This skill should be used when the user asks to \"summarize grades\", \"show me the class report\", \"generate a report card\", \"how are the students doing\", or mentions student grades, class performance, or grade summaries. It reads a students.json file and produces a formatted grade report.","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskill-tests\u002Fskill-unit\u002Ffixtures\u002Freport-card\u002F.claude\u002Fskills\u002Freport-card\u002FSKILL.md",[157],{"categoryNo":158,"categoryName":159,"taxonomyType":137,"taxonomyTypeDesc":138},"01JBSEEDCAT000000000000034","行政与办公人员",[161,162,163,164,29,165,166,167,142,168,169,170,171,172,173,174,175,176],"report","report card","card","summaries","student","summarize","it","grade report","user","json","how","show me","file","generate","performance","students",{"skillNo":178,"name":153,"nameZh":6,"description":179,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":180,"categories":181,"keywords":183,"publishedAt":47},"01M6KACGKJ6K76RG7DFBNJR2AR","Use when the user asks for a student progress summary, grade breakdown, or class report. Triggers on \"how is X doing in school\", \"show me the grades\", \"summarize class performance\", \"report card for X\", \"what are my child's grades\".","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskill-tests\u002Fskill-test-troubleshooting\u002Ffixtures\u002Fvague-test-prompt\u002F.claude\u002Fskills\u002Freport-card\u002FSKILL.md",[182],{"categoryNo":158,"categoryName":159,"taxonomyType":137,"taxonomyTypeDesc":138},[163,161,162,169,171,172,175,166,144,165,184,185,31,32,186,149,142,187,29],"child","school","progress","summary",{"skillNo":189,"name":190,"nameZh":6,"description":191,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":192,"categories":193,"keywords":194,"publishedAt":47},"01M6KACERE2CRDYS4W90DA40T0","inventory","Use when the user requests an SKU lookup or a warehouse delta report. Triggers on \"SKU lookup\", \"warehouse delta\", \"WMS variance\".","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskill-tests\u002Fskill-test-troubleshooting\u002Ffixtures\u002Fskill-bug-not-test-bug\u002Fskills\u002Finventory\u002FSKILL.md",[],[190,169,195,196,149,197,144,198,161],"requests","warehouse","delta","lookup",{"skillNo":200,"name":201,"nameZh":6,"description":202,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":203,"categories":204,"keywords":205,"publishedAt":47},"01M6KACCPX2AXJRKK54M7618ZH","weather","Use when the user asks about temperature or precipitation. Triggers on phrases like \"is it raining\", \"how cold is it\", \"current temperature\".","https:\u002F\u002Fgithub.com\u002Fdflor003\u002Fskill-unit\u002Fblob\u002Fmain\u002Fskill-tests\u002Fskill-test-troubleshooting\u002Ffixtures\u002Fsingle-failing-test\u002F.claude\u002Fskills\u002Fweather\u002FSKILL.md",[],[201,206,207,167,208,149,144,169,171],"temperature","about","cold"]