Claude-skill-registry creating-adts
This skill should be used when the user asks to "create an ADT", "scaffold a discriminated union", "add a tagged union", "create Effect Schema union", or needs to create algebraic data types following the ADT library pattern with proper member files and barrel exports.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/creating-adts" ~/.claude/skills/majiayu000-claude-skill-registry-creating-adts && rm -rf "$T"
manifest:
skills/data/creating-adts/SKILL.mdsource content
Creating ADTs
Scaffold ADT (Algebraic Data Type) unions with discriminated member types.
CRITICAL
Read the Conventions First
Before creating any ADT, read the convention documents:
— Core~/.claude/docs/conventions/namespace-module.md
/_.ts
pattern__.ts
— ADT-specific patterns~/.claude/docs/conventions/library-adt.md
Operations
Create ADT Union
Structure:
src/lib/<adt-name>/ ├── _.ts # export * as AdtName from './__.js' ├── __.ts # exports member namespaces + union ├── <adt-name>.ts # Union definition ├── <member-a>.ts # Member type └── <member-b>.ts # Member type
Steps:
- Create directory at
(kebab-case matching ADT name)src/lib/<adt-name>/ - Create member files with tagged structs
- Create union file importing members directly (NOT from
)__.ts - Create
exporting members as namespaces + union exports__.ts - Create
pointing to_.ts__.ts - Add package.json imports and tsconfig.json paths
Member File Pattern (Effect Schema)
// <member>.ts import * as S from 'effect/Schema' export class MemberName extends S.TaggedClass<MemberName>()('AdtNameMemberName', { // fields... }) { static is = S.is(MemberName) }
Naming Rules:
- Class name = member name (short, local):
Versioned - Tag name = fully qualified:
DocumentVersioned
Union File Pattern
// <adt-name>.ts import * as S from 'effect/Schema' import { MemberA } from './member-a.js' // Direct import, NOT from __.ts import { MemberB } from './member-b.js' export const AdtName = S.Union(MemberA, MemberB) export type AdtName = typeof AdtName.Type
Barrel File Pattern (__.ts
)
__.ts// __.ts export * from './<adt-name>.js' export * as MemberA from './member-a.js' export * as MemberB from './member-b.js'
Examples
LifecycleEvent ADT
// added.ts export class Added extends S.TaggedClass<Added>()('LifecycleEventAdded', { schema: SchemaRef, revision: Revision, }) { static is = S.is(Added) } // removed.ts export class Removed extends S.TaggedClass<Removed>()('LifecycleEventRemoved', { schema: SchemaRef, revision: Revision, }) { static is = S.is(Removed) } // lifecycle-event.ts import { Added } from './added.js' import { Removed } from './removed.js' export const LifecycleEvent = S.Union(Added, Removed) export type LifecycleEvent = typeof LifecycleEvent.Type // __.ts export * as Added from './added.js' export * from './lifecycle-event.js' export * as Removed from './removed.js' // _.ts export * as LifecycleEvent from './__.js'
Consumer Usage
// Import ONLY from namespace (_.js) import { LifecycleEvent } from '#lifecycle-event' // Access members via namespace const added = LifecycleEvent.Added.make({ schema, revision }) const removed = LifecycleEvent.Removed.make({ schema, revision }) // Type check if (LifecycleEvent.Added.is(event)) { // event is Added }
Notes
- Union file imports members directly to avoid circular dependencies
- Consumer code imports ONLY from
, never from_.js__.js - Use
constructor from tagged classes, never manual object construction.make() - Tag names should be fully qualified (
) for global uniquenessAdtNameMemberName - See convention doc for Simple ADT Pattern (alternative when full structure is overkill)