Skip to content
Back to skills

Design

ASecurity

Use when generating a project's design from its PRD — the /design flow that turns the requirements under specs/requirements/ into the design under specs/design/, a prototype for each web app included, then writes the acceptance tests. Also the flow for converging an existing design onto an amended PRD, and for addressing the design review's comments (/address-comments).

  • 25 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
businessgonodeawsgitapidatabasesecuritydocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 19, 2026

npx -y skills add wso2/labs-agentic-engineer --skill design --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Design?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Design
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wso2-design/badge)](https://www.skillsdirectory.com/skills/wso2-design)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: design
description: Use when generating a project's design from its PRD — the /design flow that turns the requirements under specs/requirements/ into the design under specs/design/, a prototype for each web app included, then writes the acceptance tests. Also the flow for converging an existing design onto an amended PRD, and for addressing the design review's comments (/address-comments).
metadata:
  aep:
    kind: platform
    audience: [design]
---

# Design

The design step: derive the complete design of the PRD from the requirements
under `specs/requirements/` — the product page `prd.md`, one file per feature
under `features/`, and `product-wide.md` (`prd-contract`). Design makes its
artifacts in a fixed order (**The lineup**), and each artifact builds on the
artifacts before it. The build gate checks the result mechanically — every
story claimed by some component's design.json, every component enriched — so
the way to a clean Build is to follow that order.

## Which features this run designs

Design works per feature. A feature is **designable** once it has been
interviewed (it has stories) and no `*blocking*` question in its Open
Questions stops it; a stub and a blocked feature are left out, and say so in a
line.

- `/design F1 F2` names the features: design those, and leave every other
  feature's part of the design as it is — shared components change only where
  the named features need them to.
- A bare `/design` designs every designable feature.
- Lines tagged `*assumed*` are designed **as written**. Seeing an assumption in
  a screen or a contract is the quickest way for the user to judge it; do not
  stop to ask about one, and do not leave it out.

The build checks each feature against the requirements the run that designed
it read: a feature whose words change after its design is out of date until a
run designs it again, and every other feature's design stands.

## The PRD is the brief

Design FROM those files, and do not widen or narrow the scope: what the PRD
says is what gets designed. No `prd.md` means the user needs `/start` first,
and no designable feature means a feature's interview comes first
(`/interview F<n>`) — stop and say so. The gap check (step 1) is the one step
that writes the requirements, and it adds only what the product needs to do
what the PRD already says.

**Questions do not stop the run.** Some calls only the user can make: a fact
only the user knows, or a choice that the PRD left open on purpose. Do not
make such a call, and do not stop to ask it. Write it as an open question in
the file that its answer changes (`prd-contract`), design the parts that do
not depend on it, and count it in your closing. The user answers each
question on the Design card, which reads it from that file: do not ask it in
the chat too. The PRD's own answers are
settled: asking one back reads as the document being ignored. An open question
already in the requirements does not stop the run either, except a
`*blocking*` one, which leaves its feature out (above). One marked "deferred"
is one the user has already declined for now; leave it alone.

## Reference documents ground the design

The kickoff may have attached reference documents — and for design, the ones
that matter most are the user's own sketches: a drawn screen sketch, a form
screenshot, a mockup image. They are attached to this conversation natively
(images and PDFs) or in your workspace files (text). When any exist:

- **A user-drawn sketch is the layout brief.** The web application's
  prototype follows what the user drew — screen structure, navigation, the
  controls they placed — refined, not reinvented. Look at the image before
  you write a screen.
- A form document (paper form, PDF) is the field inventory: the screens that
  digitize it carry its fields and sections, and the data model holds them.
- Where a sketch and the PRD disagree, the PRD's scope wins, but the sketch's
  layout intent survives inside that scope — and the discrepancy is worth a
  line in your closing.

No documents attached is the ordinary case: design from the PRD alone.

## Say what you write, and report each artifact

Design runs long, and a reader who can only see finished files cannot tell how
much is left. **Call `declare_plan` before you start writing**, naming the
files that step is about to produce, and call it again each time the plan grows
— you cannot know the per-component files until the cell fixes the component
set, so the list arriving in waves is the real shape of the work, not a failure
to plan. Restating a path you already declared is harmless. It does not end
your turn: declare, then write.

**When an artifact is complete, say so in the chat in one short line**, right
after its write succeeds and before the next step starts: the artifact's name,
then what it holds, in words the user knows. Do not recap the file.

- `Gap check: 3 decisions added to F1 and F2, 1 question for you.`
- `Architecture: expense-web (web app), expense-api (service), receipt-ocr (outside service).`
- `Data model: Employee (with manager), Claim, Expense, Receipt.`
- `Roles and permissions: Employee, Manager, Finance.`
- `expense-web prototype: 7 screens, 4 flows.`

## The lineup

Each step names the skill that governs it. Those bodies are inlined for this
turn — apply them directly, and load one only if you find you do not have it.
Each step reads the steps before it, so keep the order. Inside one step, write
the files that do not depend on each other as parallel calls.

0. **Declare the first wave** — `declare_plan` with what you can already name:
   `specs/design/design.cell`, `specs/design/domain-model.md`,
   `specs/design/security.json` and `specs/design/decisions.md`, plus each
   requirements file the gap check changes.
1. **Gap check** — before the architecture, find the holes in the requirements
   of the features this run designs, and close them (**The gap check**, below).
2. **Architecture** (`cell-design`, then `architecture`).
   - Emit `design.cell` FIRST: every component, boundaries and edges. The
     console streams it into the live diagram, and the platform scaffolds a
     design.json skeleton per deployable component when it lands.
   - Then `declare_plan` the per-component files and fill each component's
     design.json: language (org Tech stack default first), the `stories` it
     serves, by ID (`"F2.3"`; every story the feature files define must be
     claimed by some component — the build gate checks coverage), dependencies
     (discover before you invent), description, pinned skills.
   - A dependency is a cell node: a database or cache you introduce here goes
     into design.cell first (`component <id> as "…" database`, inside the
     cell) — the cell is the source of truth, and a design.json naming a node
     it lacks is refused.
   - An external dependency is also its own definition,
     `specs/design/dependencies/<name>/dependency.json`, written before the
     component that references it (`architecture` owns the shape). In this
     step, `dependency.json` says only what the dependency is: its `name`,
     and in `resource` its `name`, its `description`, and the `provider`
     when the requirements name one (else `suggestions`). Write no
     `contract`, `config` or `provenance`, no contract file and no
     `assumptions.md`, and do not `web_search` for its interface: step 7
     does them, when the components show what they call.
     `{ "name": "slack", "resource": { "name": "slack", "description": "Posts the round's messages to the team's channel.", "provider": "Slack" } }`
3. **Data model** — `specs/design/domain-model.md`: an H1 title, one or two
   sentences of intro, then exactly ONE mermaid `erDiagram` (entities, key
   fields, relations). The prototype's records and the API schemas come from
   it. Brief entity notes after the diagram are fine; keep them to a few
   lines. Never a second erDiagram.
4. **Roles and permissions** (`security-design`) — `specs/design/security.json`
   when the design has sign-in or roles. Write each role's and each
   permission's description in plain words, with its limits: a business
   reviewer checks them. Grant what each role's stories need; step 6 checks
   the grants against the screens.
5. **One artifact per component**, in this order:
   - each `web-application`: its prototype (`prototype`),
     `prototype.json` and `prototype.tsx` in its component directory. It is
     built on the data model and the roles, and it is what a business reviewer
     uses and comments on. Write it before any `openapi.yaml`, also when its
     screens call that service: the contract serves the screens, so the
     screens come first.
   - each `service`: its `openapi.yaml` (`openapi-conventions`). Its
     operations serve the screens of each prototype that calls it, and its
     schemas come from the data model. Before you write it, walk each
     prototype flow (`prototype.json` `flows`) that calls it to its last
     action. After that action, each screen that shows the changed records
     gets them from an operation: the same records, in the same states.
     Example: in the prototype, a booking that its booker cancels stays in
     My bookings as Cancelled, so `GET /me/bookings` returns it, and its
     `summary` says so. Where a prototype flow and the requirements differ,
     that is a gap: close it as **The gap check** says, and fix the
     prototype. Report the walk in one chat line, with what each list keeps
     after the last action: `Prototype walk: 4 flows; My bookings keeps
     cancelled bookings.`
   - each `ai-agent`: its `agent.afm.md` (`agent-building`), after the
     contracts whose operations it calls.
   A component of another kind (a scheduled task, a worker) has no artifact:
   its design.json `description` and `dependencies` hold its behaviour.
6. **Grants pass** (`security-design`) — re-read `specs/design/security.json`
   now that the screens and the operations exist. Step 4 wrote each role's
   `grants` against a design it could only intend; the operations the screens
   in each role's flow load are decidable only here. Walk each flow in each
   prototype (`prototype.json` `flows`), open the contract behind each screen,
   and make sure the role holds the handle of the operation each screen loads.
   Make sure also that each field the screen draws (a column, a value, a name
   in a select or a list) comes from that operation, or from one list
   operation that each role loading the screen may call. A field that no
   operation gives is a gap in the contract, and the build cannot change the
   contract: add the field now to the response of the operation that the
   screen loads (a name next to its id). Do not widen a scope to close the gap.
   The service fills a name from its own records, never from a name that the
   client sends. Re-emit a file only if it changes. Skip the step only when
   step 4 wrote no security.json at all. No gate refuses a role that is one
   handle short — the build's mock walk is what catches it, as a hidden screen
   — so this pass is where it is cheap.
7. **Dependencies** (`architecture`) — after the grants pass and before the
   flows, for each external dependency, now that the components show what
   they call: first `declare_plan` the files of this step. When its
   provider is chosen, climb `architecture`'s contract ladder (step 3: search
   for the published document first, then derive it from the provider's
   reference) and derive its config keys (step 4). Edit its `dependency.json`
   to add `contract`, `config` and `provenance`, and write the contract file
   when you derive it. Then write `assumptions.md` beside them: the facts
   about the service that the design relies on and nothing confirms. Only a
   dependency with no provider, or one whose ladder found no documentation,
   goes to **Needs your input** without a contract.
