From 92de3612077d2e0bf373242685024f86dde01f3c Mon Sep 17 00:00:00 2001 From: River Lynn Bailey Date: Fri, 7 Aug 2026 09:24:52 -0600 Subject: [PATCH 1/3] feat(han-coding): add the design-an-api skill Closes #173. Adds /design-an-api, which designs an interface contract for one stated goal: a discovery wave, an options document from the software architect, a user option pick, a junior-developer question round, open items surfaced one at a time, and an adversarial validation round. Every element of the contract carries a justification naming the goal language it descends from or the behavior it is a necessity of; anything that cannot fill that field lands on a cut list the user sees. Also closes the two-way disambiguation gaps against architectural-analysis, plan-a-feature, and plan-implementation. --- han-coding/.claude-plugin/plugin.json | 2 +- .../skills/architectural-analysis/SKILL.md | 4 +- han-coding/skills/design-an-api/SKILL.md | 341 ++++++++++++++++++ .../references/api-design-template.md | 117 ++++++ han-planning/skills/plan-a-feature/SKILL.md | 5 +- .../skills/plan-implementation/SKILL.md | 3 +- 6 files changed, 466 insertions(+), 6 deletions(-) create mode 100644 han-coding/skills/design-an-api/SKILL.md create mode 100644 han-coding/skills/design-an-api/references/api-design-template.md diff --git a/han-coding/.claude-plugin/plugin.json b/han-coding/.claude-plugin/plugin.json index 81ffd308..6875f924 100644 --- a/han-coding/.claude-plugin/plugin.json +++ b/han-coding/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "han-coding", - "description": "Coding-facing skills for the Han suite: writing, reviewing, testing, investigating, and standardizing code. Home of the tdd skill, which drives a feature or behavior through a BDD-framed red-green-refactor loop with an enforced observed-failure gate, and the refactor skill, which restructures existing code without changing its behavior through a test-gated refactoring loop, plus code-review (comprehensive review of local changes), code-overview (a progressive-disclosure, understand-now overview of unfamiliar code or a PR's changes), architectural-analysis (module-level coupling, data flow, concurrency, risk, and SOLID assessment), automated-test-planning (coverage-gap and edge-case test plans), manual-test-planning (plain-language manual test plans a person runs by hand), investigate (evidence-based root-cause debugging), and coding-standard (creating and updating coding standards). Depends on han-core and han-communication; bundled by the han meta-plugin.", + "description": "Coding-facing skills for the Han suite: writing, reviewing, testing, investigating, and standardizing code. Home of the tdd skill, which drives a feature or behavior through a BDD-framed red-green-refactor loop with an enforced observed-failure gate, and the refactor skill, which restructures existing code without changing its behavior through a test-gated refactoring loop, plus design-an-api (designing an interface contract for one stated goal through an options round, a question round, and an adversarial validation round), code-review (comprehensive review of local changes), code-overview (a progressive-disclosure, understand-now overview of unfamiliar code or a PR's changes), architectural-analysis (module-level coupling, data flow, concurrency, risk, and SOLID assessment), automated-test-planning (coverage-gap and edge-case test plans), manual-test-planning (plain-language manual test plans a person runs by hand), investigate (evidence-based root-cause debugging), and coding-standard (creating and updating coding standards). Depends on han-core and han-communication; bundled by the han meta-plugin.", "version": "3.0.0", "dependencies": ["han-communication", "han-core"] } diff --git a/han-coding/skills/architectural-analysis/SKILL.md b/han-coding/skills/architectural-analysis/SKILL.md index 1cf7fc8b..bc4a044c 100644 --- a/han-coding/skills/architectural-analysis/SKILL.md +++ b/han-coding/skills/architectural-analysis/SKILL.md @@ -6,8 +6,8 @@ description: review the architecture, design quality, dependency structure, coupling, cohesion, or technical debt of an existing part of the codebase. Not for investigating specific bugs, runtime errors, or failures — use investigate. Not for test planning — use automated-test-planning. Not for file-level code review — use code-review. Not for researching open-ended - options, prior art, or how something works — use research. Not for writing documentation or architectural decision - records." + options, prior art, or how something works — use research. Not for designing a new interface or contract — use + design-an-api. Not for writing documentation or architectural decision records." arguments: size argument-hint: "[size: small | medium | large | dynamic] [focus area: module, directory, or feature to analyze]" allowed-tools: Read, Glob, Grep, Agent, Bash(find *) diff --git a/han-coding/skills/design-an-api/SKILL.md b/han-coding/skills/design-an-api/SKILL.md new file mode 100644 index 00000000..592254cd --- /dev/null +++ b/han-coding/skills/design-an-api/SKILL.md @@ -0,0 +1,341 @@ +--- +name: design-an-api +description: > + Designs the contract for an API change inside one codebase — a component's props, a function surface, URL or query + parameters, an event payload, or a module boundary — through a discovery pass, an options document with one + recommendation, a question round, and an adversarial validation round, with every element of the contract justified + from one stated goal. Use when you want to design, shape, decide, or nail down an interface, contract, signature, or + API change for a capability you can already describe, sized for roughly one pull request. Produces a design document + and changes no code. Does not specify what a feature should do — use plan-a-feature. Does not plan delivery or + sequencing — use plan-implementation. Does not assess the architecture of existing code — use + architectural-analysis. Does not write the code — use tdd. Does not restructure existing code — use refactor. +arguments: size +argument-hint: + "[size: small | medium | large | dynamic] [the goal or ticket this serves, and the interface to design]" +allowed-tools: Read, Write, Glob, Grep, Agent, Bash(git *), Bash(find *), Bash(mkdir *) +--- + +## Project Context + +- git installed: !`which git 2>/dev/null || echo "not installed"` +- current branch: !`git branch --show-current 2>/dev/null || echo "no git branch"` +- CLAUDE.md: !`find . -maxdepth 1 -name "CLAUDE.md" -type f` +- project-discovery.md: !`find . -maxdepth 3 -name "project-discovery.md" -type f` +- personal config directory: !`echo "${CLAUDE_CONFIG_DIR:-$HOME/.claude}"` +- project .han/config.md: !`cat .han/config.md 2>/dev/null || echo ""` + +As your first action, use the Read tool on `.han/config.md` inside the `personal config directory` path above. A read +that returns no file is no personal configuration: continue silently. When that file or the `project .han/config.md` +probe supplies content, apply it per [config-rule.md](../../references/config-rule.md), which governs precedence +between the two files, relative-path resolution, and what to do with a file that reads but cannot be used. + +## Operating Principles + +Read these before dispatching anything. They constrain every step below. + +- **A stated goal is required, and it is the scope governor.** This skill designs a contract in service of one named + goal: a ticket, an issue, a written requirement, or a described capability. If no goal resolves, stop and ask for one + BECAUSE without a goal there is nothing to justify the design against, and the run degrades into designing a + general-purpose framework for a single consumer. +- **Every element of the contract carries a justification.** Each named parameter, field, type, default, precedence + rule, and failure behavior states exactly one of two things: the part of the stated goal it descends from, quoted or + named; or the asked-for behavior it is a necessity of. An element that can fill neither does not enter the design. It + moves to the cut list with what it would have done and why it was cut. +- **Silence never cuts a necessity.** The goal is short and does not enumerate what it depends on. A goal that never + mentions a caching layer justifies cutting one. The same goal's silence about invalid input, error behavior, and + types does not cut those, because they are necessities of the surface it did ask for. +- **The agents own the judgment; the skill orchestrates.** The skill resolves the goal and the interface, classifies + size, selects the roster, fans agents out and in, runs the two human gates, and renders the design document. It + produces no design content of its own. +- **The four-agent spine always runs; specialists are signal-selected.** `han-core:codebase-explorer`, + `han-core:software-architect`, `han-core:junior-developer`, and `han-core:adversarial-validator` run at every size + BECAUSE evidence, design, questioning, and attack are the irreducible core of a contract that survives contact. Every + other specialist is added only when the interface's signals warrant it and the band allows it, BECAUSE dispatching an + agent whose domain the contract never touches burns tokens and pulls the design toward concerns the goal did not ask + for. +- **Default to small.** Start classification at small and escalate only when a higher-band signal is clearly present. + Borderline signals stay at the smaller band. Under-dispatching is recoverable by re-running at a larger size; + over-dispatching is not. +- **This skill changes no code.** It produces a design document. Implementation is a separate, later step, normally a + `tdd` run against this document. +- **Options before commitment.** The architect produces two or three real options with one recommendation, not a single + design with alternatives invented afterward to justify it. The user picks before three further agent rounds are spent + refining one. +- **The design document template lives at + [references/api-design-template.md](./references/api-design-template.md).** The skill renders that template by filling + its sections. It does not invent a structure inline. +- **The document is written for a named reader.** As the skill writes the design document's synthesized prose, it + sources the shared standard by invoking `han-communication:readability-guidance` and applies it, holding one audience + above the writing: the engineer who will implement this contract and the reviewer who will approve it. Scope that + frame per section so the specifics that reader needs — exact signatures, types, precedence rules, file paths — are + preserved, never simplified away. + +# Design an API + +## Step 1: Resolve the Goal, the Interface, and the Starting Point + +**Bind `$size`.** If the user passed `small`, `medium`, `large`, or `dynamic` as the first positional argument, bind +`$size` to it. Anything else is part of the goal-and-interface context, not a size; bind `$size` to the literal +`none provided`. + +**Resolve the goal.** Take the remaining argument and conversation context as the goal this design serves. A ticket +reference, issue URL, file path, or a described capability all qualify. Read the referenced material if it names a file +or is fetchable from the conversation. Record the goal verbatim where it is quotable — the justification field in every +later step cites it. If no goal resolves, stop and ask the user for the ticket, issue, or one-paragraph statement of +what this change is for. Do not proceed without it. + +**Resolve the interface.** Identify what is being designed: which component, function, module, route, or payload, and +where it lives. Confirm it resolves to real files using `Glob` and `Read`. If the interface is genuinely new and has no +file yet, resolve instead the module or directory it will live in and the consumers that will call it. If neither +resolves, ask the user to name the surface before going further. + +**Resolve the starting point.** Read the `current branch` value from Project Context. If the current branch already +carries a partial or abandoned attempt at this change, ask the user in one short message whether to design from the +branch as it stands or from the merge base with the default branch, ignoring the branch's changes. Use `git` to read the +merge-base state when they choose the merge base. State the chosen starting point in one line. When git is unavailable +or the branch carries nothing relevant, the working tree is the starting point and no question is asked. + +**Resolve project context.** If `CLAUDE.md` is present, read its `## Project Discovery` section for conventions. Fall +back to `project-discovery.md`. These resolve language, framework, and convention questions so the agents infer less. If +neither exists, the agents fall back to surrounding-code inference — note this in the briefs. + +**Resolve the output folder.** The run writes three files: `{folder}/context-brief.md`, `{folder}/design-options.md`, +and `{folder}/api-design.md`. Resolve `{folder}` in this order: + +1. If the user specified an output folder, use it. +2. If the project or personal config sets an `output-directory`, place the run folder under it, per + [config-rule.md](../../references/config-rule.md). +3. Otherwise, choose a 2-to-4-word kebab-case folder named for the interface, under a documentation root surfaced via + `CLAUDE.md`, `project-discovery.md`, or a Glob fallback (`docs/plans/`, `docs/`). + +Create the folder with `mkdir -p`. If `api-design.md` already exists there, write to a date-suffixed name (for example +`api-design-2026-08-07.md`) and state which files were written; never silently overwrite. State the chosen folder in one +short line and proceed without waiting for confirmation. + +## Step 2: Detect Signals and Classify Size + +Run targeted `Grep` and `Glob` over the interface and its consumers to detect which domains the contract actually +touches. These signals drive both the band and the roster: + +- **Consumer-spread signal:** the interface has call sites beyond the module being changed — several components, several + routes, or an exported surface other packages import. +- **Ordering signal:** async, lifecycle, mount-order, retry-order, or event-order behavior is part of the contract, not + an implementation detail behind it. +- **Data-contract signal:** the interface carries persisted data, a schema or migration, a wire or event payload, or a + document shape that another system reads. +- **Trust-boundary signal:** the interface accepts untrusted input (URL and query parameters, request bodies, uploads) + or carries auth, tokens, secrets, or PII across the surface. +- **Failure-path signal:** the contract has to state what happens on failure — outbound calls, timeouts, retries, + idempotency, partial writes, or a failure that would page someone. +- **System-seam signal:** the interface crosses a deployable unit or bounded-context boundary — an RPC or HTTP contract + with a sibling service, a message broker topic, or a shared store across services. +- **Unfamiliar-area signal:** the interface's surrounding module is large or its structure is not legible from a first + read. + +**Classify the size.** Default to small. Escalate only when a band's signal is clearly present; when a signal is +borderline, stay at the smaller band. + +- **Small** _(default)_ — one interface with a contained consumer set inside one module, and no data-contract, + trust-boundary, failure-path, or system-seam signal. The ordering signal may be present or absent. +- **Medium** — a consumer-spread signal, OR exactly one of the ordering, data-contract, trust-boundary, or failure-path + signals. +- **Large** — two or more of those cross-cutting signals together, OR a system-seam signal is present, OR `$size` is + `large`. + +**Apply the size override.** If `$size` is not `none provided`, use it: a band value is the band and skips the +signal-based classification above, while `dynamic` forces the signal-based classification even when the project config +sets a default band. If `$size` is `none provided` and the project config supplies a band via `default-swarm-size` (per +[config-rule.md](../../references/config-rule.md)), use that band, skip the signal-based classification, and announce +the config as the source. In every case still select specialists by signal: a `large` band does not dispatch agents +whose domain the contract never touches. A conversational override ("design this large") is equivalent to `$size`. + +## Step 3: Build the Roster and Announce It + +**Spine — dispatched at every size:** + +- `han-core:codebase-explorer` — discovers the current surface, its consumers, and the constraints the design has to + live inside. Feeds the context brief. Runs in Step 4. +- `han-core:software-architect` — produces the options document and every later amendment. Runs in Steps 5, 7, and 9. +- `han-core:junior-developer` — questions the chosen option as a generalist who was not in the room. Runs in Step 7. +- `han-core:adversarial-validator` — attacks the amended design and the evidence under it. Runs in Step 9. + +**Signal-selected specialists — added to the discovery wave when the signal is present and the band allows:** + +| Specialist | Add when | Min band | +| --------------------------------------- | ---------------------- | -------- | +| `han-core:structural-analyst` | Consumer-spread signal | Medium | +| `han-core:behavioral-analyst` | Unfamiliar-area signal | Medium | +| `han-core:concurrency-analyst` | Ordering signal | Medium | +| `han-core:data-engineer` | Data-contract signal | Medium | +| `han-core:on-call-engineer` | Failure-path signal | Medium | +| `han-core:system-architect` | System-seam signal | Large | +| `han-core:adversarial-security-analyst` | Trust-boundary signal | Medium | + +Roster caps by band: **small** runs the spine only (4 agents); **medium** adds one or two signalled specialists (5–6 +agents); **large** adds up to four, including `han-core:system-architect` when a system-seam signal is present (7–8 +agents). If more specialists are signalled than the cap allows, keep the band's count, prefer the specialists covering +the strongest signals, and name the omitted domains in the design document's summary so the user can re-run larger. + +Extra agents named in the project config's `## Extra Agents` list join the signal-selected pool and compete under the +same signals and band caps, per [config-rule.md](../../references/config-rule.md): add one only when a signal in the +interface matches its stated specialty, count it against the band's cap, and skip an entry that does not resolve to a +dispatchable agent with a one-line note. + +**Announce the decision in one line before dispatching**, with per-specialist justification — for example: + +> **Size: medium.** Designing the query-parameter prefill contract on `FlowProvider`; consumer-spread signal (7 call +> sites) and a trust-boundary signal (values arrive from the URL). **Roster (6):** `han-core:codebase-explorer`, +> `han-core:structural-analyst` (consumer audit), `han-core:adversarial-security-analyst` (untrusted URL input), then +> `han-core:software-architect`, `han-core:junior-developer`, and `han-core:adversarial-validator`. + +State git availability in the same message if git is absent. Proceed without a blocking confirmation; discovery is +read-only and re-runnable, so a gate here would gate a reversible operation. If the user objects to the roster, honor +the adjustment. + +## Step 4: Dispatch the Discovery Wave and Write the Context Brief + +Launch `han-core:codebase-explorer` and every signalled specialist in a single message with one `Agent` call per agent +so they run concurrently. Each brief must contain: + +- The stated goal, verbatim. +- The resolved interface, its file paths, and its known consumers. +- The starting point from Step 1, so an agent reading a branch-modified file knows whether those changes count. +- The resolved project-context conventions, or a note that none were found and surrounding-code inference applies. +- The instruction to report findings with provenance: every finding carries a file path and line number, or is labelled + as an inference. + +Wait for the whole wave to return. Then write `{folder}/context-brief.md`: a numbered list of findings (F1, F2, F3, …), +each carrying the finding, its provenance (a `file:line` citation, or the label `inferred`), and the agent that reported +it. Merge duplicates and keep conflicting findings as separate numbered entries with both citations, rather than +picking a winner. Apply the evidence rule from [../../references/evidence-rule.md](../../references/evidence-rule.md) to +every finding. When a question the design depends on has no evidence at any tier, record it as an open item rather than +guessing. + +## Step 5: Dispatch the Architect for Options + +Launch `han-core:software-architect` with one `Agent` call. Pass it the stated goal verbatim, the full context brief, +and the resolved project conventions. Its brief must ask for: + +1. **Two or three real options** for the contract, each one a design someone could implement, not a strawman. +2. **One recommendation** with the reasoning that selects it over the others. +3. **The rejected alternatives** with the reason each was rejected. +4. **For every element of every option** — each parameter, field, type, default, precedence rule, lifecycle rule, and + failure behavior — the justification defined in the Operating Principles: the part of the goal it descends from, or + the asked-for behavior it is a necessity of. +5. **A cut list** of anything the interface could plausibly carry but the goal does not ask for, with what it would have + done and why it was cut. +6. **Pseudocode sketches** of each option's signatures and types. + +Write the returned options to `{folder}/design-options.md`. + +## Step 6: Human Gate — The User Picks an Option + +Present the options to the user with `AskUserQuestion`: one option per choice, the recommendation named first and +labelled as recommended, each with its one-line reasoning. Before writing the question, invoke +`han-communication:explanation-guidance` and apply it, so each option reads as an outcome the user could observe rather +than a mechanism. Include the cut list in the surrounding message so the user sees what the design is giving up. + +Handle the response: + +- **User picks the recommendation or another option** — carry it forward as the chosen design. +- **User picks a rejected alternative or amends an option** — carry their choice forward, and record their direction as + the justification for the elements it changes. Operator direction is itself a valid justification. +- **User asks for a different option entirely** — return to Step 5 with their feedback, once. If a second round still + does not produce an acceptable option, present what exists and ask for the constraint that is missing. + +## Step 7: Dispatch the Question Round and Amend + +Launch `han-core:junior-developer` with one `Agent` call. Pass it the stated goal verbatim, the context brief, and the +chosen option in full. Its brief must ask it to reframe the contract in simpler terms and raise the clarifying questions +a generalist who was not in the room would ask: unstated prerequisites, conflicts with the project's own conventions, +names that do not say what they hold, and behavior the contract leaves undefined. Ask for numbered questions. + +Sort the returned questions into three buckets: + +1. **Settled by the goal** — the stated goal already answers it. Answer it, cite the goal, and do not escalate. + Re-deciding a question the goal already decided wastes the user's turn. +2. **Settled by the context brief** — a finding answers it. Answer it, cite the finding number. +3. **Open** — neither the goal nor the brief settles it, and the answer changes the contract. These go to Step 8. + +Then relaunch `han-core:software-architect` with one `Agent` call, passing the chosen option, every question, and the +answers from buckets 1 and 2, and ask it to amend the design accordingly. Hold the open items until Step 8 answers +them. + +## Step 8: Human Gate — Open Items, One at a Time + +Surface the open items from Step 7 **one at a time**, each as its own `AskUserQuestion` call. Never batch them BECAUSE +each answer routinely settles or reshapes the ones behind it, and a batch asks the user to decide in an order the design +does not follow. + +For each item, invoke `han-communication:explanation-guidance` and apply it to the wording. Each question leads with the +plain-language consequence of the choice, names two to four candidate answers, and says what changes in the contract +depending on the answer. After each answer, re-check the remaining open items: drop the ones the answer just settled, +and re-word the ones it changed. + +When every open item is answered, relaunch `han-core:software-architect` with one `Agent` call carrying the answers, and +have it fold them into the amended design. Record each answer in the design document as the justification for the +elements it settles. + +## Step 9: Dispatch the Adversarial Validation Round + +Launch `han-core:adversarial-validator` with one `Agent` call. Pass it, verbatim and unsummarized, the stated goal, the +full context brief with every finding and its citation, the amended design with its justifications, and the cut list. +Do not summarize — the validator needs the detail to attack effectively. Its job is to try to break the contract: find +the consumer the design forgets, the input state it does not define behavior for, the invariant a caller can violate, +the justification that does not actually follow from the goal, and the finding whose evidence does not support what the +design built on it. + +Record its output as numbered validation findings (V1, V2, V3, …). For each finding, decide and record one of: + +- **Accepted** — relaunch `han-core:software-architect` once with every accepted finding to revise the design, and note + what changed. +- **Rejected** — state why the finding does not hold, citing the goal, a context-brief finding, or a user decision from + Step 6 or Step 8. + +If the validator finds nothing, record what it checked and why that supports the design. A clean validation round is a +result, not an empty section. + +Cap the revision at one round. If the revised design would open new open items, list them in the design document's Open +Risks section rather than starting another gate cycle. + +## Step 10: Render the Design Document and Rewrite It for Readability + +Read [references/api-design-template.md](./references/api-design-template.md) and render it into +`{folder}/api-design.md`. Render rules: + +1. **Fill the front matter.** The goal, the interface, the chosen size and its one-line justification, the dispatched + roster, the starting point, and git availability. +2. **Carry the justification for every element.** The justification table is the section that makes the scope discipline + auditable; an element with an empty justification is a rendering bug, not a formatting choice. +3. **Keep the cut list.** Render it even when short. It is what tells the reader what the design deliberately does not + carry. +4. **Omit sections that have no content**, keeping the remaining sections in the template's order. Never emit a heading + with placeholder or "N/A" content. A clean validation round is content, not an empty section. +5. **Write the Summary last**, after every other section is filled: the contract in two or three sentences, the option + chosen and what it was chosen over, the decisions the user made at the two gates, the validation outcome, and any + signalled domain the band cap omitted. + +Then invoke `han-communication:readability-guidance` to source the shared readability standard into your context, and +dispatch `han-communication:readability-editor` with one `Agent` call to audit and rewrite the document. Pass it the +file path and the named audience: the engineer who will implement this contract and the reviewer who will approve it. +The editor reads han-communication's own canonical rule, so pass no rule path. It preserves every fact and edits prose +regions only — never inside code fences, pseudocode sketches, type signatures in code blocks, or finding-ID and +`file:line` citation identifiers. Apply its rewrite to the file. + +Then run the readability rule's standardized six-point self-check, which is in your context from the +`readability-guidance` invocation above, over the document's prose regions only. Correct every failure before +presenting. Its fidelity criterion is not optional: the standard governs how the content is said, never whether a +required fact appears. + +## Step 11: Present the Design + +Present the design to the user in a short closing message covering: + +- The three file paths written. +- The contract in two or three sentences. +- The size band and roster used, and git availability if git was absent. +- The cut list, in the same plain language the design document uses, so the user can reinstate anything they disagree + with. Any entry they reinstate re-enters the design with their direction as its justification. +- The open risks the validation round left standing, and any signalled domain the band cap omitted that would justify a + re-run at a larger size. +- The next step: this document is the input to a `tdd` run that implements the contract. diff --git a/han-coding/skills/design-an-api/references/api-design-template.md b/han-coding/skills/design-an-api/references/api-design-template.md new file mode 100644 index 00000000..ff804604 --- /dev/null +++ b/han-coding/skills/design-an-api/references/api-design-template.md @@ -0,0 +1,117 @@ +# API Design Document Template + +The `design-an-api` skill renders this template into `{folder}/api-design.md`. Fill every section that has content and +omit the ones that do not, keeping the remaining sections in the order below. Never emit a heading with placeholder or +"N/A" content. + +Replace every `{placeholder}` with the resolved value. Text in _italics_ under a heading describes what the section +holds and is not written into the rendered document. + +--- + +```yaml +--- +goal: "{the stated goal, quoted}" +goal_source: "{ticket reference, issue URL, file path, or 'described in conversation'}" +interface: "{what is being designed, and where it lives}" +size: "{small | medium | large}" +size_reason: "{one line: which signals put it in this band}" +roster: "{the dispatched agents, comma-separated}" +starting_point: "{working tree | merge base with {branch}}" +git_available: "{yes | no}" +--- +``` + +# API Design: {interface} + +## Summary + +_Two or three sentences stating the contract, then one line each for: the option chosen and what it was chosen over, +the decisions the user made at the two gates, the validation outcome, and any signalled domain the band cap omitted. +Written last, after every other section is filled._ + +## The Goal This Serves + +_The stated goal, quoted verbatim, with its source. Every justification in this document cites back to this section._ + +## The Designed Contract + +_The contract itself, in three parts:_ + +### Surface + +_The signatures, parameters, fields, and types, in a code fence. Pseudocode is fine; this is a design, not an +implementation._ + +### Invariants + +_The rules a caller can rely on and cannot violate: precedence between sources of a value, what persists and what does +not, lifecycle and ordering guarantees, and idempotency where the contract states one._ + +### Failure Behavior + +_What the contract does with invalid, missing, malformed, or hostile input, and what a caller observes when an +underlying operation fails._ + +## Why Each Element Is Here + +_One row per named element of the contract. The justification names the part of the goal the element descends from, or +the asked-for behavior it is a necessity of. An empty justification is a rendering bug._ + +| Element | What it does | Justification | +| -------- | ------------ | ---------------------------------------------------------------------- | +| `{name}` | {behavior} | {goal language it descends from, or the behavior it is a necessity of} | + +## Options Considered + +_Each option the architect produced, with its surface sketch and the reason it was chosen or rejected. The chosen +option is named first and marked as chosen._ + +### {Option name} — chosen + +_What it does differently, and the reasoning that selected it._ + +### {Option name} — rejected + +_What it does differently, and why it was rejected._ + +## Questions Resolved + +_Every question from the question round, numbered, each with its answer and the source of the answer: the goal, a +context-brief finding (F#), or the user's decision at a gate._ + +| # | Question | Answer | Source | +| --- | ---------- | -------- | --------------------------- | +| Q1 | {question} | {answer} | {goal / F# / user decision} | + +## Validation Findings + +_Every finding from the adversarial validation round, numbered V1, V2, V3, …, each marked accepted or rejected. An +accepted finding records what changed in the design. A rejected finding records why it does not hold, with its +citation. A validation round that found nothing records what it checked and why that supports the design._ + +| # | Finding | Disposition | What changed or why it does not hold | +| --- | --------- | --------------------- | ----------------------------------------- | +| V1 | {finding} | {accepted / rejected} | {change, or the citation that rejects it} | + +## Cut List + +_Everything this interface could plausibly carry that the goal does not ask for. Each entry names what it would have +done, in the same plain language the closing summary uses, and why it was cut. Rendered even when short. The reader can +reinstate any entry; their direction becomes its justification._ + +- **{What it would have done}** — cut because {reason, with the citation that supports the cut}. + +## Open Risks + +_What the validation round left standing, what the design depends on but could not verify, and any signalled domain the +band cap omitted. Each entry names the condition that would make it matter._ + +## Evidence + +_A pointer to `context-brief.md` for the numbered findings this design was built on, plus any finding this document +cites directly._ + +## Next Step + +_This document is the input to a `tdd` run that implements the contract._ diff --git a/han-planning/skills/plan-a-feature/SKILL.md b/han-planning/skills/plan-a-feature/SKILL.md index 65881a1a..eaf14195 100644 --- a/han-planning/skills/plan-a-feature/SKILL.md +++ b/han-planning/skills/plan-a-feature/SKILL.md @@ -5,8 +5,9 @@ description: > decision-by-decision, resolving dependencies as it goes. Use when the user wants to plan, design, scope, specify, or flesh out a new feature, capability, or system behavior before implementation. Produces a feature specification focused on system behaviors, not implementation detail. Does not refine or stress-test an existing plan — use - iterative-plan-review. Does not document already-built features — use project-documentation. Does not research - open-ended options before there is a feature to specify — use research. + iterative-plan-review. Does not document already-built features — use project-documentation. Does not design the + contract for an interface — use design-an-api. Does not research open-ended options before there is a feature to + specify — use research. arguments: size argument-hint: "[size: small | medium | large | dynamic] [feature description, optional: output folder path]" allowed-tools: Read, Write, Edit, Glob, Grep, Agent, Bash(find *), Bash(mkdir *), Bash(cp *) diff --git a/han-planning/skills/plan-implementation/SKILL.md b/han-planning/skills/plan-implementation/SKILL.md index afe4564a..446370c2 100644 --- a/han-planning/skills/plan-implementation/SKILL.md +++ b/han-planning/skills/plan-implementation/SKILL.md @@ -4,7 +4,8 @@ description: > Builds a feature implementation plan from an existing feature specification (or equivalent context) through a facilitated team conversation. Use when the user wants to plan how to implement, build, deliver, or ship a feature that has already been specified. Does not specify what the feature should do — use plan-a-feature first. Does - not refine or stress-test an already-written plan — use iterative-plan-review. + not design the contract for an interface — use design-an-api. Does not refine or stress-test an already-written plan — + use iterative-plan-review. arguments: size argument-hint: "[size: small | medium | large | dynamic] [feature specification path, optional: additional context]" allowed-tools: Read, Write, Edit, Glob, Grep, Agent, Bash(find *), Bash(git *), Bash(mkdir *), Bash(cp *) From 97779d1a7152a8fa446d8c2b574cde3ecd0a8ce5 Mon Sep 17 00:00:00 2001 From: River Lynn Bailey Date: Fri, 7 Aug 2026 09:31:11 -0600 Subject: [PATCH 2/3] docs(han-coding): document design-an-api and apply the guidance review fixes Adds the long-form doc, the plugin README scent line, the skills index entry, the workflows chain, and the CLAUDE.md map entries. Review fixes against the plugin-building guidance: a testable git criterion for the starting-point question, error handling for a failed discovery agent and a single-option architect round, explicit continuation after each mid-workflow skill invocation, and a boundary-data signal replacing the unfamiliar-area signal that had no consumer now that codebase-explorer runs at every band. --- CLAUDE.md | 5 +- docs/skills/README.md | 3 + docs/workflows.md | 8 +- han-coding/README.md | 3 + han-coding/docs/skills/design-an-api.md | 153 +++++++++++++++++++++++ han-coding/skills/design-an-api/SKILL.md | 67 ++++++---- 6 files changed, 211 insertions(+), 28 deletions(-) create mode 100644 han-coding/docs/skills/design-an-api.md diff --git a/CLAUDE.md b/CLAUDE.md index 3908a2a0..0144cde5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,7 +20,8 @@ implementation: specifying with `plan-a-feature`, planning the build with `plan- `iterative-plan-review`, plus the `discussion-facilitator` agent that audits a planning discussion in progress; depends on `han-communication` and `han-core` and is bundled by the `han` meta-plugin), `han-coding` (the coding skills -you reach for while working in code: writing it with `tdd` and `refactor`, plus reviewing, overviewing, analyzing, +you reach for while working in code: writing it with `tdd` and `refactor`, designing an interface contract with +`design-an-api`, plus reviewing, overviewing, analyzing, testing, investigating, and standardizing it with `code-review`, `code-overview`, `architectural-analysis`, `automated-test-planning`, `manual-test-planning`, `investigate`, and `coding-standard`; depends on `han-communication` and `han-core` and is bundled by the `han` meta-plugin), @@ -109,7 +110,7 @@ han-plugin-builder skill: │ ├── skills/ # Planning skill directories, each with SKILL.md + references/ │ ├── docs/ # In-plugin long-form docs: docs/skills/{name}.md + docs/agents/discussion-facilitator.md │ └── references/ # Both kinds: han-planning-owned canonical files (planning-boundary-rule.md, scope-justification-rule.md, operator-escalation-rule.md) beside vendored copies (yagni-rule.md, evidence-rule.md, config-rule.md). Each owned file opens by saying so; do not overwrite one in a re-sync sweep -├── han-coding/ # Coding plugin: tdd, refactor, code-review, code-overview, architectural-analysis, automated-test-planning, manual-test-planning, investigate, coding-standard (the skills for working in code; depends on han-communication and han-core; bundled by the han meta-plugin) +├── han-coding/ # Coding plugin: tdd, refactor, design-an-api, code-review, code-overview, architectural-analysis, automated-test-planning, manual-test-planning, investigate, coding-standard (the skills for working in code; depends on han-communication and han-core; bundled by the han meta-plugin) │ ├── README.md # Light front door + scent-line skills list │ ├── .claude-plugin/ │ │ └── plugin.json diff --git a/docs/skills/README.md b/docs/skills/README.md index aeada121..9eab0342 100644 --- a/docs/skills/README.md +++ b/docs/skills/README.md @@ -31,6 +31,9 @@ skill-and-agent split is fuzzy, read [Concepts](../concepts.md) first. or specified files, with a size-scaled roster of specialist agents. - [`/coding-standard`](../../han-coding/docs/skills/coding-standard.md) — Create and update coding standards from existing patterns or evidence-based research. +- [`/design-an-api`](../../han-coding/docs/skills/design-an-api.md) — Design the contract for an API change inside one + codebase, with every element justified from one stated goal and the design run past a question round and an + adversarial validation round. - [`/edit-for-readability`](../../han-communication/docs/skills/edit-for-readability.md) — Rewrite the prose of a target you already have against the shared readability standard, preserving every fact. - [`/explanation-guidance`](../../han-communication/docs/skills/explanation-guidance.md) — Surface the shared standard diff --git a/docs/workflows.md b/docs/workflows.md index 1d7bf029..2ba8441b 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -80,8 +80,10 @@ prepare the ground for a test-first build. flowchart TD review["/code-review"] --> refactor["/refactor"] arch["/architectural-analysis"] --> refactor + arch --> design["/design-an-api"] + design --> tdd["/tdd"] review --> pr["/post-code-review-to-pr"] - refactor --> tdd["/tdd"] + refactor --> tdd tdd --> prdesc["/update-pr-description"] investigate["/investigate"] --> iterate["/iterative-plan-review"] ``` @@ -95,6 +97,10 @@ flowchart TD work orders. - **[`/refactor`](../han-coding/docs/skills/refactor.md) → [`/tdd`](../han-coding/docs/skills/tdd.md).** Preparatory refactoring makes the change easy, then `/tdd` makes the easy change. +- **[`/architectural-analysis`](../han-coding/docs/skills/architectural-analysis.md) → + [`/design-an-api`](../han-coding/docs/skills/design-an-api.md) → [`/tdd`](../han-coding/docs/skills/tdd.md).** Judge + the structure you are designing into, shape the contract against one stated goal, then implement it test-first. The + analysis step is optional; `/design-an-api` runs its own discovery wave when you start there. - **[`/investigate`](../han-coding/docs/skills/investigate.md) → [`/iterative-plan-review`](../han-planning/docs/skills/iterative-plan-review.md).** Root-cause the bug, then stress-test the proposed fix. diff --git a/han-coding/README.md b/han-coding/README.md index 107af3cf..c719c66a 100644 --- a/han-coding/README.md +++ b/han-coding/README.md @@ -12,6 +12,9 @@ specialist agents to cover each dimension in parallel. Reach for it once there i enforced observed-failure gate; it writes code, not a document. - [`/refactor`](docs/skills/refactor.md) — Restructure existing code without changing its behavior through a test-gated loop that re-runs the full suite after every small step. +- [`/design-an-api`](docs/skills/design-an-api.md) — Design the contract for an API change inside one codebase, with + every element justified from one stated goal and the design run past a question round and an adversarial validation + round. - [`/code-review`](docs/skills/code-review.md) — Run a comprehensive code review on the current branch or specified files, with a size-scaled roster of specialist agents. - [`/code-overview`](docs/skills/code-overview.md) — Produce a human-readable, progressive-disclosure overview of diff --git a/han-coding/docs/skills/design-an-api.md b/han-coding/docs/skills/design-an-api.md new file mode 100644 index 00000000..21b4908c --- /dev/null +++ b/han-coding/docs/skills/design-an-api.md @@ -0,0 +1,153 @@ +# /design-an-api + +Operator documentation for the `/design-an-api` skill in the han plugin. This document helps you decide _when_ and _how_ +to use the skill. For what the skill does internally, read the skill definition at +[`han-coding/skills/design-an-api/SKILL.md`](../../skills/design-an-api/SKILL.md). + +> See also: [Plugin README](../../README.md) · [Repo root](../../../README.md) · +> [All skills](../../../docs/skills/README.md) · [All agents](../../../docs/agents/README.md) · +> [YAGNI](../../../docs/yagni.md) + +## TL;DR + +- **What it does.** Designs the contract for an API change inside one codebase, running the design past a question round + and an adversarial validation round before you commit to it. +- **When to use it.** You know what the capability should do, and you need to decide the shape of the interface that + delivers it, sized for roughly one pull request. +- **What you get back.** A run folder holding a context brief, a design-options document, and the final design document + that a `/tdd` run implements against. + +## Key concepts + +- **The stated goal.** One ticket, issue, or written requirement the whole design answers to. The skill will not run + without one, because it is the only thing the design can be justified against. +- **The justification field.** Every parameter, field, type, default, precedence rule, and failure behavior names either + the goal language it descends from or the asked-for behavior it is a necessity of. +- **The cut list.** Anything the interface could plausibly carry that the goal never asks for, recorded with what it + would have done so you can put it back. +- **The two gates.** You pick the design option, and later you answer each open item one at a time. Everything else + runs unattended. + +## When to use it + +**Invoke when:** + +- A ticket asks for a capability and the real work is deciding the interface: a component's props, a function surface, + URL or query parameters, an event payload, or a module boundary. +- You are about to change a shared surface and want the consumer audit and the failure behavior settled before anyone + writes code. +- A branch already carries a half-built attempt and you want the contract redesigned from the merge base instead. + +**Do not invoke for:** + +- **Deciding what a feature should do.** Use [`/plan-a-feature`](../../../han-planning/docs/skills/plan-a-feature.md) + instead; it settles behavior, this settles contract shape. +- **Planning how to deliver the work.** Use + [`/plan-implementation`](../../../han-planning/docs/skills/plan-implementation.md) instead. +- **Judging the architecture already in the codebase.** Use + [`/architectural-analysis`](./architectural-analysis.md) instead; it assesses what exists rather than designing what + comes next. +- **Writing the code.** Use [`/tdd`](./tdd.md) to implement the design, or [`/refactor`](./refactor.md) to restructure + existing code without changing its behavior. + +## How to invoke it + +Run `/design-an-api` in Claude Code. + +Give it: + +1. **The goal.** A ticket reference, issue URL, file path, or one paragraph describing what this change is for. A sharp + goal names the user-visible outcome ("a link can prefill the first two steps of the signup flow"). A thin goal names + only the mechanism ("add query param support"), which gives the justification field nothing to cite. +2. **The interface.** Which component, function, module, route, or payload is being designed, and where it lives. A new + surface with no file yet is fine; name the module it will live in. +3. **A size, optionally.** `small`, `medium`, `large`, or `dynamic` as the first argument. Leave it off and the skill + classifies from signals it detects in the interface and its consumers. + +Example prompts: + +- `/design-an-api`. _"Design the change to FlowProvider that lets URL query values prefill a flow's steps, per + ticket ABC-142."_ +- `/design-an-api medium https://github.com/acme/app/issues/88 the exported cache client surface in src/cache/`. + +## What you get back + +Three files in one run folder, placed under your configured `output-directory` or a folder named for the interface +under the project's documentation root: + +- **`context-brief.md`.** Numbered findings `F1`, `F2`, `F3`, … from the discovery wave. Each finding carries a + `file:line` citation or the label `inferred`, plus the agent that reported it. Conflicting findings stay as separate + entries with both citations rather than being resolved silently. +- **`design-options.md`.** The two or three options the architect produced, with one recommendation, the rejected + alternatives and why, and pseudocode sketches of each option's signatures. +- **`api-design.md`.** The deliverable. It holds the designed contract in three parts (surface, invariants, failure + behavior), the justification table, the options considered, the questions resolved (`Q1`, `Q2`, … each with its + answer's source), the validation findings (`V1`, `V2`, … each accepted or rejected), the cut list, and the open + risks. + +If `api-design.md` already exists in the folder, the run writes a date-suffixed file instead and tells you which. It +never overwrites. + +## How to get the most out of it + +- **Paste the ticket, do not paraphrase it.** The justification field quotes the goal. A paraphrase you wrote from + memory becomes the scope authority, and it drifts. +- **Answer the open items with the consequence in mind.** Each one is surfaced with candidate answers and what changes + in the contract; the answer you give becomes the recorded justification for those elements. +- **Read the cut list before you approve.** It is the only place the design tells you what it deliberately left out. + Reinstating an entry is one sentence, and your direction becomes its justification. +- **Re-run larger when the closing summary names an omitted domain.** The band cap can drop a signalled specialist. The + summary says which one. +- **Pair with `/tdd` next.** The design document is written to be the input to a test-first implementation run. + +## YAGNI + +This skill is enforcing, not advisory. An element that cannot fill its justification field does not enter the design at +all; it moves to the cut list with what it would have done and why it was cut. The cut list appears in the closing +message as well as the document, so a wrong cut is visible in the turn rather than buried in a file you have no reason +to open. + +One floor bounds that discipline: silence never cuts a necessity. A goal that never mentions a caching layer justifies +cutting one, but the same goal's silence about invalid input, error behavior, and types cuts nothing, because those are +necessities of the surface it did ask for. See [YAGNI](../../../docs/yagni.md) for the shared evidence and +simpler-version gates this sits beside. + +## Cost and latency + +A small run dispatches four agents in sequence-with-one-parallel-wave: the discovery wave, then the architect, the +junior developer, and the adversarial validator. A large run adds up to four signalled specialists to the discovery +wave, for seven or eight agents total. The architect is the most expensive single participant, because it runs up to +four times: once for options and once after each of the question round, the open items, and the validation round. + +This is an infrequent, high-signal run. It sits before implementation, not inside a tight loop. + +## In more detail + +The skill exists because the arrangement it packages was already working by hand. A session documented in +[issue #173](https://github.com/testdouble/han/issues/173) dispatched `han-core:software-architect`, +`han-core:junior-developer`, and `han-core:adversarial-validator` directly, against a hand-assembled context brief, to +design a query-parameter prefill contract on a shared React flow provider. The designed API shipped essentially as +specified and survived a later code review. One junior-developer question reversed a naming decision before any code +existed. + +What the skill adds to that arrangement is the discovery step the session assembled ad hoc, the size band that scales +the roster, and the two gates in fixed positions. What it deliberately does not add is the full analyst fan-out that +`/architectural-analysis` runs: that roster is built to assess an existing module across every dimension, and it is +oversized for shaping one contract. + +## Related documentation + +- [Plugin README](../../README.md). The plugin's front door: its skills, agents, and how they fit together. +- [Repo root README](../../../README.md). The Han suite landing page. Start here if you arrived from outside the docs + tree. +- [YAGNI](../../../docs/yagni.md). The evidence-based "You Aren't Gonna Need It" rule: the two gates, the + acceptable-evidence list, the named anti-patterns, and the deferral format. +- [`/tdd`](./tdd.md). The implementation run this design document feeds. +- [`/architectural-analysis`](./architectural-analysis.md). Assesses the module you are about to change, when you want + the existing structure judged before designing into it. +- [`software-architect`](../../../han-core/docs/agents/software-architect.md). Produces the options and every + amendment. +- [`junior-developer`](../../../han-core/docs/agents/junior-developer.md). Questions the chosen option as a generalist + who was not in the room. +- [`adversarial-validator`](../../../han-core/docs/agents/adversarial-validator.md). Attacks the amended design and the + evidence under it. diff --git a/han-coding/skills/design-an-api/SKILL.md b/han-coding/skills/design-an-api/SKILL.md index 592254cd..61204cc9 100644 --- a/han-coding/skills/design-an-api/SKILL.md +++ b/han-coding/skills/design-an-api/SKILL.md @@ -89,11 +89,12 @@ where it lives. Confirm it resolves to real files using `Glob` and `Read`. If th file yet, resolve instead the module or directory it will live in and the consumers that will call it. If neither resolves, ask the user to name the surface before going further. -**Resolve the starting point.** Read the `current branch` value from Project Context. If the current branch already -carries a partial or abandoned attempt at this change, ask the user in one short message whether to design from the -branch as it stands or from the merge base with the default branch, ignoring the branch's changes. Use `git` to read the -merge-base state when they choose the merge base. State the chosen starting point in one line. When git is unavailable -or the branch carries nothing relevant, the working tree is the starting point and no question is asked. +**Resolve the starting point.** Read the `current branch` value from Project Context. Run +`git diff --name-only $(git merge-base HEAD origin/HEAD)...HEAD` and check whether any interface file resolved above +appears in the output. Only when one does, ask the user in one short message whether to design from the branch as it +stands or from the merge base, ignoring the branch's changes; read the merge-base state with `git show` when they +choose the merge base. In every other case — no interface file changed on the branch, git unavailable, or the command +fails — the working tree is the starting point and no question is asked. State the chosen starting point in one line. **Resolve project context.** If `CLAUDE.md` is present, read its `## Project Discovery` section for conventions. Fall back to `project-discovery.md`. These resolve language, framework, and convention questions so the agents infer less. If @@ -127,18 +128,18 @@ touches. These signals drive both the band and the roster: or carries auth, tokens, secrets, or PII across the surface. - **Failure-path signal:** the contract has to state what happens on failure — outbound calls, timeouts, retries, idempotency, partial writes, or a failure that would page someone. +- **Boundary-data signal:** the contract moves data across a module boundary, or how errors propagate across that + boundary is itself part of what the design has to decide. - **System-seam signal:** the interface crosses a deployable unit or bounded-context boundary — an RPC or HTTP contract with a sibling service, a message broker topic, or a shared store across services. -- **Unfamiliar-area signal:** the interface's surrounding module is large or its structure is not legible from a first - read. **Classify the size.** Default to small. Escalate only when a band's signal is clearly present; when a signal is borderline, stay at the smaller band. - **Small** _(default)_ — one interface with a contained consumer set inside one module, and no data-contract, - trust-boundary, failure-path, or system-seam signal. The ordering signal may be present or absent. -- **Medium** — a consumer-spread signal, OR exactly one of the ordering, data-contract, trust-boundary, or failure-path - signals. + trust-boundary, failure-path, boundary-data, or system-seam signal. The ordering signal may be present or absent. +- **Medium** — a consumer-spread signal, OR exactly one of the ordering, data-contract, trust-boundary, failure-path, + or boundary-data signals. - **Large** — two or more of those cross-cutting signals together, OR a system-seam signal is present, OR `$size` is `large`. @@ -164,7 +165,7 @@ whose domain the contract never touches. A conversational override ("design this | Specialist | Add when | Min band | | --------------------------------------- | ---------------------- | -------- | | `han-core:structural-analyst` | Consumer-spread signal | Medium | -| `han-core:behavioral-analyst` | Unfamiliar-area signal | Medium | +| `han-core:behavioral-analyst` | Boundary-data signal | Medium | | `han-core:concurrency-analyst` | Ordering signal | Medium | | `han-core:data-engineer` | Data-contract signal | Medium | | `han-core:on-call-engineer` | Failure-path signal | Medium | @@ -209,7 +210,13 @@ each carrying the finding, its provenance (a `file:line` citation, or the label it. Merge duplicates and keep conflicting findings as separate numbered entries with both citations, rather than picking a winner. Apply the evidence rule from [../../references/evidence-rule.md](../../references/evidence-rule.md) to every finding. When a question the design depends on has no evidence at any tier, record it as an open item rather than -guessing. +guessing, and carry it into Step 8 alongside the open items the question round produces. + +If a specialist returns nothing usable or fails, record a one-line note in the context brief naming the agent and the +domain left uncovered, and continue. A missing specialist narrows the design's evidence; it does not stop the run. If +`han-core:codebase-explorer` returns nothing usable, relaunch it once with the interface's file paths spelled out. If +the second attempt also returns nothing, stop and tell the user the interface could not be discovered, naming the paths +that were searched. ## Step 5: Dispatch the Architect for Options @@ -228,12 +235,20 @@ and the resolved project conventions. Its brief must ask for: Write the returned options to `{folder}/design-options.md`. +If the architect returns one option, or returns options whose elements carry no justification, relaunch it once with the +missing requirement restated. If the second attempt still returns one option, carry that option forward and record in +the design document that only one viable option was produced, with the architect's stated reason. + ## Step 6: Human Gate — The User Picks an Option +Before writing the question, invoke `han-communication:explanation-guidance` to source the shared explanation standard +into your context. After that skill returns, proceed immediately to the question below — do not stop there. The +standard stays in context for Step 8, so do not invoke it a second time. + Present the options to the user with `AskUserQuestion`: one option per choice, the recommendation named first and -labelled as recommended, each with its one-line reasoning. Before writing the question, invoke -`han-communication:explanation-guidance` and apply it, so each option reads as an outcome the user could observe rather -than a mechanism. Include the cut list in the surrounding message so the user sees what the design is giving up. +labelled as recommended, each with its one-line reasoning. Apply the explanation standard to the wording, so each option +reads as an outcome the user could observe rather than a mechanism. Include the cut list in the surrounding message so +the user sees what the design is giving up. Handle the response: @@ -263,12 +278,13 @@ them. ## Step 8: Human Gate — Open Items, One at a Time -Surface the open items from Step 7 **one at a time**, each as its own `AskUserQuestion` call. Never batch them BECAUSE +Surface the open items — those the question round produced in Step 7, plus any no-evidence item recorded in Step 4 — +**one at a time**, each as its own `AskUserQuestion` call. Never batch them BECAUSE each answer routinely settles or reshapes the ones behind it, and a batch asks the user to decide in an order the design does not follow. -For each item, invoke `han-communication:explanation-guidance` and apply it to the wording. Each question leads with the -plain-language consequence of the choice, names two to four candidate answers, and says what changes in the contract +Apply the explanation standard already in your context from Step 6 to each question's wording. Each question leads with +the plain-language consequence of the choice, names two to four candidate answers, and says what changes in the contract depending on the answer. After each answer, re-check the remaining open items: drop the ones the answer just settled, and re-word the ones it changed. @@ -285,12 +301,12 @@ the consumer the design forgets, the input state it does not define behavior for the justification that does not actually follow from the goal, and the finding whose evidence does not support what the design built on it. -Record its output as numbered validation findings (V1, V2, V3, …). For each finding, decide and record one of: +Record its output as numbered validation findings (V1, V2, V3, …), and mark each one: -- **Accepted** — relaunch `han-core:software-architect` once with every accepted finding to revise the design, and note - what changed. -- **Rejected** — state why the finding does not hold, citing the goal, a context-brief finding, or a user decision from - Step 6 or Step 8. +- **Rejected** — the finding does not hold. Record why, citing the goal, a context-brief finding, or a user decision + from Step 6 or Step 8. +- **Accepted** — the finding holds. Once every finding is marked, relaunch `han-core:software-architect` a single time + carrying all accepted findings together, and record what changed for each. If the validator finds nothing, record what it checked and why that supports the design. A clean validation round is a result, not an empty section. @@ -315,8 +331,9 @@ Read [references/api-design-template.md](./references/api-design-template.md) an chosen and what it was chosen over, the decisions the user made at the two gates, the validation outcome, and any signalled domain the band cap omitted. -Then invoke `han-communication:readability-guidance` to source the shared readability standard into your context, and -dispatch `han-communication:readability-editor` with one `Agent` call to audit and rewrite the document. Pass it the +Then invoke `han-communication:readability-guidance` to source the shared readability standard into your context. After +that skill returns, proceed immediately to the rewrite below — do not stop there. Dispatch +`han-communication:readability-editor` with one `Agent` call to audit and rewrite the document. Pass it the file path and the named audience: the engineer who will implement this contract and the reviewer who will approve it. The editor reads han-communication's own canonical rule, so pass no rule path. It preserves every fact and edits prose regions only — never inside code fences, pseudocode sketches, type signatures in code blocks, or finding-ID and From 75fea2020f1c5f9c19a2bf78253ed4d26cafb5a7 Mon Sep 17 00:00:00 2001 From: River Lynn Bailey Date: Mon, 10 Aug 2026 07:51:31 -0600 Subject: [PATCH 3/3] fix(han-coding): correct design-an-api's size bands, roster, and failure paths Two defects made the skill's own rules contradict each other. The ordering signal matched both the Small band (which said it "may be present or absent") and the Medium band (which counted it among the five escalating signals), and because the concurrency analyst carries a Medium minimum, the signal could fire at small with no specialist able to answer it. The roster listed the architect as running in Steps 5, 7, and 9, omitting the Step 8 relaunch that folds in the open-item answers. The starting-point check ran `git diff $(git merge-base HEAD origin/HEAD)...HEAD`. When origin/HEAD is unset the substitution empties, git reads the rest as HEAD...HEAD, and the command exits clean with no output, so a branch that did modify the interface was reported as untouched. It now reads the same default-branch probe the other Han skills use and treats `unknown` explicitly. Also: the overwrite guard covered only api-design.md, leaving the context brief and options document to be silently overwritten; Step 5 retried the architect for missing justifications but had no disposition when the retry also came back unjustified; Step 8 had no path for zero open items; and the roster caps were written as ranges whose floors the rules cannot produce, since a large band reached by a lone system-seam signal dispatches five agents, not seven. --- han-coding/docs/skills/design-an-api.md | 11 ++-- han-coding/skills/design-an-api/SKILL.md | 59 +++++++++++-------- .../references/api-design-template.md | 4 +- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/han-coding/docs/skills/design-an-api.md b/han-coding/docs/skills/design-an-api.md index 21b4908c..78a72785 100644 --- a/han-coding/docs/skills/design-an-api.md +++ b/han-coding/docs/skills/design-an-api.md @@ -85,8 +85,8 @@ under the project's documentation root: answer's source), the validation findings (`V1`, `V2`, … each accepted or rejected), the cut list, and the open risks. -If `api-design.md` already exists in the folder, the run writes a date-suffixed file instead and tells you which. It -never overwrites. +If any of the three files already exists in the folder, the run date-suffixes all three so one run's files stay +together, and tells you which names it wrote. It never overwrites. ## How to get the most out of it @@ -115,9 +115,10 @@ simpler-version gates this sits beside. ## Cost and latency A small run dispatches four agents in sequence-with-one-parallel-wave: the discovery wave, then the architect, the -junior developer, and the adversarial validator. A large run adds up to four signalled specialists to the discovery -wave, for seven or eight agents total. The architect is the most expensive single participant, because it runs up to -four times: once for options and once after each of the question round, the open items, and the validation round. +junior developer, and the adversarial validator. A large run adds as many as four signalled specialists to the discovery +wave, for up to eight agents total. Only signalled specialists are added, so a run at a size you set by hand can sit +under its band's ceiling. The architect is the most expensive single participant, because it runs up to four times: once +for options and once after each of the question round, the open items, and the validation round. This is an infrequent, high-signal run. It sits before implementation, not inside a tight loop. diff --git a/han-coding/skills/design-an-api/SKILL.md b/han-coding/skills/design-an-api/SKILL.md index 61204cc9..8b25c234 100644 --- a/han-coding/skills/design-an-api/SKILL.md +++ b/han-coding/skills/design-an-api/SKILL.md @@ -19,6 +19,7 @@ allowed-tools: Read, Write, Glob, Grep, Agent, Bash(git *), Bash(find *), Bash(m - git installed: !`which git 2>/dev/null || echo "not installed"` - current branch: !`git branch --show-current 2>/dev/null || echo "no git branch"` +- default branch: !`git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null || echo unknown` - CLAUDE.md: !`find . -maxdepth 1 -name "CLAUDE.md" -type f` - project-discovery.md: !`find . -maxdepth 3 -name "project-discovery.md" -type f` - personal config directory: !`echo "${CLAUDE_CONFIG_DIR:-$HOME/.claude}"` @@ -89,12 +90,14 @@ where it lives. Confirm it resolves to real files using `Glob` and `Read`. If th file yet, resolve instead the module or directory it will live in and the consumers that will call it. If neither resolves, ask the user to name the surface before going further. -**Resolve the starting point.** Read the `current branch` value from Project Context. Run -`git diff --name-only $(git merge-base HEAD origin/HEAD)...HEAD` and check whether any interface file resolved above -appears in the output. Only when one does, ask the user in one short message whether to design from the branch as it -stands or from the merge base, ignoring the branch's changes; read the merge-base state with `git show` when they -choose the merge base. In every other case — no interface file changed on the branch, git unavailable, or the command -fails — the working tree is the starting point and no question is asked. State the chosen starting point in one line. +**Resolve the starting point.** Read the `current branch` and `default branch` values from Project Context. When +`default branch` reads `unknown`, `origin/HEAD` is unset and there is no base to compare against: the working tree is +the starting point, no question is asked, and the run continues. Otherwise run +`git diff --name-only {default branch}...HEAD` and check whether any interface file resolved above appears in the +output. Only when one does, ask the user in one short message whether to design from the branch as it stands or from +the merge base, ignoring the branch's changes; read the merge-base state with `git show` when they choose the merge +base. In every other case — no interface file changed on the branch, git unavailable, or the command fails — the +working tree is the starting point and no question is asked. State the chosen starting point in one line. **Resolve project context.** If `CLAUDE.md` is present, read its `## Project Discovery` section for conventions. Fall back to `project-discovery.md`. These resolve language, framework, and convention questions so the agents infer less. If @@ -109,9 +112,11 @@ and `{folder}/api-design.md`. Resolve `{folder}` in this order: 3. Otherwise, choose a 2-to-4-word kebab-case folder named for the interface, under a documentation root surfaced via `CLAUDE.md`, `project-discovery.md`, or a Glob fallback (`docs/plans/`, `docs/`). -Create the folder with `mkdir -p`. If `api-design.md` already exists there, write to a date-suffixed name (for example -`api-design-2026-08-07.md`) and state which files were written; never silently overwrite. State the chosen folder in one -short line and proceed without waiting for confirmation. +Create the folder with `mkdir -p`. Check all three names with `Glob` before writing anything. If any of the three +already exists there, write every file this run produces to a date-suffixed name (for example `api-design-2026-08-07.md` +alongside `context-brief-2026-08-07.md` and `design-options-2026-08-07.md`) so one run's files stay together, and state +which files were written; never silently overwrite. State the chosen folder in one short line and proceed without +waiting for confirmation. ## Step 2: Detect Signals and Classify Size @@ -136,8 +141,8 @@ touches. These signals drive both the band and the roster: **Classify the size.** Default to small. Escalate only when a band's signal is clearly present; when a signal is borderline, stay at the smaller band. -- **Small** _(default)_ — one interface with a contained consumer set inside one module, and no data-contract, - trust-boundary, failure-path, boundary-data, or system-seam signal. The ordering signal may be present or absent. +- **Small** _(default)_ — one interface with a contained consumer set inside one module, and none of the ordering, + data-contract, trust-boundary, failure-path, boundary-data, or system-seam signals. - **Medium** — a consumer-spread signal, OR exactly one of the ordering, data-contract, trust-boundary, failure-path, or boundary-data signals. - **Large** — two or more of those cross-cutting signals together, OR a system-seam signal is present, OR `$size` is @@ -156,7 +161,7 @@ whose domain the contract never touches. A conversational override ("design this - `han-core:codebase-explorer` — discovers the current surface, its consumers, and the constraints the design has to live inside. Feeds the context brief. Runs in Step 4. -- `han-core:software-architect` — produces the options document and every later amendment. Runs in Steps 5, 7, and 9. +- `han-core:software-architect` — produces the options document and every later amendment. Runs in Steps 5, 7, 8, and 9. - `han-core:junior-developer` — questions the chosen option as a generalist who was not in the room. Runs in Step 7. - `han-core:adversarial-validator` — attacks the amended design and the evidence under it. Runs in Step 9. @@ -172,10 +177,12 @@ whose domain the contract never touches. A conversational override ("design this | `han-core:system-architect` | System-seam signal | Large | | `han-core:adversarial-security-analyst` | Trust-boundary signal | Medium | -Roster caps by band: **small** runs the spine only (4 agents); **medium** adds one or two signalled specialists (5–6 -agents); **large** adds up to four, including `han-core:system-architect` when a system-seam signal is present (7–8 -agents). If more specialists are signalled than the cap allows, keep the band's count, prefer the specialists covering -the strongest signals, and name the omitted domains in the design document's summary so the user can re-run larger. +Roster caps by band are ceilings, not quotas: **small** runs the spine only (4 agents); **medium** adds at most two +signalled specialists (up to 6 agents); **large** adds at most four, including `han-core:system-architect` when a +system-seam signal is present (up to 8 agents). A band reached by override rather than by signal can sit well under its +ceiling; add no specialist whose signal is absent just to fill the band. If more specialists are signalled than the cap +allows, keep the band's count, prefer the specialists covering the strongest signals, and name the omitted domains in +the design document's summary so the user can re-run larger. Extra agents named in the project config's `## Extra Agents` list join the signal-selected pool and compete under the same signals and band caps, per [config-rule.md](../../references/config-rule.md): add one only when a signal in the @@ -237,7 +244,10 @@ Write the returned options to `{folder}/design-options.md`. If the architect returns one option, or returns options whose elements carry no justification, relaunch it once with the missing requirement restated. If the second attempt still returns one option, carry that option forward and record in -the design document that only one viable option was produced, with the architect's stated reason. +the design document that only one viable option was produced, with the architect's stated reason. If the second attempt +still leaves elements unjustified, do not carry those elements: move each one to the cut list with what it would have +done and the note that no justification was produced for it, so the gap reaches the user in Step 6 rather than passing +as designed. ## Step 6: Human Gate — The User Picks an Option @@ -278,8 +288,11 @@ them. ## Step 8: Human Gate — Open Items, One at a Time -Surface the open items — those the question round produced in Step 7, plus any no-evidence item recorded in Step 4 — -**one at a time**, each as its own `AskUserQuestion` call. Never batch them BECAUSE +If Step 7 and Step 4 left no open item, say so in one line, skip this gate, and go straight to Step 9. The gate exists +to settle open items; with none to settle it has nothing to ask and no answer to fold in. + +Otherwise surface the open items — those the question round produced in Step 7, plus any no-evidence item recorded in +Step 4 — **one at a time**, each as its own `AskUserQuestion` call. Never batch them BECAUSE each answer routinely settles or reshapes the ones behind it, and a batch asks the user to decide in an order the design does not follow. @@ -319,8 +332,8 @@ Risks section rather than starting another gate cycle. Read [references/api-design-template.md](./references/api-design-template.md) and render it into `{folder}/api-design.md`. Render rules: -1. **Fill the front matter.** The goal, the interface, the chosen size and its one-line justification, the dispatched - roster, the starting point, and git availability. +1. **Fill the front matter.** The goal and where it came from, the interface, the chosen size and its one-line + justification, the dispatched roster, the starting point, and git availability. 2. **Carry the justification for every element.** The justification table is the section that makes the scope discipline auditable; an element with an empty justification is a rendering bug, not a formatting choice. 3. **Keep the cut list.** Render it even when short. It is what tells the reader what the design deliberately does not @@ -328,8 +341,8 @@ Read [references/api-design-template.md](./references/api-design-template.md) an 4. **Omit sections that have no content**, keeping the remaining sections in the template's order. Never emit a heading with placeholder or "N/A" content. A clean validation round is content, not an empty section. 5. **Write the Summary last**, after every other section is filled: the contract in two or three sentences, the option - chosen and what it was chosen over, the decisions the user made at the two gates, the validation outcome, and any - signalled domain the band cap omitted. + chosen and what it was chosen over, the decisions the user made at each gate that ran, the validation outcome, and + any signalled domain the band cap omitted. Then invoke `han-communication:readability-guidance` to source the shared readability standard into your context. After that skill returns, proceed immediately to the rewrite below — do not stop there. Dispatch diff --git a/han-coding/skills/design-an-api/references/api-design-template.md b/han-coding/skills/design-an-api/references/api-design-template.md index ff804604..e2eeb2cd 100644 --- a/han-coding/skills/design-an-api/references/api-design-template.md +++ b/han-coding/skills/design-an-api/references/api-design-template.md @@ -27,8 +27,8 @@ git_available: "{yes | no}" ## Summary _Two or three sentences stating the contract, then one line each for: the option chosen and what it was chosen over, -the decisions the user made at the two gates, the validation outcome, and any signalled domain the band cap omitted. -Written last, after every other section is filled._ +the decisions the user made at each gate that ran, the validation outcome, and any signalled domain the band cap +omitted. Written last, after every other section is filled._ ## The Goal This Serves