API and Interface Design
Define the contract before the implementation. This skill is for public or cross-team interfaces
where downstream consumers can depend on every observable behavior, including the ones you did not
mean to promise.
When to Use
- Designing a new public HTTP API, CLI command, webhook, SDK surface, or plugin contract
- Changing an existing interface that other teams, tools, or customers already consume
- Clarifying breaking-change policy before implementation starts
- Tightening the interface section of
spec-driven-development for a compatibility-sensitive feature
When NOT to Use
| Instead of api-and-interface-design |
Use |
| Internal implementation design inside one module |
spec-driven-development |
| Writing user-facing docs for a finished API |
api-documentation |
| Retiring or replacing an old interface |
deprecation-and-migration |
| Narrow bug fixes with no contract change |
do the fix directly |
Workflow
1. Identify the real contract boundary
Write down:
- Who consumes this interface? Humans, services, CLI users, integrations, third-party developers
- What is observable? Inputs, outputs, error codes, ordering, timing, idempotency, pagination, retries
- What must stay stable? Field names, response structure, exit codes, callback payloads, invariants
If the consumer or stability target is unclear, you are not ready to implement.
2. Draft the contract before code
Create a contract document or spec section before touching implementation:
## Interface Contract: createWidget
**Interface type**: REST API / CLI / SDK / webhook
**Consumers**: Internal services + external customers
**Stability**: stable / beta / experimental
### Inputs
- Method / command / function name:
- Required parameters:
- Optional parameters:
- Validation rules:
### Outputs
- Success shape:
- Error shape:
- Ordering / pagination guarantees:
### Invariants
- [Behavior that must remain true]
### Non-Goals
- [What this interface deliberately does not promise]
3. Run a Hyrum's Law review
For every observable behavior, ask:
- Is this behavior intentionally part of the contract?
- If consumers start depending on it, can we support it long-term?
- If not, should we remove it, hide it, or document that it is non-contractual?
Common accidental contracts:
- Stable ordering without documenting it
- Error message wording used by scripts
- Undocumented default values
- Side effects triggered by read operations
- Field presence that is only an implementation artifact
4. Design validation at the trust boundary
Validation should happen where untrusted input enters the system:
- HTTP body, query params, headers
- CLI args and environment variables
- Webhook payloads
- Files or user-supplied configuration
Do not scatter the same runtime validation through every internal layer. Define:
- Accepted input shape
- Rejection rules
- Standard error envelope or exit code mapping
- Which invariants are guaranteed after boundary validation succeeds
5. Choose the compatibility strategy
| Change type |
Default strategy |
| Additive field |
Make optional first; define default behavior |
| Renamed field |
Add new field, deprecate old one, keep overlap window |
| Semantic change |
Version the interface or add a new endpoint/flag |
| Removed capability |
Publish a migration path before removal |
If you cannot explain the migration path in two or three sentences, the change is not ready.
6. Hand off to implementation planning
Once the contract is stable:
- Feed it into
spec-driven-development
- Identify tests that prove the contract
- Implement the smallest slice that honors the contract exactly
Example
## Interface Contract: `copilot skill install`
**Interface type**: CLI
**Consumers**: Developers using Copilot CLI
**Stability**: beta
### Inputs
- Command: `copilot skill install <url-or-path>`
- Optional flags: `--dry-run`, `--force`
- Validation rules:
- URL must be HTTPS or GitHub shorthand
- Local path must contain a valid skill directory
### Outputs
- Exit code `0`: install succeeded
- Exit code `1`: validation failure
- Exit code `2`: network or fetch failure
### Invariants
- Installed skill is validated before being written
- `--dry-run` never mutates the filesystem
### Non-Goals
- Private repository authentication
- Version pinning
Common Mistakes
| Mistake |
Fix |
| Letting implementation details leak into the contract |
Document only consumer-visible behavior |
| Treating every internal helper as a public interface |
Limit this skill to external or cross-team boundaries |
| Adding validation everywhere "just in case" |
Validate once at the boundary, then trust the normalized input |
| Delaying breaking-change planning until after coding |
Choose the migration strategy before implementation |
Verification
See Also
1---2name: api-and-interface-design3description: Use when defining a public API, CLI, webhook, or SDK surface — lock the contract first so compatibility, validation, and versioning stay intentional instead of accidental4---56# API and Interface Design78Define the contract before the implementation. This skill is for **public or cross-team interfaces**9where downstream consumers can depend on every observable behavior, including the ones you did not10mean to promise.1112## When to Use1314- Designing a new public HTTP API, CLI command, webhook, SDK surface, or plugin contract15- Changing an existing interface that other teams, tools, or customers already consume16- Clarifying breaking-change policy before implementation starts17- Tightening the interface section of `spec-driven-development` for a compatibility-sensitive feature1819## When NOT to Use2021| Instead of api-and-interface-design | Use |22|-------------------------------------|-----|23| Internal implementation design inside one module | `spec-driven-development` |24| Writing user-facing docs for a finished API | `api-documentation` |25| Retiring or replacing an old interface | `deprecation-and-migration` |26| Narrow bug fixes with no contract change | do the fix directly |2728## Workflow2930### 1. Identify the real contract boundary3132Write down:3334- **Who consumes this interface?** Humans, services, CLI users, integrations, third-party developers35- **What is observable?** Inputs, outputs, error codes, ordering, timing, idempotency, pagination, retries36- **What must stay stable?** Field names, response structure, exit codes, callback payloads, invariants3738If the consumer or stability target is unclear, you are not ready to implement.3940### 2. Draft the contract before code4142Create a contract document or spec section before touching implementation:4344```markdown45## Interface Contract: createWidget4647**Interface type**: REST API / CLI / SDK / webhook48**Consumers**: Internal services + external customers49**Stability**: stable / beta / experimental5051### Inputs52- Method / command / function name:53- Required parameters:54- Optional parameters:55- Validation rules:5657### Outputs58- Success shape:59- Error shape:60- Ordering / pagination guarantees:6162### Invariants63- [Behavior that must remain true]6465### Non-Goals66- [What this interface deliberately does not promise]67```6869### 3. Run a Hyrum's Law review7071For every observable behavior, ask:7273- Is this behavior intentionally part of the contract?74- If consumers start depending on it, can we support it long-term?75- If not, should we remove it, hide it, or document that it is non-contractual?7677Common accidental contracts:7879- Stable ordering without documenting it80- Error message wording used by scripts81- Undocumented default values82- Side effects triggered by read operations83- Field presence that is only an implementation artifact8485### 4. Design validation at the trust boundary8687Validation should happen where untrusted input enters the system:8889- HTTP body, query params, headers90- CLI args and environment variables91- Webhook payloads92- Files or user-supplied configuration9394Do not scatter the same runtime validation through every internal layer. Define:9596- Accepted input shape97- Rejection rules98- Standard error envelope or exit code mapping99- Which invariants are guaranteed after boundary validation succeeds100101### 5. Choose the compatibility strategy102103| Change type | Default strategy |104|-------------|------------------|105| Additive field | Make optional first; define default behavior |106| Renamed field | Add new field, deprecate old one, keep overlap window |107| Semantic change | Version the interface or add a new endpoint/flag |108| Removed capability | Publish a migration path before removal |109110If you cannot explain the migration path in two or three sentences, the change is not ready.111112### 6. Hand off to implementation planning113114Once the contract is stable:1151161. Feed it into `spec-driven-development`1172. Identify tests that prove the contract1183. Implement the smallest slice that honors the contract exactly119120## Example121122```markdown123## Interface Contract: `copilot skill install`124125**Interface type**: CLI126**Consumers**: Developers using Copilot CLI127**Stability**: beta128129### Inputs130- Command: `copilot skill install <url-or-path>`131- Optional flags: `--dry-run`, `--force`132- Validation rules:133 - URL must be HTTPS or GitHub shorthand134 - Local path must contain a valid skill directory135136### Outputs137- Exit code `0`: install succeeded138- Exit code `1`: validation failure139- Exit code `2`: network or fetch failure140141### Invariants142- Installed skill is validated before being written143- `--dry-run` never mutates the filesystem144145### Non-Goals146- Private repository authentication147- Version pinning148```149150## Common Mistakes151152| Mistake | Fix |153|---------|-----|154| Letting implementation details leak into the contract | Document only consumer-visible behavior |155| Treating every internal helper as a public interface | Limit this skill to external or cross-team boundaries |156| Adding validation everywhere "just in case" | Validate once at the boundary, then trust the normalized input |157| Delaying breaking-change planning until after coding | Choose the migration strategy before implementation |158159## Verification160161- [ ] Consumers and stability target are explicitly named162- [ ] Inputs, outputs, invariants, and non-goals are written before coding163- [ ] Observable but accidental behaviors were reviewed for Hyrum's Law risk164- [ ] Boundary validation and error semantics are defined165- [ ] Breaking changes have a migration or versioning strategy166167## See Also168169- [`spec-driven-development`](../spec-driven-development/SKILL.md) — turn the contract into an implementation plan170- [`api-documentation`](../../documentation/api-documentation/SKILL.md) — publish user-facing API docs171- [`deprecation-and-migration`](../deprecation-and-migration/SKILL.md) — retire or replace old interfaces safely