8. **Flows** — only when a flow is worth writing (see **Flows**, below). A
   design with one component, or with no journey across components, has none.
9. **Acceptance tests** (`acceptance-criteria`) — LAST, because they come from
   the prototypes: `specs/validation/acceptance/F<n>-<slug>.feature`, one per
   feature this run designs. A design without them is unfinished — never skip
   this step.

Write `specs/design/decisions.md` after step 4 and edit it when a later step
makes a new decision (**Technical decisions**, below).

## The gap check

A gap is something the built product must do or have that no requirement
says. A coder who meets a gap guesses, and the user sees the guess only after
the build. Find the gaps now, from the requirements of the features this run
designs, before any artifact exists.

Walk each actor's work through the product, from an empty database. Ask these
questions about each story and decision:

- **What must exist first?** The database starts empty, and nothing is
  seeded. Each record or relation that a story needs must come from a story or
  a decision that makes it through the product. Example: "a manager approves
  their team's claims" needs each employee's manager, so something must set
  it.
- **Who can do it, and who cannot?** Each actor reaches what its stories need,
  and no more. Example: can a manager see the claims of another team? Can a
  manager approve their own claim?
- **What happens at each limit?** Each amount, date, count or state change has
  a boundary. Example: does a claim of exactly $1,000.00 need Finance's
  approval?
