From tk-house-style
Use when writing module signatures, designing public exports, or reviewing call sites - checks call-site clarity, misuse resistance, error-surface size, and boilerplate ratio; mandates a caller-perspective comment on every stubbed module
How this skill is triggered — by the user, by Claude, or both
Slash command
/tk-house-style:api-ergonomicsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Core principle:** the public surface is a UX. Pure FP can produce miserable APIs. Discipline does not constrain ergonomics; this skill does.
Core principle: the public surface is a UX. Pure FP can produce miserable APIs. Discipline does not constrain ergonomics; this skill does.
Why this matters: type safety and purity are necessary but not sufficient. A correct API the caller cannot figure out is a defect. Boilerplate compounds; a 3-line setup tax on every call site adds up to thousands of lines across a project.
Trigger symptoms:
string or generic ErrorYOU MUST add, at the top of every stubs file produced by stub-author, a representative call-site example before any signatures:
// caller-perspective:
//
// const cart = Cart.empty();
// const updated = await cart.addItem({ sku, qty });
// if (updated.tag === "err") return reportError(updated.error);
// const result = await orders.place(updated.value, payment);
// ...
//
5 to 15 lines. Real types, real names, the dominant use case. stub-author writes it BEFORE signatures. body-implementor matches it. Reviewer Step 3c flags drift between the comment and the actual exported surface.
NO EXCEPTIONS. A stubs file without this comment is incomplete.
PaymentToken not EncodedJWT.Result<T, E> depends on the usability of E.string. Antithesis of newtype.isAdmin: bool instead of role ADT.string/number everywhere instead of domain types.a.b().c().d() chain, often nullable.Reviewer flags string / Error / unknown as error types. What good looks like:
tag field per failure mode the caller can act on.ParseError, TransferError, AuthError. Don't mix concerns.out-of-stock, payment-declined).network-timeout, db-unavailable); usually retried at the shell.E.cause chain ambiguity. If you wrap an underlying error, name the field (cause) and type it; do not stringify.Smell: every variant has the same shape { tag, message: string }. That is a string error wearing a tag. Variants must carry case-specific fields.
Reviewer Step 3c runs through these on every public export:
A "no" on any => issue. Default to flagging as Important.
| Excuse | Reality | What to do |
|---|---|---|
| "Caller can read the types" | Types document mechanism; example documents intent. | Write the caller-perspective comment. |
| "Options object is flexible" | 40 fields = 40 things to misconfigure. | Group related fields into typed sub-records or split into multiple constructors. |
| "Error is just a string for now" | "For now" survives to production. Caller has nothing to branch on. | Define an ADT error type with named variants. |
| "Caller will figure out init order" | They won't. They will call out of order and crash in prod. | Encode order with typestate; require init before use at the type level. |
| "We expose internals so callers can do advanced things" | Now you cannot refactor internals without breaking callers. | Layered API: public convenience, separate low-level module. |
| "The 12-arg function is faster" | Caller readability lost; refactor cost high. | Take a struct/record. Argument order is a documentation tax. |
| "We will document the gotchas" | Docs rot. Types do not. | Make the gotcha unrepresentable. |
| "It is more functional to chain" | Chains hide control flow and break under null/undefined. | pipe over explicit values; one stage per line. |
string, Error, or unknown.computeFromCachedDigest) instead of intent (getOrder)._examples.md - before/after for each red flag.caller-perspective.md - the marker exercise, deeper guidance for stub-author.When in doubt: put yourself in the caller's editor. If autocomplete and the example do not get them to working code in 10 lines, the API is not ready.
Provenance: original to tk-harness; structure cribbed from ed3d-house-style skill conventions (CC-BY-SA-4.0).
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
npx claudepluginhub tk-evans01/tk-harness --plugin tk-house-style