programming-api-design
Skill1 starsChanged 6 days agoMITView on GitHub
This skill should be used when designing or reviewing local APIs for modules, libraries or functions; not HTTP/REST or OpenAPI.
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 8 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Keep one implementation per behavior.
- Distinctive: line 19
Every public symbol documents: preconditions, ownership and lifetime of inputs and outputs, side effects, idempotency, complexity when not …
- Distinctive: line 20
Use one error strategy per layer, following the language skill.
- Distinctive: line 22
Keep the surface minimal: private by default.
- Distinctive: line 23
Default to safe behavior: least privilege, validated input at the boundary, opaque handles over exposed internals.
- Distinctive: line 24
Don't over-engineer. Not every edge case is relevant.
- Distinctive: line 30
Keep names whose form the language or a framework requires, such as constructors, operator hooks and interface methods.
- Distinctive: line 43
Never add a required parameter, remove a field or narrow accepted input in a published API.
- Very specific: line 45
Treat added struct fields, enum values and return fields as non-breaking only when callers are documented to tolerate them …
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
API Design
Deliver APIs as signatures with contract comments, plus happy-path, error-path and composition examples.
Units
- Give each unit one responsibility. If describing it needs "and", split it.
- Build features by composing small units. Options may tune one behavior; give distinct behaviors their own functions instead of switching modes inside one.
- Keep one implementation per behavior; reuse it instead of copying logic between units.
- Callers use public contracts only, never another unit's internal state or helpers.
Contract
- Every public symbol documents: preconditions, ownership and lifetime of inputs and outputs, side effects, idempotency, complexity when not obvious, and each failure (condition, caller action, retry safety).
- Use one error strategy per layer, following the language skill; never mix throwing and result values for the same failure class.
- Separate commands from queries: queries never mutate; retryable commands are idempotent.
- Keep the surface minimal: private by default; export only what callers need.
- Default to safe behavior: least privilege, validated input at the boundary, opaque handles over exposed internals.
- Don't over-engineer. Not every edge case is relevant. Example: if system is out of memory you have bigger problems than code correctness.
Naming
- Order name parts from general to specific: the thing acted on first, the action last (
<subject><action>). Nest further subjects the same way (<module><subject><action>). - Spell names in the project's or language's case and separator style; the word order stays the same:
tableBuild,table_build,table.build,note-create/note-destroy. - Keep names whose form the language or a framework requires, such as constructors, operator hooks and interface methods.
Signatures
- Take 0–3 positional arguments; move optional settings into an options struct or object. Order: subject or context first, required before optional, inputs before outputs, options last.
- Symmetric pairs share names and argument order (
file.read/file.write,File.open/file.close,poolInit/poolDestroy). - Make every call site state its meaning: replace positional flags with named options or separate functions (
render(doc, { draft: true })ordraftRender(doc), notrender(doc, true, false)). - Type a multi-valued mode with the language's checked form, not free strings: an enum in C or Zig, a string-literal union in TypeScript, a documented string set validated at entry in JavaScript.
- Distinguish adjacent same-type parameters with named fields (
copy({ src, dst })) or, in typed languages, distinct types (UserId/GroupId). - Return the useful value so calls compose; return a struct for multiple values.
Evolution
- Never add a required parameter, remove a field or narrow accepted input in a published API. Add optional fields with defaults; put new required behavior in a new function.
- Deprecate before removal; state the replacement and removal version.
- Treat added struct fields, enum values and return fields as non-breaking only when callers are documented to tolerate them (zero-initialized structs,
default/elsebranches).
In this repository16 other files it gives its agents.
- AGENTS.mdAGENTS.md
- ai-prompt-authoringSkill
- ai-skill-authoringSkill
- ai-tool-writingSkill
- analyzing-securitySkill
- coreSkill
- language-writingSkill
- programming-debuggingSkill
- programming-javascriptSkill
- programming-optimizationSkill
- technical-specificationsSkill
- ux-uiSkill
- web-buildSkill
- web-frontendSkill
- web-uxSkill
- web-visual-checkSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