- **What does the actor see when it goes wrong?** An empty list, a refused
  action, an outside service that fails or is slow.

Close each gap that you find in one of these ways:

- **The product user would notice it, and you can decide it.** Write the
  decision as a line in the Decisions of the feature it belongs to (or of
  `product-wide.md`, when it spans features), closed by `*assumed*`
  (`prd-contract`). Give the work to an actor that `prd.md` defines. Example:
  `- Finance assigns each employee's manager, on a People screen. *assumed*`.
  Then design the line as written, like every `*assumed*` line.
- **Only an engineer would notice it.** It is not a requirement. It is a
  technical decision, made at the artifact it shapes (**Technical
  decisions**).
- **Only the user can decide it** (a fact only they know, or a choice
  between two products, such as an actor nobody defined). Write it as an open
  question in that feature's file (`prd-contract`; never `*blocking*`). Design
  the rest of the feature, and count the question in your closing.

Then report the gap check in one chat line, with the count of decisions per
feature and the count of questions. A gap that a later step finds goes the
same way, in that step.

## Technical decisions

`specs/design/decisions.md` holds the technical decisions that the design
makes and the requirements do not state. One test decides where a decision
goes: **would a person who uses the product notice it?**

- Yes: it is a requirement. It goes in the feature's file, as the gap check
  writes it.
