К основному содержанию
скилл CX Codex

design · rainmanjam — скилл для Claude Code: типы, которые нельзя использовать неправильно

Скилл проектирует API, схемы и машины состояний так, чтобы некорректное обращение просто не выражалось в коде. Пригодится, когда пишешь новый интерфейс и не хочешь миграций потом.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add rainmanjam/poka-yoke --skill design -a claude-code
Открыть на GitHub

Что делает design

Скилл помогает до написания сигнатуры перечислить способы, которыми интерфейс можно сломать: перепутать соседние параметры одного типа, забыть вызвать метод, собрать бессмысленную комбинацию полей, отправить пустой фильтр в удаление. Ответы на эти вопросы определяют форму API заранее.

Дальше идёт набор приёмов по убыванию силы: отдельные типы для разных понятий (UserId вместо string), размеченные объединения вместо пачки опциональных полей, парсинг на границе вместо проверки с булевым результатом, машина состояний в типах и исчерпывающий switch, который ломает сборку при добавлении варианта. Где язык не справляется, ограничения уезжают в базу: NOT NULL, CHECK, UNIQUE, внешние ключи.

Отдельно скилл требует не глушить ошибки: catch {} и || defaultValue навыворот превращают громкий сбой в тихий. Разрушительные операции по умолчанию безопасны, а идемпотентный ключ для списания денег обязателен, не опционален. Для уже написанного кода нужен другой скилл — audit.

Какие задачи решает

  • спроектировать API, в котором соседние параметры одного типа не перепутать
  • заменить структуру с опциональными полями на размеченное объединение
  • перенести проверку входных данных в парсер на границе системы
  • запретить вызов методов в неверном порядке через машину состояний
  • закрыть добавление нового варианта перечисления ошибкой сборки

Примеры запросов агенту

  • Спроектируй тип заказа так, чтобы невалидное состояние было невыразимо
  • Напиши сигнатуру transfer(from, to, amount) и объясни, как защитить её от перепутанных аргументов
  • Сделай машину состояний для заявки, где commit() недоступен до валидации

Как установить design

1Через Skills CLI (Vercel)

npx skills add rainmanjam/poka-yoke --skill design -a claude-code

2Вручную: положить файлы

~/.claude/skills/design/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/design/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о design

Как установить design в Claude Code?

Выполните npx skills add rainmanjam/poka-yoke --skill design -a claude-code. Файл скилла окажется по пути ~/.claude/skills/design/SKILL.md.

Что делает design?

Подсказывает форму типов, схем и машин состояний, при которой неправильный вызов не компилируется. Работает на этапе проектирования нового интерфейса.

Чем design отличается от audit?

design для нового кода, который ещё не написан. Если интерфейс уже существует и его надо разобрать, предназначен скилл audit.

Исходный текст

SKILL.md · MIT
---
name: design
description: >-
  Design APIs, schemas, types and state machines so misuse cannot be expressed. Use when writing a new interface and someone asks "what should the types look like", "make invalid states unrepresentable", "so callers cannot screw it up", or wants illegal state transitions rejected. Covers branded types, discriminated unions, typestate, parse-don't-validate. For code that already exists use audit.
---

# Poka-Yoke Design

Mistake-proofing is cheapest before the code exists. Once an interface has callers, every
device you add is a migration; before it has callers, a device is free. So the work here is
front-loaded: decide how this thing will be misused, *then* pick the shape that makes the
misuse unsayable.

This is Shingo's **source inspection**: checking the conditions that produce errors rather
than the errors themselves, and it is the strongest of his three inspection types, because
the error never gets the chance to happen.

## The ritual: enumerate misuse before you write the signature

Before writing an interface, spend real effort on this list. It takes two minutes and it
determines the design.

1. **What are the parameters, and can any two be swapped without complaint?** Same type
   adjacent to same type is among the most common footguns in software.
