بنقرة واحدة
design-state-machine
Statechart and state machine modeling for lifecycle and behavior specification
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Statechart and state machine modeling for lifecycle and behavior specification
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Read an open GitHub pull request via the `gh` CLI and rewrite its title and description to follow a conventional-commits + JIRA-ticket format with a concise structured body and a smart pre-merge checklist derived from the diff. Use this skill whenever the user wants to clean up, format, normalize, standardize, or apply a template to a pull request — including phrases like "fix my PR description" or "update PR".
Compact the current conversation into a handoff document for another agent to pick up.
Pipe the response's prose to the macOS clipboard via `pbcopy` so the user can paste it directly. Use when the user says "copy to clipboard", "/copy", "pbcopy this", "put it on my clipboard", or otherwise asks for paste-ready output. macOS only.
Best practices for OpenID Connect (OIDC) and OAuth 2.0 — flow selection, token validation, endpoints, discovery, and security hardening. Use when building, integrating, or reviewing authentication code: OIDC/OAuth clients (RP), authorization servers (OP), an OIDC library, ID token / JWT validation, PKCE, refresh tokens, DPoP, or logout. Triggers on OpenID Connect, OAuth, SSO, ID token, access token, auth flow, JWKS, client_secret, PKCE, or "log in with".
Code-review skill with mode routing. Default lens is `standard` (alias `quick`) — correctness, security, quality in one pass with a verdict. Other modes: `security` (OWASP, high-confidence only), `architecture` (module depth, coupling, boundaries), `merge-risk` (shippability + reversibility), `intent` (alias `adversarial`) — does the diff deliver what was promised, `multi` (alias `full`) — six parallel reviewers plus a verifier. Invoke as /review-code [<mode>] [<scope>]. Use for any code-review or PR-audit task.
OAuth2.0
| name | design-state-machine |
| description | Statechart and state machine modeling for lifecycle and behavior specification |
| allowed-tools | Read, Glob, Grep, Write, Edit |
Use this skill when:
Design finite state machines and statecharts for modeling entity lifecycles, workflows, and system behavior.
Before designing state machines:
| Element | Description | Example |
|---|---|---|
| State | Condition the system can be in | Draft, Submitted, Paid |
| Transition | Change from one state to another | Draft → Submitted |
| Event | Trigger for a transition | Submit, Pay, Cancel |
| Guard | Condition that must be true | [hasItems], [isValid] |
| Action | Side effect on transition | sendNotification, updateDatabase |
| Entry Action | Action when entering state | onEnter: startTimer |
| Exit Action | Action when leaving state | onExit: stopTimer |
type StateType =
| 'initial' // Starting state (filled circle)
| 'normal' // Regular state
| 'final' // End state (circle with border)
| 'composite' // Contains sub-states
| 'parallel' // Concurrent regions
| 'history' // Remember last sub-state
| 'choice'; // Decision point
stateDiagram-v2
[*] --> Draft : Create
state Draft {
direction LR
[*] --> Empty
Empty --> HasItems : AddItem
HasItems --> HasItems : AddItem
HasItems --> Empty : RemoveLastItem
}
Draft --> Submitted : Submit
Draft --> Cancelled : Cancel
Submitted --> Paid : PaymentReceived
Submitted --> Cancelled : Cancel
Submitted --> Draft : RequireChanges
Paid --> Shipped : Ship
Paid --> Refunded : Refund
Shipped --> Delivered : Deliver
Shipped --> Returned : Return
Delivered --> Completed : Finalize
Delivered --> Returned : Return
Returned --> Refunded : ProcessReturn
Completed --> [*]
Refunded --> [*]
Cancelled --> [*]
@startuml
title Order State Machine
[*] --> Draft : Create
state Draft {
Draft : entry / initializeOrder
Draft : exit / validateOrder
}
Draft --> Submitted : Submit [hasItems]
Draft --> Cancelled : Cancel
state Submitted {
Submitted : entry / reserveInventory
}
Submitted --> Paid : ProcessPayment [paymentValid]
Submitted --> Cancelled : Cancel / releaseInventory
Submitted --> Draft : RequireChanges
state Paid {
Paid : entry / confirmInventory
}
Paid --> Shipped : Ship
Paid --> Refunded : Refund
state Shipped {
Shipped : entry / sendTrackingNotification
}
Shipped --> Delivered : Deliver
Shipped --> Returned : Return
Delivered --> Completed : Finalize
Delivered --> Returned : Return
Returned --> Refunded : ProcessReturn
Completed --> [*]
Refunded --> [*]
Cancelled --> [*]
@enduml
Simple, declarative — good for machines with no side effects in the transition logic itself.
const OrderStatus = {
Draft: 'draft',
Submitted: 'submitted',
Paid: 'paid',
Shipped: 'shipped',
Delivered: 'delivered',
Completed: 'completed',
Cancelled: 'cancelled',
Returned: 'returned',
Refunded: 'refunded',
} as const;
type OrderStatus = (typeof OrderStatus)[keyof typeof OrderStatus];
const OrderEvent = {
Submit: 'submit',
Cancel: 'cancel',
Pay: 'pay',
RequireChanges: 'requireChanges',
Ship: 'ship',
Refund: 'refund',
Deliver: 'deliver',
Return: 'return',
Finalize: 'finalize',
ProcessReturn: 'processReturn',
} as const;
type OrderEvent = (typeof OrderEvent)[keyof typeof OrderEvent];
const transitions: Record<string, OrderStatus> = {
[`${OrderStatus.Draft}:${OrderEvent.Submit}`]: OrderStatus.Submitted,
[`${OrderStatus.Draft}:${OrderEvent.Cancel}`]: OrderStatus.Cancelled,
[`${OrderStatus.Submitted}:${OrderEvent.Pay}`]: OrderStatus.Paid,
[`${OrderStatus.Submitted}:${OrderEvent.Cancel}`]: OrderStatus.Cancelled,
[`${OrderStatus.Submitted}:${OrderEvent.RequireChanges}`]: OrderStatus.Draft,
[`${OrderStatus.Paid}:${OrderEvent.Ship}`]: OrderStatus.Shipped,
[`${OrderStatus.Paid}:${OrderEvent.Refund}`]: OrderStatus.Refunded,
[`${OrderStatus.Shipped}:${OrderEvent.Deliver}`]: OrderStatus.Delivered,
[`${OrderStatus.Shipped}:${OrderEvent.Return}`]: OrderStatus.Returned,
[`${OrderStatus.Delivered}:${OrderEvent.Finalize}`]: OrderStatus.Completed,
[`${OrderStatus.Delivered}:${OrderEvent.Return}`]: OrderStatus.Returned,
[`${OrderStatus.Returned}:${OrderEvent.ProcessReturn}`]: OrderStatus.Refunded,
};
function transition(current: OrderStatus, event: OrderEvent): OrderStatus {
const next = transitions[`${current}:${event}`];
if (!next) {
throw new Error(`Cannot ${event} order in ${current} status`);
}
return next;
}
Full statechart implementation with context, guards, actions, and services.
import { createMachine, assign } from 'xstate';
interface OrderContext {
items: LineItem[];
customerId: string;
paymentId?: string;
trackingNumber?: string;
}
type OrderEvent =
| { type: 'ADD_ITEM'; item: LineItem }
| { type: 'REMOVE_ITEM'; itemId: string }
| { type: 'SUBMIT' }
| { type: 'PAY'; paymentId: string }
| { type: 'CANCEL' }
| { type: 'SHIP'; trackingNumber: string }
| { type: 'DELIVER' }
| { type: 'RETURN' }
| { type: 'REFUND' };
const orderMachine = createMachine({
id: 'order',
initial: 'draft',
context: {
items: [],
customerId: '',
} as OrderContext,
states: {
draft: {
entry: 'initializeOrder',
on: {
ADD_ITEM: {
actions: assign({
items: ({ context, event }) => [...context.items, event.item],
}),
},
REMOVE_ITEM: {
actions: assign({
items: ({ context, event }) =>
context.items.filter(i => i.id !== event.itemId),
}),
},
SUBMIT: {
target: 'submitted',
guard: 'hasItems',
},
CANCEL: 'cancelled',
},
},
submitted: {
entry: 'reserveInventory',
exit: 'onSubmittedExit',
on: {
PAY: {
target: 'paid',
guard: 'paymentValid',
actions: assign({
paymentId: ({ event }) => event.paymentId,
}),
},
CANCEL: {
target: 'cancelled',
actions: 'releaseInventory',
},
},
},
paid: {
entry: 'confirmInventory',
on: {
SHIP: {
target: 'shipped',
actions: assign({
trackingNumber: ({ event }) => event.trackingNumber,
}),
},
REFUND: 'refunded',
},
},
shipped: {
entry: 'sendTrackingNotification',
on: {
DELIVER: 'delivered',
RETURN: 'returned',
},
},
delivered: {
on: {
RETURN: 'returned',
},
after: {
'14d': 'completed',
},
},
returned: {
on: {
REFUND: 'refunded',
},
},
completed: { type: 'final' },
cancelled: { type: 'final' },
refunded: { type: 'final' },
},
}, {
guards: {
hasItems: ({ context }) => context.items.length > 0,
paymentValid: ({ event }) => event.type === 'PAY' && !!event.paymentId,
},
actions: {
initializeOrder: () => console.log('Order initialized'),
reserveInventory: ({ context }) =>
console.log(`Reserving ${context.items.length} items`),
confirmInventory: () => console.log('Inventory confirmed'),
releaseInventory: () => console.log('Inventory released'),
sendTrackingNotification: ({ context }) =>
console.log(`Tracking: ${context.trackingNumber}`),
},
});
| Category | What to Verify |
|---|---|
| Happy paths | Each valid transition produces correct next state |
| Invalid transitions | Rejected events in wrong states throw/return errors |
| Guards | Transitions blocked when guard conditions are false |
| Actions | Entry, exit, and transition actions fire correctly |
| Context | State context is updated correctly on transitions |
| Terminal states | Final states accept no further transitions |
| Full paths | End-to-end flows through the entire lifecycle |
import { describe, it, expect } from 'vitest';
describe('order state machine', () => {
// Happy path transitions
describe('valid transitions', () => {
it.each([
['draft', 'submit', 'submitted'],
['draft', 'cancel', 'cancelled'],
['submitted', 'pay', 'paid'],
['submitted', 'cancel', 'cancelled'],
['submitted', 'requireChanges', 'draft'],
['paid', 'ship', 'shipped'],
['paid', 'refund', 'refunded'],
['shipped', 'deliver', 'delivered'],
['shipped', 'return', 'returned'],
['delivered', 'finalize', 'completed'],
['delivered', 'return', 'returned'],
['returned', 'processReturn', 'refunded'],
] as const)('%s + %s → %s', (from, event, expected) => {
expect(transition(from, event)).toBe(expected);
});
});
// Invalid transitions
describe('rejected transitions', () => {
it.each([
['draft', 'pay'],
['draft', 'ship'],
['submitted', 'ship'],
['paid', 'cancel'],
['completed', 'cancel'],
['cancelled', 'submit'],
['refunded', 'refund'],
] as const)('%s + %s → throws', (from, event) => {
expect(() => transition(from, event)).toThrow();
});
});
// Full lifecycle paths
describe('end-to-end paths', () => {
it('happy path: draft → completed', () => {
let status: OrderStatus = 'draft';
for (const event of ['submit', 'pay', 'ship', 'deliver', 'finalize'] as const) {
status = transition(status, event);
}
expect(status).toBe('completed');
});
it('return path: draft → refunded', () => {
let status: OrderStatus = 'draft';
for (const event of ['submit', 'pay', 'ship', 'return', 'processReturn'] as const) {
status = transition(status, event);
}
expect(status).toBe('refunded');
});
it('cancellation from submitted', () => {
let status: OrderStatus = 'draft';
status = transition(status, 'submit');
status = transition(status, 'cancel');
expect(status).toBe('cancelled');
});
});
// Terminal states accept nothing
describe('terminal states', () => {
const terminalStates: OrderStatus[] = ['completed', 'cancelled', 'refunded'];
const allEvents = Object.values(OrderEvent);
for (const state of terminalStates) {
it(`${state} rejects all events`, () => {
for (const event of allEvents) {
expect(() => transition(state, event)).toThrow();
}
});
}
});
});
import { describe, it, expect, vi } from 'vitest';
import { createActor } from 'xstate';
describe('order machine (XState)', () => {
function createOrderActor(context?: Partial<OrderContext>) {
return createActor(orderMachine, {
input: context,
});
}
// Snapshot testing: verify state after events
describe('transitions', () => {
it('submits when items exist', () => {
const actor = createOrderActor();
actor.start();
actor.send({ type: 'ADD_ITEM', item: { id: '1', name: 'Widget', qty: 1 } });
actor.send({ type: 'SUBMIT' });
expect(actor.getSnapshot().value).toBe('submitted');
expect(actor.getSnapshot().context.items).toHaveLength(1);
});
it('blocks submit without items (guard)', () => {
const actor = createOrderActor();
actor.start();
actor.send({ type: 'SUBMIT' });
expect(actor.getSnapshot().value).toBe('draft');
});
});
// Guard testing
describe('guards', () => {
it('blocks payment without paymentId', () => {
const actor = createOrderActor();
actor.start();
actor.send({ type: 'ADD_ITEM', item: { id: '1', name: 'Widget', qty: 1 } });
actor.send({ type: 'SUBMIT' });
actor.send({ type: 'PAY', paymentId: '' });
expect(actor.getSnapshot().value).toBe('submitted');
});
});
// Action testing: verify side effects
describe('actions', () => {
it('calls reserveInventory on entering submitted', () => {
const reserveInventory = vi.fn();
const testMachine = orderMachine.provide({
actions: { reserveInventory },
});
const actor = createActor(testMachine);
actor.start();
actor.send({ type: 'ADD_ITEM', item: { id: '1', name: 'Widget', qty: 1 } });
actor.send({ type: 'SUBMIT' });
expect(reserveInventory).toHaveBeenCalledOnce();
});
});
// Context mutation testing
describe('context updates', () => {
it('stores trackingNumber on ship', () => {
const actor = createOrderActor();
actor.start();
actor.send({ type: 'ADD_ITEM', item: { id: '1', name: 'Widget', qty: 1 } });
actor.send({ type: 'SUBMIT' });
actor.send({ type: 'PAY', paymentId: 'pay_123' });
actor.send({ type: 'SHIP', trackingNumber: 'TRACK_456' });
expect(actor.getSnapshot().context.trackingNumber).toBe('TRACK_456');
});
});
});
machine.provide({ actions }) to inject mocks and verify calls(state, event) pair not in the valid set, assert rejection@xstate/test to auto-generate test paths from the machine definitionSubmitted not SubmitSubmit not Submitted| Pattern | Use Case |
|---|---|
| Linear | Simple sequential flow |
| Choice | Conditional branching |
| Parallel | Concurrent activities |
| Hierarchical | Complex nested states |
| History | Resume from last state |
When designing state machines:
Last Updated: 2026-03-25