agentsclimarketplace

Workflow domain entity

Skill marzun9620/agent_skills/workflow/skills/workflow-domain-entity

Domain Entity implementation guide. Define entities with Schema.Class + Brand, plus Value Objects, Domain Errors (Schema.TaggedError), and barrel exports. Triggers: domain entity creation, Schema.Class, Brand types, domain model, Value Object, domain error, domain layer implementation.From its SKILL.md

Install
npx -y skills add marzun9620/agent_skills --skill workflow-domain-entity

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

4.7 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

Domain Entity 実装手順

ADR-0001 / ADR-0004 準拠。domain 層は純粋なデータ定義のみ。I/O 禁止。

ファイル構成(必ずこの構造に従う)

apps/datahub/src/domain/{module}/
├── {entity}Id.ts         # Brand 型 ID
├── {entity}Status.ts     # Enum(必要な場合)
├── {entity}.ts           # Entity 本体(Schema.Class)
├── errors.ts             # Domain Error(Schema.TaggedError)
└── index.ts              # Barrel export(全 public 型)

ファイル名は camelCase。1ファイル1責務。

Import ルール(重要)

  • 同一ディレクトリ内: ./ で直接 import OK
  • cross-directory(他の domain module 等): barrel(index.js)経由のみ
// ✅ 同一ディレクトリ内
import { EntityId } from "./entityId.js";

// ✅ 他の domain module
import { UserId } from "~/domain/user/index.js";

// ❌ 禁止
import { UserId } from "~/domain/user/userId.js";

1. Entity 定義

ファイル: apps/datahub/src/domain/{module}/{entity}.ts

import { Schema } from "effect";
import { EntityId } from "./entityId.js";

export class Entity extends Schema.Class<Entity>("Entity")({
  id: EntityId,
  name: Schema.String,
  status: EntityStatus,
  // nested value objects OK
}) {}
  • Schema.Class<T>(name)({fields}) で定義
  • メソッドなし、純粋なデータコンテナ
  • ネストされた Value Object / Enum を参照可能

2. Value Object(ID)

ファイル: apps/datahub/src/domain/{module}/{entity}Id.ts

import { Schema } from "effect";

export const EntityId = Schema.String.pipe(Schema.brand("EntityId"));
export type EntityId = typeof EntityId.Type;

3. Enum(Status / Role / Kind)

ファイル: apps/datahub/src/domain/{module}/{entity}Status.ts

import { Schema } from "effect";

export const EntityStatus = Schema.Literal("ACTIVE", "ARCHIVED");
export type EntityStatus = typeof EntityStatus.Type;

命名: *Status, *Role, *Kind を使う。*Type は避ける。

4. Domain Error

ファイル: apps/datahub/src/domain/{module}/errors.ts

import { Schema } from "effect";
import { EntityId } from "./entityId.js";

export class EntityNotFoundError extends Schema.TaggedError<EntityNotFoundError>()(
  "EntityNotFoundError",
  { entityId: EntityId },
) {}
  • Schema.TaggedError を使う(Data.TaggedError は domain 層で禁止)
  • Brand にしない

5. Domain Service(必要な場合のみ)

ファイル: apps/datahub/src/domain/services/{serviceName}.ts

import { Match, Option } from "effect";

// 純粋関数のみ。Effect を返す場合も I/O なし
export const checkPermission = (role: SystemRole) =>
  Match.value(role).pipe(
    Match.when("SYSTEM_ADMIN", () => Effect.void),
    Match.when("USER", () => Effect.fail(new InsufficientPermissionError({}))),
    Match.exhaustive,
  );
  • nullable は Option.fromNullable + Option.match で処理
  • Match.value() + Match.exhaustive でパターンマッチ

6. Barrel Export

ファイル: apps/datahub/src/domain/{module}/index.ts

export { Entity } from "./entity.js";
export { EntityId } from "./entityId.js";
export type { EntityId as EntityIdType } from "./entityId.js";
export { EntityStatus } from "./entityStatus.js";
export { EntityNotFoundError } from "./errors.js";

cross-directory import はこの barrel 経由のみ。同一ディレクトリ内は ./ OK。

テスト踏襲ルール

実装前に、plan の Ref test に指定された既存テストファイルを読むこと:

  • 同モジュールのテストがあればそれを踏襲
  • なければ tests/domain/ 内の別モジュールのテストを参考にする
  • 構造を合わせる: type 定義(XxxCase)、table-driven(.each())、AAA パターン
  • expect(result).toEqual(expected) を使う(toBe ではなく toEqual

チェックリスト

  • type を使っている(interface 禁止 — ADR-0001)
  • Schema.TaggedError を使っている(Data.TaggedError 禁止)
  • I/O なし(postgres, drizzle, hono, node:fs, node:net の import なし)
  • _tag への直接アクセスなし(Schema.is() / Match.tag() を使用)
  • barrel export が存在する
  • any を使っていない
  • named export のみ(default export 禁止)

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most automation workflows skills give in ~1.3k tokens

Counted across 745 of the 1,008 authors here whose files we hold, read 2026-08-07

  • Write conventional commit messagesin 36 of 745, across 35 files
  • Delete branches after mergein 30 of 745, across 21 files
  • Make atomic commitsin 25 of 745, across 15 files
  • Write minimal code to pass testsin 22 of 745, across 10 files
  • Re-snapshot after navigation or DOM changesin 21 of 745, across 13 files
  • Use try-catch for error handlingin 20 of 745, across 8 files
  • Run tests before committingin 20 of 745, across 12 files
  • Write tests before implementationin 20 of 745, across 8 files
  • Configure branch protection rulesin 19 of 745, across 5 files
  • Explain the why in commit messagesin 19 of 745, across 9 files
  • Refactor code while tests remain greenin 19 of 745, across 6 files
  • Interact with elements using refsin 19 of 745, across 11 files

Said here and by no other author read

  • define entities using schema class
  • use brand types for identifiers
  • use schema tagged error for errors
  • create a barrel export file
  • use direct imports within same directory
  • import cross-directory modules via barrel exports

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,367. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.