
Kamae Review
- 56 installs
- 50 repo stars
- Updated June 25, 2026
- iwasa-kosui/functional-ts-principles
Adversarially review server-side TypeScript against the Kamae principles: discriminated unions, branded types, Result handling, boundary validation and PII.
About
Kamae-review is an adversarial code-review skill that checks server-side TypeScript against the Kamae principles via severity-tagged checklists for domain modeling, state transitions, error handling, boundaries and PII. Use it when reviewing or auditing domain-logic TS pull requests.
- Walks checklist sub-files with High/Medium/Low severity and location, principle and fix per finding
- Loads the matching Result and validation library guides from package.json before reviewing
Kamae Review by the numbers
- 56 all-time installs (skills.sh)
- +8 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #560 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/iwasa-kosui/functional-ts-principles --skill kamae-reviewAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 56 |
|---|---|
| repo stars | ★ 50 |
| Last updated | June 25, 2026 |
| Repository | iwasa-kosui/functional-ts-principles ↗ |
What it does
Adversarially review server-side TypeScript against the Kamae principles: discriminated unions, branded types, Result handling, boundary validation and PII.
Files
Kamae Code Review
Adversarial review against the kamae principles. The knowledge base lives in ../kamae/; this skill links rather than duplicates.
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-toiskamae-reviewor*. - Group by
name. For eachname, keep only the highest-tier instance (1 > 2 > 3); within a tier the lexicographically last filename wins. - A
check-togglerule withenabled: falseremoves the named check from the walk in step 3 below. - A
conventionrule sets project-specific expectations the review respects (e.g., a designated location for Branded Types).
If no rules are found, proceed with all checks active. See `../../rules/README.md` for the rule format.
Review Procedure
1. Load principle knowledge. Before reading any code under review, read:
- `../kamae/SKILL.md` — principle index
- The validation library guide matching the project's
package.jsonunder `../kamae/validation-libraries/` (zod.md/valibot.md/arktype.md) - The Result library guide matching the project's
package.jsonunder `../kamae/result-libraries/` (neverthrow.md/byethrow.md/fp-ts.md/option-t.md) - Each topic file under
../kamae/cited by the checklist sub-files you read.
2. Read the files under review.
3. Walk the checklist. Read each checklist sub-file in order; match findings to its items.
- `checklist/domain-modeling.md` — Discriminated Unions, Companion Objects, Branded Types, file structure (items 1.x)
- `checklist/state-transitions.md` — pure state transitions, exhaustiveness (items 2.x)
- `checklist/error-handling.md` — Result types, no thrown exceptions, DU error types (items 3.x)
- `checklist/boundary.md` — schema validation, no
asassertions (items 4.1, 4.2) - `checklist/pii-protection.md` —
Sensitive<T>for PII (item 4.3) - `checklist/declarative-and-tests.md` — array operations, events, fixtures (items 5.x, 6.x)
4. Report findings. For each violation: 1. Location (path:line). 2. Why it is a problem — cite the principle (link back to ../kamae/...) and the risk of violating it. 3. How to fix — code example showing the corrected version.
5. Suggestions (non-violations with room for improvement) are communicated with the same format but framed as suggestions rather than findings.
Severity classes
Each checklist item is tagged High / Medium / Low.
- High — direct cause of runtime errors or compliance violations (
as, missing PII protection, missing schema validation, missing Branded Types on semantically distinct primitives). - Medium — invalid state representation, inconsistent error handling, missing exhaustiveness, catch-all type files, classes for domain models.
- Low — stylistic, readability, edge-case correctness (method notation,
interfacefor domain types, missingReadonly<>, non-kinddiscriminants, imperative array loops, fixtures withoutas const satisfies).
Example Finding
### Use of method notation
`src/repository/task-repository.ts:15`
`save(task: Task): Promise<void>` uses method notation. Per
[`../kamae/SKILL.md` §1 "Use function property notation"](../kamae/SKILL.md),
parameters become bivariant under method notation, so a narrower implementation
such as `save(task: DoingTask): Promise<void>` will pass type checking at the
injection site.
Suggested fix:
\`\`\`typescript
type TaskRepository = {
save: (task: Task) => Promise<void>;
};
\`\`\`Boundary Defense Checklist
Reference: `../../kamae/SKILL.md` §4, `../../kamae/boundary-defense.md`, and the project's validation library guide under `../../kamae/validation-libraries/`.
4.1 Is schema validation present at every external boundary? — High
Flag: API handlers, DB-result mappers, queue/message handlers, file/config loaders, or env-var readers that treat raw data as domain types without parsing it through a validation library schema (Zod / Valibot / ArkType).
4.2 Are as type assertions used? — High
The only permitted as forms are as const and as const satisfies Type. Flag every other as and verify it falls into one of these acceptable cases:
- External or unknown-typed data: must be replaced by a validation-library schema parse.
asdoes not give the guarantee its type claims. asinside a Branded Type factory: tolerated only as a last-resort fallback when no validation library is present (unique symbolpattern). When flagged, recommend introducing a validation library and rewriting the brand withz.brand()/v.brand()/.brand()so theascan be removed.- Internal data: type inference should resolve it; if not, the type design is likely wrong.
Declarative Style and Test Data Checklist
Reference: `../../kamae/SKILL.md` §5–§6, `../../kamae/declarative-style.md`, `../../kamae/test-data.md`.
5.1 Are array operations declarative? — Low
Flag: for / for…of loops that build up arrays imperatively when filter / map / reduce would express the intent directly. Suggest defining predicates on the companion object (e.g., tasks.filter(Task.isActive)).
5.2 Are domain events emitted as immutable records? — Low
Flag: state-change code that mutates a shared event log, or that omits domain events entirely when the state-modeling guidance calls for them. Events should be Readonly<{ eventId; eventAt; eventName; payload; aggregateId }> and recorded separately from the repository.
5.3 Are companion-object predicates free of redundant x is Y annotations? — Low
Flag: predicate functions over a discriminated union that carry an explicit : x is Y return-type annotation when the body is just kind === "..." comparisons (or their !== negation). TypeScript 5.5+ infers the type predicate from such bodies and Array.prototype.filter consumes the inferred predicate, so the annotation adds nothing — and falsely implies that discriminated union narrowing alone is insufficient. Suggest dropping the annotation.
6.1 Is as const satisfies Type used for fixtures? — Low
Flag: test fixtures typed with : Type = or with as Type, which widen discriminant literals to string. Suggest as const satisfies Type so kind keeps its literal type.
Domain Modeling Checklist
Reference: `../../kamae/SKILL.md` §1, `../../kamae/domain-modeling.md`, and the project's validation library guide under `../../kamae/validation-libraries/`.
1.1 Are domain states modeled as Discriminated Unions? — Medium
Flag: a single type with many optional properties and a string state field (e.g. { state: string; driverId?: string; startTime?: Date }). Suggest splitting into per-state types unioned together so state-specific properties become required.
1.2 Is kind used as the unified discriminant? — Low
Flag: discriminant property names other than kind (type, status, state, _tag, …). Suggest renaming to kind for codebase consistency.
1.3 Are classes used for domain models? — Medium
If class defines domain entities or value objects, suggest migrating to Discriminated Union + Companion Object. Class inheritance required by an external library is a legitimate exception.
1.4 Is the Companion Object pattern followed? — Medium
Check that:
- A type's related operations live on a
constof the same name as the type. - Branded Type validation schemas are exposed as
.schemaon the companion object, not as standaloneXxxSchemaexports. - Domain logic is not scattered as free-standing
xxxAssignDriverhelpers when a companion object would naturally own them.
1.5 Is interface used for domain types? — Low
Declaration merging silently changes a type's shape. Domain types must be type. interface is acceptable only for library type augmentation.
1.6 Is method notation used inside type definitions? — Low
Method notation (save(task: Task): Promise<void>) makes parameters bivariant, allowing a narrower implementation (save(task: DoingTask): …) to type-check at injection sites. Suggest function property notation (save: (task: Task) => Promise<void>).
1.7 Are Branded Types applied to semantically distinct primitives? — High
Flag: string / number used directly for IDs and semantically distinct values (UserId, OrderId, Email, money amounts, …). Verify that brands use the validation library's brand feature when one is present (so as casts are unnecessary), or the unique symbol pattern when no library is used.
1.8 Are domain objects Readonly<>? — Low
Flag: domain object types defined without Readonly<…> (or readonly per-property). State changes should produce new objects, not mutate properties.
1.9 Is the "one concept per file" rule followed? — Medium
Flag: catch-all files (types.ts, models.ts, domain.ts) aggregating many domain types, especially when companion objects live elsewhere. Barrel files (index.ts) must only re-export.
Error Handling Checklist
Reference: `../../kamae/SKILL.md` §3, `../../kamae/error-handling.md`, and the project's Result library guide under `../../kamae/result-libraries/`.
3.1 Are exceptions thrown in the domain layer? — Medium
Flag: throw in entities, value objects, or use cases. Suggest migrating to Result. Acceptable: throw inside assertNever (unreachable) and unexpected failures in the infrastructure layer.
3.2 Are error types Discriminated Unions? — Medium
Flag: Error subclasses, free-form string error codes, or Result<T, string>. Suggest a Discriminated Union ({ kind: "DriverNotAvailable"; driverId } | { kind: "RequestAlreadyAssigned" }) so callers can branch exhaustively.
3.3 Are Result chains used instead of nested if/else? — Low
Verify that the project uses the matching Result library API (.map, .andThen, Result.do, …) rather than unwrapping immediately into branching code. Cite the matching guide under ../../kamae/result-libraries/ for the correct combinator.
PII Protection Checklist
Reference: `../../kamae/SKILL.md` §4 "PII Protection", `../../kamae/boundary-defense.md`.
4.3 Do PII fields use Sensitive<T>? — High
Flag: fields plausibly carrying personal information (name, email, phone, address, government IDs, payment details, health/diagnostic information, IP addresses) that are bare string/number rather than Sensitive<T>. Pay special attention to objects that may appear in logs or error messages. Verify that the validation schema auto-wraps such fields with Sensitive.of.
This check is independently toggleable via a check-toggle rule (check: pii-protection) for projects that handle no personal information.
State Transitions Checklist
Reference: `../../kamae/SKILL.md` §2, `../../kamae/state-modeling.md`.
2.1 Do state transitions constrain source states by argument type? — Medium
Flag: a transition function whose argument type is the union (TaxiRequest) instead of the specific source state (Waiting). The wider type allows callers to apply the transition to invalid source states.
2.2 Do switch statements over Discriminated Unions have assertNever? — Medium
Flag: switch on kind without default: return assertNever(x). Without it, adding a new variant will not produce a compile error.