2. **What must a caller remember to do?** Call something first. Call something after. Check a
   return value. Close a handle. Pass the right units. Every "must remember" is a defect
   scheduled for later.
3. **What states can this thing be in, and which combinations are nonsense?** If you can
   construct a value that means nothing, the type is wrong.
4. **What happens on the second call?** Retries, double-clicks, at-least-once queues. If the
   answer is "it charges twice," you need a motion-step device.
5. **What's the worst plausible input?** Empty set, enormous set, null, wrong tenant,
   yesterday's token, a string from an attacker.
6. **When someone adds a new case next year, what breaks?** The right answer is "the build."
   The wrong answer is "nothing, it silently falls through."

Write the answers down where the user can see them, briefly. Then design against them.

## The moves, in preference order

Reach for the highest one the language and situation allow. Each rung down is a real
concession, take it consciously and say why.

### 1. Make the illegal state unrepresentable (Control, contact lens)

The strongest move: change the type so the bad value has no spelling.

- **Distinct types for distinct concepts.** `UserId` and `OrderId` are not both `string`.
  Money is not a float. A timeout is not a bare number. Branded types / newtypes / value
  objects cost almost nothing and kill an entire class of swap-and-mix-up bugs.
- **Sum types over bags of optionals.** `{status, error?, data?, retryAt?}` permits states
  like "succeeded with an error and a retry time." A discriminated union permits exactly the
  states that exist. If your struct has N optional fields, it claims 2^N states are legal;
  ask how many actually are.
- **Non-empty and bounded collections** when zero or unbounded is nonsense.

### 2. Parse, don't validate (Control at the boundary)

Validation returns a boolean and throws the knowledge away; parsing returns a *new type* that
carries the proof. `validateEmail(s: string): boolean` leaves every downstream function still
holding an unvalidated string. `parseEmail(s: string): Email | Error` means downstream
functions that take `Email` cannot receive garbage: the type system carries the guarantee
for you, forever, for free.

Do this once, at the system's edge: HTTP handlers, queue consumers, config loading, file
parsing, and every third-party response. Inside the boundary, work only with parsed types.

### 3. Make order and lifecycle enforceable (Control, motion-step lens)

When steps must happen in sequence, encode the sequence in types rather than in prose:

- **Typestate**: each operation consumes one state and returns the next, so `.commit()` does
  not exist on an uncommitted-and-unvalidated value.
- **Builders that cannot `build()`** until required steps have run, enforced by the type,
  not by a runtime check, where the language allows it.
- **Constructors that return ready objects.** If `init()` must be called before use, the
  constructor is doing the wrong job. Give it a static factory that does both.
- **Scope-bound resources**: context managers, `defer`, RAII, `using`. Never "remember to close."
- **Idempotency keys as required parameters** for anything that moves money, sends a message,
  or mutates external state. Required, not optional: an optional idempotency key is a
  suggestion, and suggestions are rung zero.

### 4. Make completeness checkable (Control/Warning, fixed-value lens)

- **Exhaustive matching** with a compiler-enforced never/unreachable arm, so adding an enum
  variant breaks the build at every site that must change. This is one of the highest
  leverage devices in existence and it costs one line per switch.
- **Required arguments over defaulted ones** when there is no safe default. A default that is
  wrong half the time is worse than no default: it hides the decision.
- **Whole-config validation at startup**, so a missing variable fails the deploy rather than
  the 3am request.

### 5. Fail fast and loud (Warning)

When the type system genuinely cannot express the constraint, assert at the boundary and
throw. This is a real poka-yoke, one rung down. Make the message name the mistake and the fix.

Two rules that decide whether this rung works at all:

- **No silent fallbacks.** `catch {}`, `except: pass`, `|| defaultValue`, `unwrap_or_default()`
  on an error path. These are devices *removed*. They convert a loud mistake into a quiet
  one, which is exactly backwards. If a fallback is genuinely correct, the comment must say
  which failure it is absorbing and why that failure is expected.
