Program Design
Align on code shape before implementation: the types, signatures, call stacks, and file layout that architecture is too coarse for and review is too late to change. The model drafts compact sketches; you argue about taste; then you lock the shape. Nobody writes production code.
This is not an implementation spec. If you are writing function bodies, AC matrices, or a file-by-file work order, you have gone too far.
Core contract
- Lock the program for one implementation unit: a ticket, or a capability whose architecture is already settled.
- Behaviour comes from the spec and ticket. Architecture (if any) constrains seams. This skill owns taste — depth, naming, layout, call shape.
- Inspect the repository. Prefer evidence over generic best practices.
- Read-only: inspect code, docs, tests, and history; do not modify production code.
- Draft sketches, grill taste forks, lock. Stop unless the user asks to continue.
- Use language: module, seam, depth, interface.
When to use / skip
text
wayfinder → grill-with-docs → /to-spec
↓
/architecture # system shape, if new seams / multi-ticket
↓
/program-design # this skill
↓
/to-tickets → /implement
| Situation | Skill |
|---|
| Product or requirements still open | / first |
| New services, schemas, or module boundaries | first |
| Obvious oneshot on an established pattern | Skip to |
| Architecture is obvious; quality of the code is not | |
| Ticket exists and this slice's internals matter | on that ticket |
Forbidden
- Full function bodies
- Per-AC behaviour matrices
- Implementation sequences or phased checklists
- Test-command and fixture inventories
- Dual representation of the same fact
- A second evidence appendix restating the sketches
- Every available visual in one document
- Box-drawing as the first character, markers, column-padded comments, unicode in sketches
and
stay path-free.
stays at module boundaries.
owns files, tests, and sequence.
Steps
1. Establish the unit
Read the ticket, spec, architecture (if any), ADRs, and project instructions.
Ready when the behaviour is clear and the remaining unknown is how the code should look. If behaviour is still open, stop and send the user back. If a multi-ticket spec is the only input and slice boundaries are unclear, send them to
after this — or to
if seams are also unclear.
Record the outcome in one sentence. Recommend defaults for non-blocking ambiguity. Stop for the user only when a taste fork would change public APIs, persistence, security, or system boundaries — those belong in architecture.
This step is complete when the unit and outcome are explicit.
2. Inspect the repository
Trace the current call path. Note symbols, types, helpers, and conventions this change should reuse. Conflicting patterns: pick one, with evidence.
This step is complete when every proposed seam has an existing counterpart or is named as new and justified.
3. Draft the smallest sketches
Pick
only the views this change needs — usually two, rarely more than three. Follow
references/program-design-template.md
for rendering, including the sketch formatting rules. Those rules exist because chat highlighters, not the author, control color and wrapping.
| Change is about | View |
|---|
| Where it lives / what is new | File tree in — marker, then |
| Orchestration or control flow | Call tree in — same glyphs as calldiff |
| Frontend structure | Component tree in |
| Types an agent would get wrong | Signatures and types — no bodies |
| The algorithm is the decision | Short pseudocode |
Use
when the surrounding shape already exists. Show the whole block only when most of it is new.
Prefer, in order:
- Existing code over new code.
- Local code over a shared abstraction.
- Established repository patterns over new patterns.
- Explicit code over generic frameworks.
- A narrow implementation over speculative extensibility.
- One clear execution path over interchangeable layers.
New interfaces, factories, adapters, registries, or shared utilities require a current problem with multiple immediate call sites.
This step is complete when a reviewer can see the proposed program without reading prose around it.
4. Grill taste
Put the real forks to the user, one at a time, each with a recommendation. A taste fork is something a reviewer would fight about: deep vs shallow module, existing helper vs new file, sync vs job, this seam vs that one.
Revise the sketches after each answer. Do not interview about facts the repo already contains.
This step is complete when remaining forks are locked or explicitly deferred.
5. Lock
Persist only when a later session needs the sketches (
or
in a fresh context). If none exists, use
docs/agents/program-design/<short-slug>.md
. For small work continuing in this conversation, the sketches in-chat are the artifact.
Before handing off, verify:
- Two or three sketches, not a spec.
- File layout and call stacks follow the sketch formatting rules in
references/program-design-template.md
(diff marker then , no , no padded comment columns, lines ~72 characters, predicates in words).
- No function bodies, AC matrices, test commands, or implementation sequence.
- Proposed symbols are marked; existing symbols come from the repo.
- Taste forks are resolved or named as blocking.
Handoff
Report:
- Path to the document, or .
- One-sentence summary of the locked shape.
- Blocking decisions, or .
- Confirmation that production code was not modified.
- Next step:
If slices are not published:
text
/to-tickets using <program-design-path>
If a ticket already exists:
text
/implement <ticket> using <program-design-path>