- No: it goes in `decisions.md`.
- It is a fact about an outside service ("Xero accepts up to 500 lines per
  batch"): it goes in that dependency's `assumptions.md` (`architecture`).

```markdown
# Technical decisions

- [architecture] Receipt photos are kept in object storage, not in the database. *assumed* (F1)
- [data-model] Amounts are stored in cents. *assumed* (F1, F2)
- [security] A manager reads the team's claims through /me/team/claims. *assumed* (F2)
- [expense-api] A list returns 50 claims per page. *assumed* (F1, F2)
```

- One line per decision. The line starts with the tag of the artifact that
  the decision shapes: `architecture`, `data-model`, `security`, `flows`, or
  the name of a component (`expense-api`, `expense-web`). Then the decision,
  in one sentence. Then `*assumed*`. Then, in parentheses, the IDs of the
  features that the decision serves, or `all`.
- Write a line only for a choice between real options that a reviewer could
  change. Do not restate a requirement: a choice that a requirement line
  already makes stays only in the requirements. A fact that an organization default or a skill settles (the
  language, the stack, the sign-in provider) is not a decision.
- Write `decisions.md` once the roles and permissions are written, with
  every decision made so far and those you already know the later artifacts
  will follow. Edit it when a later step makes a new decision.
- `*assumed*` stays on the line until the user confirms or changes the
  decision. Then the tag comes off, and the line stays.
- On a later run, keep each line that still holds, with its words and its
  tag. Remove a line when no artifact makes that choice now.

## Flows

A flow is a PRD actor's end-to-end journey across components: it starts with
an actor, spans cell components or an outside service, and involves more than
one component interaction or a decision or async step. Plain CRUD on one entity
is NOT a flow, and a screen-by-screen walk is the prototype's, not a flow's.
One file per flow: `specs/design/flows/<kebab-slug>.md`, an H1 title, one or
two sentences naming the actor and the outcome, then exactly ONE mermaid
`sequenceDiagram`. Every participant must be a node design.cell declares (a
component, or a boundary external such as the identity server or a SaaS) or an
actor from the PRD — never an invented name. No context/C1 diagram anywhere:
the cell and the PRD carry that. The shape is formulaic — write it like this,
first try:

```mermaid
sequenceDiagram
    actor Employee
    actor LineManager as Line Manager
    participant expense-webapp
    participant expense-api

    Employee->>expense-webapp: submit claim (amount, receipt)
    expense-webapp->>expense-api: create claim
    alt no receipt
        expense-api-->>expense-webapp: refused
    else
        expense-api-->>expense-webapp: created
    end
    LineManager->>expense-webapp: approve
```

Names are ONE word. A multi-word PRD actor gets an alias — `actor
LineManager as Line Manager` — and every message uses the one-word id;
spaces in a declared name or a message endpoint are refused. The
platform judges both documents (the data model and each flow) as you write
them: a second diagram, a statement outside plain mermaid, or an unresolved
participant is refused (`INVALID_DIAGRAM`, `UNKNOWN_PARTICIPANT`) with the
offending line and the ids you may use — fix it and re-emit the whole file
once.

## Regeneration and the delta pass

A design already exists → CONVERGE it to the current PRD, for the features
this run designs: update what
drifted, remove what the PRD no longer calls for, keep what holds. A legacy
`specs/design/design.md` (the retired single-file overview) is not part of
the design any more — `removeFile` it and put its content where it now
belongs (domain-model.md, flows/).

An amended PRD is a **delta pass with shipped parts protected**: design what
the new stories require and touch shipped components only where those stories
force it — calling out every such change. When built reality contradicts the
design, surface the conflict to the user; never silently redraw shipped
architecture.

## Addressing comments

`/address-comments` sends you the design review's comments. They are in
`specs/design/review.json`: one entry per artifact `path`, each with its
`comments`. Act on each comment whose `status` is `sent` or `reopened`, with
one exception: a `sent` comment that has your `question` and no `answer`
waits for the user. Do not act on it, and do not change it. A comment that
has an `answer` is the user's answer to your `question`: act on the comment as
the answer says. A `reopened` comment keeps your earlier `reply`: its author
did not accept that answer. Do not act on a `draft` comment, and do not change
it. When no comment is left to act on, say so and stop.

1. **Find what each comment changes.** The artifact that a comment is on
   shows where its author saw the problem. The change can start in an earlier
   artifact. Example: "show the receipt on Team approvals" is on the
   prototype, and it also needs the contract. A comment on a prototype has an
   `anchor`: the `screenId`, the `elementIds` (empty for the whole screen),
   the `roleId`, the `stateId` and, if there is one, the `flowId`. Find them
   in the prototype as it is now.
2. **Do not guess an ambiguous comment.** A comment is ambiguous when two
   reasonable readings give different designs, or when it needs a fact that
   only the user knows. Do not act on it. Write your question on the comment,
   as its `question`: one or two sentences, in the words of the reader, that
   the user can answer in a line ("Sort the list by the date of the expense,
   or by the date it was sent?"). The comment stays `sent`. Write
   the question only there, not also in a feature file: the Design card asks
   it from the comment. When the user's answer is a product rule, step 4
   writes it into the requirements. If a comment that has an `answer` is still
   ambiguous, replace its `question` with the new one and remove its
   `answer`.
3. **Start at the earliest artifact.** Of the comments that you act on, find
   the change that comes first in this order: the requirements, the
   architecture, the data model, the roles and permissions, the components'
   artifacts (the prototypes, then the contracts, then the agents), the
   dependencies, the flows, `decisions.md`, the acceptance tests.
   A prototype comment is **cosmetic** when its change touches no record or
   field, role or permission, API operation, flow step, validation rule or
   business rule: a label, copy, the layout, the order of things, an empty or
   an error state. A cosmetic comment stays inside the prototype: change the
   prototype and nothing else for it. Every other prototype comment starts at
   the earliest artifact that it touches. When you cannot tell whether a
   comment is cosmetic, it is not.
4. **Regenerate from there down, in that order.** Read each later artifact
   again. Change it only where a comment asks, or where an earlier change
   makes it wrong. Write a file only when it changes: edit it, and keep its
   ids, keys and names. When you change one part of a file, keep every other
   part as it is. Use `editFile` for a local change. A whole-file rewrite
   (`removeFile`, then `addFile`) must carry the whole file: each section,
   list and diagram that you do not change, as it was. Apply a prototype comment with the `prototype` skill
   in this run, together with the contract change that it needs. Write the
   acceptance tests last: rewrite each feature file whose scenarios the
   changes make wrong.
   - A comment that changes a product rule (who can do what, a limit, a
     state) is a requirement. Write it in the Decisions of its feature, in
     the comment's words, without `*assumed*`: its author decided it.
   - A decision that you make to apply a comment goes where **Technical
     decisions** puts it.
   - When you change a prototype screen or a contract operation, walk again
     each flow that reaches that screen, as step 5 of **The lineup** says
     for a `service`.
   - Decline a comment only when it conflicts with a requirement.
5. **Change every place.** A comment that renames a field or a term changes
   each line that has the old name. Before you edit a file, find each of
   those lines in it, and change all of them. A new field goes in each
   artifact that the change needs. In `prototype.tsx`, write a rename in
   one write, as the `prototype` skill says.
6. **Answer each comment in `review.json`.** It is the last file that you
   write in the turn, in one write: write it only when every artifact write
   has succeeded (when you rewrite the prototype, after its `addFile`),
   because each reply tells what the artifacts now say. The same write sets the `question` of each comment that step 2 asks
   about. Set `status` to `"addressed"`, `addressedAt` to the time that
   the turn gives, `revision` to the revision of this run, and `reply` to one
   line that tells what you did, in the words of the reader: `Renamed
   totalAmountCents to totalCents in the data model, the contract and the
   prototype.` The reply names no revision ("addressed in revision 3"): the
   `revision` field holds it, and the console shows each file's own revision.
   A declined comment is also addressed: its reply tells which requirement it
   conflicts with. The revision of this run is the highest
   `revision` in the file plus one, or 2 when no comment has one (the first
   Design run is revision 1). All the comments of one run get the same
   revision. Keep the `question` and the `answer` of a comment that you
   address. Change no other field and no other comment.

Close with one line for each comment that you addressed (its author and your
reply). Write no line for a comment that you asked about. When you asked a
question, write one line with the count: `1 question for you on the Design
card.` Do not repeat the question: the card shows it.
End with one line that names the next step on the Design card, for example
`Next on the Design card: answer 1 question, then check the 3 changed files.`

## Where this stops

`/design` ends at the design and its acceptance tests — no task planning,
no application code. An ambiguity that the acceptance tests meet is an open
question in its feature's file, as the gap check writes one. Close with these
parts and nothing more: one line per component (name, type, one-clause role);
when the run left open questions, one line with their count (`2 questions for
you on the Design card.`), without the questions, which the card shows;
a **"Needs your input"** block
listing only the dependencies still unresolved, each as a link to its
definition (`[<name>](aep://spec/specs/design/dependencies/<name>/dependency.json)`,
the `architecture` skill's closing form) followed by the one thing you need,
so the user opens it with a click; and a last line that names the next step on
the Design card (`Next on the Design card: answer 2 questions, then check the
9 files.`). Name the step, never a command or a path. Leave out a part that has
nothing in it. The artifact lines and the dependency narration during the turn
(the `architecture` skill owns its format) already carried the play-by-play.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.