- **Destructive operations default to safe.** Dry-run by default, require an explicit
  predicate, refuse to act on an empty or oversized set. `deleteUsers(filter)` with an empty
  filter should raise, not truncate the table.

### 6. Where the language can't help, move the device to the data layer

The database is a type system that all your services share. `NOT NULL`, `CHECK`, `UNIQUE`,
foreign keys, and partial unique indexes are Control-rung devices that hold even when someone
writes a script, connects with `psql`, or ships a service in another language. When
application-level enforcement is the only thing standing between you and corrupt data, push
it down.

## Deliver the design with its reasoning attached

You were asked for code, so write the code. But narrate the mistake-proofing in a few lines,
because the reasoning is what stops it being undone later:

- what misuses you enumerated,
- which ones the design now makes impossible, and at which rung,
- which ones you consciously left possible, and why.

That last bullet matters most. Every design leaves something possible; naming it is the
difference between a considered tradeoff and an oversight.

## Restraint

Mistake-proofing has a cost, and past a point it stops paying. Signs you have gone too far:
five wrapper types for one function, a builder for a two-field struct, a type parameter no
caller will ever understand. The test is whether the device prevents a mistake someone would
*plausibly make*, weighted by what happens when they do. An internal helper with two callers
and a trivial failure mode does not need a newtype; a public payments API does.

Sean Goedecke's [critique of the maximalist version](https://www.seangoedecke.com/invalid-states/)
is worth taking seriously: types that model every invariant can become harder to change than
the bugs they prevent. Aim the strongest devices at the highest blast radius, and leave
low-stakes code readable.

Read `../../references/hazard-catalog.md` for the misuse shapes worth
enumerating, and the matching `references/lang-*.md` for what your language can actually
express: the moves above are only as strong as the type system underneath them.

© rainmanjam · MIT · rainmanjam/poka-yoke

Похожие скиллы

Все скиллы по теме «Бэкенд и API» →

Сначала — design от других авторов.

design claudekit Скилл для генерации логотипов, бренд-айдентики, дизайн-токенов, слайдов на Chart.js и баннеров через ИИ и Python-скрипты. CX Codex +1 41 800установок design SubframeApp Ведёт агента по работе с Subframe: собрать страницу или компонент, сравнить варианты на канвасе, поправить тему. CX Codex +1 775установок design rshankras Набор дизайн-скиллов для интерфейсов Apple: Liquid Glass, анимации, игровой отклик, UX-тексты, SF Symbols и типографика. Пригодится, когда экран выглядит плоско и нужен план правок. CX Codex +1 677установок design cognitedata Скилл настраивает работу с дизайн-системой Aura в приложениях Flows и Fusion. Помогает выбирать готовые примитивы, расставлять токены вместо сырых значений и собирать интерфейсы. CX Codex +1 1 900установок design kirkchen Скилл создаёт артефакты спецификации для изменения Beat: proposal, gherkin и design.md. Нужен в начале работы над изменением. CX Codex +1 506установок mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. 130 949установок claude-api официальный anthropics Справочник по Anthropic SDK и API Claude для генерации кода без устаревших параметров и выдуманных методов. 74 198установок lark-im larksuite Скилл подключает Lark IM к агенту: он отправляет сообщения, ищет историю, управляет чатами и файлами. Подойдёт для задач вокруг командных коммуникаций. CX Codex +1 472 900установок lark-event larksuite Слушает события Lark/Feishu и отдаёт их потоком NDJSON. Подходит для ботов, обработчиков сообщений и долгих подписчиков. CX Codex +1 466 800установок caveman-discover JuliusBrussee Находит точки вызова LLM в репозитории и размечает их воркфлоу для Caveman Cloud, чтобы расходы на токены не сливались в одну общую кучу. CX Codex +1 104 400установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. CX Codex +1 103 900установок

Из того же набора4

Спонсоры проекта

Компании, которые помогают держать аналитику открытой