# Kamae

> Kamae (構え) — robust server-side TypeScript design. Functional domain modeling with discriminated unions, pure state transitions, Result types, schema-validated boundaries, and PII protection. TRIGGER when: writing TypeScript domain models, use cases, repositories, state transitions, error handling, boundary validation, or PII handling on the server side; designing types for business logic; implementing entity/value-object semantics in TS. SKIP: frontend React/Vue components, browser code, build tooling, code generation scripts, pure infrastructure-as-code; code unrelated to domain logic.

- Skill: `iwasa-kosui/kamae` (Agent Skill, multi-file: 20 files)
- Install (CLI): `npx skillmds@latest add iwasa-kosui/kamae`
- Raw SKILL.md: https://api.skillmd.com/api/skills/iwasa-kosui/kamae/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: iwasa-kosui (https://skillmd.com/u/iwasa-kosui)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/iwasa-kosui/kamae

---


# Kamae — Functional Domain Modeling in TypeScript

Six topic files cover the principles. Read only the file(s) relevant to the current task. The library guides under `result-libraries/` and `validation-libraries/` are read on demand based on the project's `package.json`.

## Step 0: Load applicable rules

Before any other step, glob and Read rules in priority order:

1. `.claude/rules/*.md` (project-level overrides at the working-tree root)
2. `~/.claude/rules/*.md` (user-global preferences)
3. `../../rules/defaults/*.md` relative to this `SKILL.md` (plugin defaults)

For each file:

- Read the YAML frontmatter. Skip the rule unless `applies-to` is `kamae` or `*`.
- Group by `name`. For each `name`, keep only the highest-tier instance (1 > 2 > 3); within a tier the lexicographically last filename wins.
- Apply the body of each surviving rule throughout the remaining steps. A `library-preference` rule overrides Step 1 detection; a `convention` rule shapes generated code; an `override` rule replaces guidance from a specific topic file.

If no rules are found, proceed with the plugin defaults already documented in [`../../rules/defaults/`](../../rules/defaults/).

See [`../../rules/README.md`](../../rules/README.md) for the rule format.

Before applying the topic and library guides, inspect nearby files in the same package for an established, consistent coding and import style. Follow that local convention when it exists; use Kamae's guide conventions only when the repository does not establish one.

## Step 1: Detect project libraries

Read `package.json` once. Note which Result library and validation library are present:

- Result libraries — match the first present in priority `neverthrow` > `byethrow` > `fp-ts` > `option-t`. Load the matching guide under [`result-libraries/`](./result-libraries/) when error-handling is in scope.
- Validation libraries — match the first present in priority `zod` > `valibot` > `arktype`. Load the matching guide under [`validation-libraries/`](./validation-libraries/) when boundary or branded-type work is in scope.

If none are present, ask the user before proceeding.

## Step 2: Apply the topic relevant to the task

Each topic below is one file. Read it lazily — only the file(s) you need for the current task.

### Type-Driven Domain Modeling — [domain-modeling.md](./domain-modeling.md)

Represent states with discriminated unions using `kind` as the unified discriminant. Use `type` (not `interface`), Companion Object pattern, branded types via the project's validation library, `Readonly<>`, function property notation, and one-concept-per-file structure.

Separate read contracts (resolvers) from write contracts (stores), and prefer one method per contract. Give each consumer only the operations it needs; an event store does not require a resolver or a CRUD repository. Keep I/O at workflow edges and pass values into pure domain decisions.

Place these domain-facing ports beside the concepts they serve in the domain layer. Do not introduce a dedicated `port/` or `ports/` directory, including inside `domain/`. Keep concrete I/O adapters outside the domain; use cases and adapters import the domain-owned contracts. Read the domain-modeling guide when defining dependency contracts or choosing their file locations.

### State Transitions — [state-modeling.md](./state-modeling.md)

Express transitions with pure functions. Argument types constrain valid source states; return types make targets explicit. Invalid transitions become compile errors. Use `assertNever` for exhaustiveness.

### Error Handling — [error-handling.md](./error-handling.md)

- Model expected business failures as use-case-specific `Result` error unions.
- Include an external failure in the domain `Result` error union only when the workflow has a documented recovery decision.
- Let unexpected infrastructure failures and contract/invariant violations reach the application error boundary. Preserve library contracts: fp-ts uses a separate execution failure channel inside `TaskEither` and rethrows unexpected faults at a native `Promise` boundary; see the [fp-ts guide](./result-libraries/fp-ts.md).
- A private control-flow sentinel is allowed when its associated boundary catches only that sentinel and rethrows all other errors.

### Boundary Defense — [boundary-defense.md](./boundary-defense.md)

Validate every external input (API requests, DB results, file/queue/env) with a schema at runtime. Trust types inside the domain. Do not use type assertions — `as const` and `as const satisfies Type` are the only allowed forms; when the type is unknown, parse through a validation-library schema instead. Apply `Sensitive<T>` to PII fields; the validation schema auto-wraps them.

When a runtime schema already defines a boundary representation, derive its TypeScript type from the schema instead of restating the same shape.

### Declarative Style — [declarative-style.md](./declarative-style.md)

Use `filter` / `map` / `reduce` with companion-object predicates instead of imperative loops. Model domain events as immutable records.

### Test Data — [test-data.md](./test-data.md)

Define fixtures with `as const satisfies Type` to preserve discriminant literal types and prevent widening.

## Examples

Worked end-to-end examples are in [examples/](./examples/). Read them only when the topic guide cites a specific example.

## Applying These Principles

These are recommendations, not strict rules. Use judgment based on context. If you deviate from a principle, state the reason in a comment. Justifiable reasons include: external library requires class inheritance, immutable object creation cost is a measured performance concern, or a different pattern has been adopted by team agreement.

