state-machine-design

State Machine Design Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "state-machine-design" with this command: npx skills add melodic-software/claude-code-plugins/melodic-software-claude-code-plugins-state-machine-design

State Machine Design Skill

When to Use This Skill

Use this skill when:

  • State Machine Design tasks - Working on statechart and state machine modeling for lifecycle and behavior specification

  • Planning or design - Need guidance on State Machine Design approaches

  • Best practices - Want to follow established patterns and standards

Overview

Design finite state machines and statecharts for modeling entity lifecycles, workflows, and system behavior.

MANDATORY: Documentation-First Approach

Before designing state machines:

  • Invoke docs-management skill for state machine patterns

  • Verify implementation patterns via MCP servers (context7 for XState, etc.)

  • Base all guidance on Harel statechart semantics

State Machine Concepts

Core Elements

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

State Types

public enum 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 }

State Machine Notation

PlantUML Syntax

@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

Mermaid Syntax

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 --> [*]

C# Implementation Patterns

Simple State Machine

public sealed class Order : Entity { public OrderStatus Status { get; private set; }

private static readonly Dictionary<(OrderStatus From, OrderEvent Event), OrderStatus> _transitions =
    new()
    {
        { (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 },
    };

public Result Transition(OrderEvent @event)
{
    if (!_transitions.TryGetValue((Status, @event), out var newStatus))
    {
        return Result.Failure($"Cannot {@event} order in {Status} status");
    }

    var oldStatus = Status;
    Status = newStatus;

    AddDomainEvent(new OrderStatusChangedEvent(Id, oldStatus, newStatus, @event));

    return Result.Success();
}

}

public enum OrderStatus { Draft, Submitted, Paid, Shipped, Delivered, Completed, Cancelled, Returned, Refunded }

public enum OrderEvent { Submit, Cancel, Pay, RequireChanges, Ship, Refund, Deliver, Return, Finalize, ProcessReturn }

State Pattern Implementation

public abstract class OrderState { public abstract OrderStatus Status { get; }

public virtual Result Submit(Order order) =>
    Result.Failure($"Cannot submit order in {Status} state");

public virtual Result Cancel(Order order) =>
    Result.Failure($"Cannot cancel order in {Status} state");

public virtual Result Pay(Order order) =>
    Result.Failure($"Cannot pay order in {Status} state");

public virtual Result Ship(Order order) =>
    Result.Failure($"Cannot ship order in {Status} state");

protected void TransitionTo(Order order, OrderState newState)
{
    order.SetState(newState);
}

}

public sealed class DraftState : OrderState { public override OrderStatus Status => OrderStatus.Draft;

public override Result Submit(Order order)
{
    if (!order.HasItems)
        return Result.Failure("Order must have items to submit");

    TransitionTo(order, new SubmittedState());
    order.ReserveInventory();
    return Result.Success();
}

public override Result Cancel(Order order)
{
    TransitionTo(order, new CancelledState());
    return Result.Success();
}

}

public sealed class SubmittedState : OrderState { public override OrderStatus Status => OrderStatus.Submitted;

public override Result Pay(Order order)
{
    TransitionTo(order, new PaidState());
    order.ConfirmInventory();
    return Result.Success();
}

public override Result Cancel(Order order)
{
    order.ReleaseInventory();
    TransitionTo(order, new CancelledState());
    return Result.Success();
}

}

Stateless Library Pattern

using Stateless;

public sealed class OrderStateMachine { private readonly StateMachine<OrderStatus, OrderEvent> _machine; private readonly Order _order;

public OrderStateMachine(Order order)
{
    _order = order;
    _machine = new StateMachine&#x3C;OrderStatus, OrderEvent>(
        () => order.Status,
        status => order.SetStatus(status));

    ConfigureTransitions();
}

private void ConfigureTransitions()
{
    _machine.Configure(OrderStatus.Draft)
        .Permit(OrderEvent.Submit, OrderStatus.Submitted)
        .Permit(OrderEvent.Cancel, OrderStatus.Cancelled)
        .OnEntry(() => _order.InitializeOrder());

    _machine.Configure(OrderStatus.Submitted)
        .PermitIf(OrderEvent.Pay, OrderStatus.Paid,
            () => _order.PaymentIsValid)
        .Permit(OrderEvent.Cancel, OrderStatus.Cancelled)
        .Permit(OrderEvent.RequireChanges, OrderStatus.Draft)
        .OnEntry(() => _order.ReserveInventory())
        .OnExit(() => { /* cleanup if needed */ });

    _machine.Configure(OrderStatus.Paid)
        .Permit(OrderEvent.Ship, OrderStatus.Shipped)
        .Permit(OrderEvent.Refund, OrderStatus.Refunded)
        .OnEntry(() => _order.ConfirmInventory());

    _machine.Configure(OrderStatus.Shipped)
        .Permit(OrderEvent.Deliver, OrderStatus.Delivered)
        .Permit(OrderEvent.Return, OrderStatus.Returned)
        .OnEntry(() => _order.SendTrackingNotification());

    _machine.Configure(OrderStatus.Delivered)
        .Permit(OrderEvent.Finalize, OrderStatus.Completed)
        .Permit(OrderEvent.Return, OrderStatus.Returned);

    _machine.Configure(OrderStatus.Returned)
        .Permit(OrderEvent.ProcessReturn, OrderStatus.Refunded);

    // Terminal states
    _machine.Configure(OrderStatus.Completed);
    _machine.Configure(OrderStatus.Cancelled);
    _machine.Configure(OrderStatus.Refunded);
}

public bool CanFire(OrderEvent trigger) => _machine.CanFire(trigger);

public void Fire(OrderEvent trigger) => _machine.Fire(trigger);

public IEnumerable&#x3C;OrderEvent> GetPermittedTriggers() =>
    _machine.GetPermittedTriggers();

}

XState Pattern (TypeScript)

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: {
    // Auto-complete after 14 days
    '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}), }, });

Design Best Practices

State Design Guidelines

  • Name states as conditions: Submitted not Submit

  • Name events as commands: Submit not Submitted

  • Use guards for conditional transitions

  • Keep states atomic: One responsibility per state

  • Document entry/exit actions

  • Consider terminal states (final states)

Common Patterns

Pattern Use Case

Linear Simple sequential flow

Choice Conditional branching

Parallel Concurrent activities

Hierarchical Complex nested states

History Resume from last state

Workflow

When designing state machines:

  • Identify entity: What has the lifecycle?

  • List states: What conditions can it be in?

  • Define events: What triggers state changes?

  • Map transitions: State + Event → New State

  • Add guards: What conditions must be true?

  • Define actions: What happens on transitions?

  • Draw diagram: Visualize for review

  • Implement: Choose appropriate pattern

References

For detailed guidance:

Last Updated: 2025-12-26

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

design-thinking

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

plantuml-syntax

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

system-prompt-engineering

No summary provided by upstream source.

Repository SourceNeeds Review