Builds the application test plan from the estimate, data model, mockup and brief. Produces test_plan.json with cases traced to the estimate epics, exportable to Excel.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add Federico-Anastasi/DYLA-ai --skill test-plan --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Test Plan?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/federico-anastasi-test-plan-dyla-ai)More formats (shields.io, HTML) on the badges page.
---
name: test-plan
description: "Builds the application test plan from the estimate, data model, mockup and brief. Produces test_plan.json with cases traced to the estimate epics, exportable to Excel."
user-invocable: true
pack: delivery
---
# /test-plan — Test plan
The test plan is the list of cases the team runs before delivery. It does two jobs: it
verifies the application does what the brief promised, and it proves it to the client.
The material is all there already: the estimate says **what was built**, the mockup says
**how it is used**, the brief says **what should happen**.
---
**UX: chat stays conversational.** Never paste the test cases into chat: the user reads
them in the viewer. In chat you talk about coverage and areas, citing cases by id **and**
title (e.g. "TC12, the import with rejected rows").
## PROTOCOL
1. **Check dependencies** — a confirmed estimate is required
2. **Read** the estimate, mockup, data model, brief and context.md
3. **If the test plan exists:** ask whether to update or regenerate it
4. **Write test_plan.json straight away** with `meta.status: "draft"`
5. **Say in words** what is covered and what is not (BLOCKING)
6. **On confirmation:** `meta.status: "confirmed"`
7. **Update context.md**
---
## PHASE 1 — CHECK DEPENDENCIES
Read `projects/{project}/estimate.json`. If it does not exist, **stop**:
```
Writing the test plan needs the estimate: the epics it measures coverage against come
from there. Produce it first with /estimate.
```
If it exists but `meta.status` is `"draft"`, say the cases will need revisiting once the
estimate settles, then carry on: waiting gains nothing, most of the cases will not change.
---
## PHASE 2 — READING
Read ALL of these before you go on:
- `projects/{project}/estimate.json` — the epics and tasks: the skeleton of the coverage
- `projects/{project}/mockup.json` — if it exists: pages, fields, actions, dialogs
- `projects/{project}/data_model.json` — if it exists: the entities and constraints to verify
- the brief: `projects/{project}/brief.json`, or the input document (or its extract under
`.extracted/`)
- `projects/{project}/context.md` — decisions and assumptions
- `projects/{project}/test_plan.json` — if it exists
- `knowledge/` — if the folder exists: house test conventions, client requirements
If `test_plan.json` exists, ask in a ```questions block (format in
`.claude/prompts/questions_format.md`):
````
```questions
[
{
"id": 1,
"q": "The test plan already exists ({N} cases, {M} already run). Update it or regenerate it from scratch?",
"options": ["Update it — add missing cases, flag the ones to revisit, KEEP the outcomes", "Regenerate it from scratch — the recorded outcomes are lost"]
}
]
```
````
Updating is nearly always the right answer: the outcomes are the tester's work, and they
do not get thrown away for a regeneration.
---
## PHASE 3 — WRITE THE DRAFT test_plan.json (before you talk in chat)
**Living-documents architecture: this skill writes ONLY JSON.** The Excel export
(`test_plan.xlsx`) is generated by the backend on demand from `test_plan.json`.
Build the JSON following `schemas/test_plan.schema.json`. `meta` requires `project`,
`title` and `date` — `title` is easy to forget since chat never shows it, but the schema
rejects the document without it.
**Write it in pieces, not in one call.** A finished test plan runs to tens of thousands of
characters, and emitting all of it in a single tool call is where this breaks: observed on
a local model, the `Write` arrived with an EMPTY payload and the document was never
created at all. So: `Write` the skeleton first — `meta` (with `status: "draft"`) and an
empty list (`cases` has no `minItems`, so an empty list is a valid document) — then add
one epic's cases per `Edit`. Anchor `old_string` on the last case already written — its
unique `id` (e.g. `"id": "TC7"`) makes the match unambiguous — and insert the new cases
right after it. Every call stays small, the file is valid JSON throughout, and an
interruption costs the last item instead of the whole document.
### How many cases, and which
- **Every epic must have at least one case.** That is the rule that makes coverage
measurable, and the first thing anyone looks at in the "Coverage" sheet of the export
- As an order of magnitude, expect roughly 1-3 cases per estimate task, more where an
epic has approval branches or file imports (see below) — a 20-task estimate typically
lands 25-45 cases, not 6 and not 150
- One case per **complete user flow**, not per technical object: "submit a new request for
approval" is a case, "the request table" is not
- For every flow with an approval: one case for the happy path and one for the rejection.
They are different paths, not variants of one
- For every file import: one case with a valid file and one with rejected rows. The second
is the one that finds bugs
- `type`: `functional` by default; `integration` when the case crosses an external system;
`negative` for cases verifying that errors are handled; `regression` for what has to be
re-run at every release
### How a case is written
- `title`: what it verifies, in one line, from the user's point of view
- `epic` (and `task` when the case maps to exactly one): the link that makes coverage
measurable. Without it the case does not count
- `preconditions`: the state of the system and the data needed. A tester who did not build
the application has to be able to start from here. If nothing is needed, say so
explicitly rather than leaving it blank
- `steps`: numbered from 1 with no gaps (the backend checks). The `action` cites the
mockup page when one exists ("from the Requests list, open the detail and click
Approve"). `expected` is filled in when that step produces something verifiable; on pure
navigation steps it can be absent
- `expected_result`: the overall outcome — what the tester writes in the report
- `brief_ref`: the chapter that defines the behaviour being verified. This is what lets
you trace back to the requirement when a result is disputed
- `outcome`: always `"to_run"` on new cases. Outcomes are recorded by the tester in the
viewer
### When updating
- **Do not touch** `outcome`, `tester`, `run_at` or `notes` on existing cases
- Cases whose requirement changed: update the steps and flag them in chat, so the tester
knows they need re-running
- New cases take ids continuing after the last existing one
Check validity:
```
python -c "import json; from jsonschema import validate; validate(json.load(open(r'projects/{project}/test_plan.json', encoding='utf-8')), json.load(open(r'schemas/test_plan.schema.json', encoding='utf-8'))); print('valid')"
```
---
## PHASE 4 — CONVERSATIONAL SUMMARY (BLOCKING)
The file already exists and the user can see it in the viewer. In chat: how many cases,
how they spread across the epics, **which epics are uncovered or covered by a single
case** (the most useful thing you can say), and which areas needed the most negative cases
and why.
An example of the tone (not a fixed template):
```
34 cases, spread across all six epics. Most of them sit on the import (9 cases): half are
negative, because that is where the file arrives malformed and the rejected rows have to
be handled by hand.
Two epics have a single case: "Reporting" and "Notifications". For the first that is
fine, it is one view. For the second it is not — I think it needs at least the
failed-delivery cases. Want me to add them?
```
**STOP. Wait for confirmation or change requests.**
---
## PHASE 5 — CONFIRMATION
On confirmation: `meta.status: "confirmed"` in `test_plan.json` (`Edit` just that line — do not rewrite the file: it is tens of thousands of
characters, and regenerating all of them to change one word is both slow and a
chance to alter something by accident), re-validate. Confirm briefly in chat, mentioning that the Excel downloads from the
"download" button in the viewer and that outcomes are recorded in the Test plan tab.
---
## PHASE 6 — UPDATE context.md
`## Test plan` section: status, number of cases, coverage per epic, and the gaps that are
known and accepted. Update `## Deliverables`.
---
## RULES
- Every epic of the estimate has at least one case: if one is left uncovered, say so in
chat explicitly, do not bury it in the JSON
- One case = one complete user flow, not one technical object
- Steps numbered from 1 with no gaps
- Negative cases are not optional: imports, approvals and integrations always have them
- When updating, recorded outcomes are never touched
- Chat stays conversational: never the list of cases in the message
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!