xstate-v5 について
xstate-v5は、TypeScriptとReactで型付きXState v5ステートマシンを設計、実装、リファクタリング、レビューするための厳格なCodexスキルです。コードを書く前のステートチャート設計を必須とし、アクター境界、イベント型、v4の旧パターン回避を定めています。
主な機能
- 01ステートチャート設計資料の作成
- 02XState v5 API規約の厳守
- 03イベント、コンテキスト、入力の型付け
- 04invokeと子アクターの境界明確化
- 05Reactアクターコンテキストの指針
活用シーン
- 01新しいXState v5ステートマシンの設計
- 02XState v5コードのリファクタリングやレビュー
- 03XState v4旧パターンからの移行
- 04Reactアプリでのアクター境界の設計
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ johnlombardo-dev/ xstate-skill --skill xstate-v5インストール後、Claude Code で/xstate-v5を入力して読み込まれたか確認します。
詳細
xstate-v5(厳格)スキル
厳格で型安全性の高いルールセットに従って、XState v5 のステートマシン(TypeScript および React)の構築、リファクタリング、レビューを行います。
信頼できる唯一の情報源: references/xstate-v5-rules.md(このリポジトリ内。スキルのルートから解決されます)。このスキルの内容がルールファイルと矛盾する場合は、ルールファイルに従ってください。
インライン化された必須要件(エージェントは必ず従うこと)
エージェントが外部のリファレンスを先に読み込まなくても要件を遵守できるよう、以下の要件を意図的に重複して記載しています。
- まず設計し、その後にコードを記述します。
- 実装前に計画資料(状態一覧、イベントカタログ、遷移表、非同期処理/アクターのマップ、受け入れテストのシナリオ)を作成します。
- 境界と分解に関する決定記録(何を分割し、何をオーケストレーションするか、およびその理由)を含めます。
- 何でも詰め込む巨大なステートマシン構成にしません。
- 関連のないドメイン(認証、トースト、ナビゲーション、ワークフロー、通信/再試行ポリシー)を、1つのステートマシンですべてモデル化してはいけません。
- 単一のステートマシンが許容されるのは、薄いオーケストレーションルートとして、または密接に連携するアプリシェルの並列リージョンとしてのみです。
- コンテキストに状態を重複させるフラグを作成しません。
state.valueがすでにモードを表している場合、コンテキストのブール値(isLoading、isAuthenticatedなど)でモードを重複させてはいけません。- 一時的な移行フラグがある場合は、その根拠と削除計画を記録します。
- XState v5 の厳格なルールを守ります。
setup({...}).createMachine({...})を使用します。actions/guards/actorsはsetup(...)内で実装します。- イベントオブジェクトのみを送信します。
- 禁止されている v4 のパターン(
interpret、Machine、cond、send、pure、chooseなど)は使用しません。
- 非同期処理とアクターの境界を明示します。
- リクエスト/レスポンスには、
onDoneとonErrorを指定したinvokeを使用します。 - 長期間連携するコンポーネントには
spawnChild/stopChildを使用し、sendToで明示的にイベントをルーティングします。
- リクエスト/レスポンスには、
フェイルクローズルール:
- 詳細が曖昧な場合は、ステートマシンのコードを記述またはレビューする前に
references/xstate-v5-rules.mdを読み込んでください。 - そのファイルが存在しない、または読み取れない場合は、推測せずに停止し、問題を報告してください。
使用する場面
次のようなタスクでこのスキルを使用します。
- XState v5 のステートマシン/アクター(
xstate、@xstate/react) - XState のコードを、より型安全で v5 の慣用的な書き方にリファクタリングする
- XState v4 のパターン(Machine/interpret/cond/send/pure/choose など)を v5 の相当するパターンに移行する
- XState v5 のステートマシンとして実装する前に、ステートチャートを計画/設計する
- アクターの境界(invoke と spawnChild の使い分け)や、
createActorContextを介した React 連携を設計する
必須要件(遵守必須)
- すべてのステートマシンで
setup({...}).createMachine({...})を優先します。 - すべての
actions、guards、actorsをsetup({...})オブジェクト内で実装します。 - イベント由来のデータは、型付きの
paramsを介してアクション/ガードに渡すことを優先します。 - 文字列イベントは送信しません。常にイベントオブジェクトを送信します。例:
actor.send({ type: '...' }) references/xstate-v5-rules.mdに記載されている XState v4 のレガシー API とパターンは禁止します。- 薄いオーケストレーションステートマシンを除き、関連のないドメイン(認証、通知/トースト、ナビゲーション、データのライフサイクルなど)を1つのステートマシン内でモデル化しません。
state.valueがすでにそのモードを表している場合、コンテキストのブール値(isLoading、isAuthenticatedなど)に状態を重複させません。
ルール目次
- ステートチャート設計:0 ステートチャート設計(コーディング前)
- コア原則:1 マシン作成パターン、2 型安全性を最優先
- セットアップオブジェクトのルール:3 実装の配置、4 パラメーターの型指定
- イベント処理のルール:5 assertEvent によるイベントの型安全性、6 イベントオブジェクトの必須要件
- 非推奨パターンの防止:7 禁止されている v4 パターン、8 v5 での最新の代替手段
- コンテキストと入力のルール:9 コンテキストの初期化、10 コンテキストの更新
- Invoke とアクターのルール:11 Invoke の設定、12 アクターの生成
- 型ヘルパーのルール:13 型ヘルパー
- テストのルール:14 型安全なテスト(14.1 決定論的なアクターテスト、14.2 モデルベーステスト、14.3 グラフユーティリティ)
- XState React のルール:15 createActorContext による状態共有
- ベストプラクティスのまとめ:16 コードの整理、17 パフォーマンスに関する考慮事項、18 エラー処理、19 ドキュメント
- AI エージェント向けの適用ルール:20 必須パターン、21 品質保証、22 ドキュメントが曖昧な場合
クイックスタート
最小限の型付きマシンのスケルトン:
import { setup, assign } from "xstate"
type Ctx = { count: number }
type Ev = { type: "inc" } | { type: "add"; amount: number } | { type: "reset" }
type Input = { initialCount?: number }
export const counterMachine = setup({
types: {
context: {} as Ctx,
events: {} as Ev,
input: {} as Input,
},
actions: {
inc: assign({ count: ({ context }) => context.count + 1 }),
add: assign({
count: ({ context }, params: { amount: number }) => context.count + params.amount,
}),
reset: assign({ count: ({ input }) => input.initialCount ?? 0 }),
},
}).createMachine({
id: "counter",
context: ({ input }) => ({ count: input.initialCount ?? 0 }),
on: {
inc: { actions: "inc" },
add: {
actions: {
type: "add",
params: ({ event }) => ({ amount: event.amount }),
},
},
reset: { actions: "reset" },
},
})
React 共有状態のスケルトン:
import { createActorContext, shallowEqual } from "@xstate/react"
import { type SnapshotFrom } from "xstate"
import { counterMachine } from "./counterMachine"
const CounterCtx = createActorContext(counterMachine)
export const CounterProvider = CounterCtx.Provider
export const useCounterSelector = CounterCtx.useSelector
export const useCounterActorRef = CounterCtx.useActorRef
const selectCount = (s: SnapshotFrom<typeof counterMachine>) => s.context.count
export const useCount = () => useCounterSelector(selectCount)
const selectCtx = (s: SnapshotFrom<typeof counterMachine>) => s.context
export const useCounterContext = () => useCounterSelector(selectCtx, shallowEqual)
ワークフロー(毎回行うこと)
- まず
references/xstate-v5-rules.mdを読みます。 - 対象範囲を特定します:
- プレーンなマシン/アクター(React 以外)
- React 統合(
createActorContext)またはローカルのuseActor - v4 パターンからの移行
- まずステートチャートを設計します:
references/xstate-v5-rules.md#0-statechart-design-before-you-codeを参照してください。- 以下を書き出します:状態一覧、イベントカタログ(ペイロード+発生元)、遷移表、非同期/アクターの境界、受け入れテストのシナリオ。
- 型設計の前に、境界/分解の判断を記録します:
- ライフサイクル、所有者、障害モードに基づいて、どの関心事を別々のアクター/マシンに分けるか。
- どの関心事をトップレベルで意図的にオーケストレーションするか(およびその理由)。
- ロジックを1つのマシンにまとめる場合は、その例外について記録します。
- 既定ではこの手順を行います。ただし、ユーザーから計画を省略するよう明示的に求められた場合を除きます。
- まず型を設計します:
types.context、types.events、types.input(該当する場合はtypes.outputも)- コードベースですでに Zod を使用している場合、またはユーザーから求められた場合に限り、
zodスキーマを使用します。
- 実装は
setup({ actions, guards, actors })に記述します:- イベント由来のデータが必要なアクション/ガードには、型付きの
paramsを渡します。 - 実装内でイベント固有のフィールドを読み取るのは必要な場合に限り、その際は
assertEventを使用します。
- イベント由来のデータが必要なアクション/ガードには、型付きの
- 非同期処理の境界を選びます:
- リクエスト/レスポンスのフローには、型付きの
inputを使用するinvokeを優先します。 - 長期間存続する子アクターには
spawnChild/stopChildを使用します。
- リクエスト/レスポンスのフローには、型付きの
- v5 のランタイム API を使用します:
createActor(machine)(interpretではなく)raise/sendTo(sendアクションではなく)enqueueActions(pure/chooseではなく)
- 検証します:
tscが成功し、paramsにanyが漏れていないこと。- 文字列によるイベント送信がないこと。
- 禁止されている v4 のインポートや設定キー(
cond、withContext、withConfigなど)がないこと。 - 非同期アクターのテストには
waitForを、モデル/グラフ駆動のテスト生成にはxstate/graph(createTestModel、getShortestPathsなど)を優先します。
モノリスが許容される場合
子アクター、または密接に結合した並列のアプリシェル関連の関心事を調整する、薄いオーケストレーションルートである場合に限り、単一のトップレベルマシンを使用します。その場合でも、無関係なドメインロジックは別々のアクター/マシンに置き、明示的なイベントを介して通信させます。
レビューチェックリスト(PR の監査時に使用)
- すべてのマシンが
setup(...).createMachine(...)になっている。 - マシンに明確なステートチャートの計画(状態/イベント/遷移表)がある、または PR の説明に記載されている。
- ドメイン設計上の問題がない:1つのマシンが1つの責務、または明示されたオーケストレーション範囲を担っている。
- 根拠が文書化されていない、状態をミラーリングするコンテキストフラグがない。
types内に実装がない。actions/guardsが、paramsまたはassertEventを介してのみイベントフィールドを読み取っている。interpret、Machine、withConfig、withContext、cond、send、pure、chooseがない。invokeにonErrorがあり(該当する場合はonDoneもある)。- React の使用では、モジュールスコープの
createActorContextを優先し、セレクターが安定しており、オブジェクトにはshallowEqualを使用している。
よくある修正
-
アクション内でイベントのペイロードを使用する場合:
- 優先する方法:
paramsでペイロードを計算し、アクションの実装がparamsに依存するようにします。 - それ以外の場合:実装内に
assertEvent(event, 'someType')を追加します。
- 優先する方法:
-
v4 の
cond:guardに名前を変更し、ガードの実装をsetup({ guards: { ... } })に移します。
-
v4 の
interpret:- 必要に応じて
createActor(machine)と.start()に置き換えます。
- 必要に応じて
注記
公式ドキュメントが曖昧に感じられる場合は、推測するのではなく、XState v5 のソース、課題/ディスカッション、または最小限の再現コード/型テストで動作を確認し、ルールファイルの指針に従ってください。