Works with the AI Agents you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIMuseMuseDotsDots+22 more

    React Component State Machine Outliner

    1

    Architect complex React component logic with exhaustive XState machine mapping and transition outlines.

    $5

    Secure checkout via Stripe

    Money-back guarantee

    Converts to your local currency at checkout

    Security scanned
    React Component State Machine Outliner

    React Component State Machine Outliner

    Example session with this skill installed

    Feature Description: A multi-step checkout wizard with a cart review step, shipping address form, payment processing, and success confirmation. Key Requirements/Edge Cases: The user must be able to go back to previous steps without losing data. Payment processing can fail and should allow 3 retries before locking the session.

    • Read your context and instructions
    • Compiled the react component state

    1. Machine Overview

    A multi-step checkout wizard that moves a user through

    cart review → shipping address → payment → success. It supports non-destructive backward navigation (all entered data lives in context and survives step changes) and a payment retry policy: a failed payment can be retried up to 3 times, after which the session is locked and no further payment attempts are possible.

    Scope: step navigation, form data retention, payment invocation and failure handling, retry counting, session locking. Out of scope: field-level input validation UI (handled by form libraries), cart editing, and payment-provider UI internals.

    2. Context (Extended State)

    interface CheckoutContext {
      cart: {
        items: Array<{ id: string; name: string; qty: number; unitPrice: number }>;
        subtotal: number;
      };
      shippingAddress: {
        fullName: string;
        line1: string;
        line2?: string;
        city: string;
        state: string;
        postalCode: string;
        country: string;
        phone?: string;
      } | null;
      paymentDetails: {
        method: 'card' | 'upi' | 'wallet';
        token: string;            // tokenized reference only, never raw card data
        billingSameAsShipping: boolean;
      } | null;
      paymentAttempts: number;    // starts at 0, max 3
      maxPaymentAttempts: number; // constant 3
      lastError: { code: string; message: string } | null;
      orderId: string | null;
      lockedReason: string | null;
    }
    

    3. Events

    • NEXT: advance from the current step (payload: none; relies on context already updated)
    • BACK: return to the previous step (no payload)
    • UPDATE_CART: { items: CartItem[] }, sync cart changes in from the outside
    • UPDATE_SHIPPING: { address: ShippingAddress }, save form data without leaving the step
    • SUBMIT_SHIPPING: { address: ShippingAddress }, save and advance
    • UPDATE_PAYMENT: { details: PaymentDetails }, save payment form data
    • SUBMIT_PAYMENT: { details: PaymentDetails }, save and start processing
    • RETRY_PAYMENT: no payload, retry after a failure
    • EDIT_PAYMENT: no payload, return to the payment form after a failure to change details
    • RESET: no payload, start a new checkout (only from success or locked, per product decision)

    Internal (invoked actor) events: done.invoke.processPayment (output: { orderId }) and error.platform.processPayment (error: { code, message }).

    4. State Diagram Outline

    • State: checkout (root)

      • Type: compound (parent of the wizard steps; holds the history-preserving behavior)
      • On RESET: Transitions to checkout.cartReview (Guard: none; action resetContext)
      • Entry Actions: none
      • Exit Actions: none
    • State: checkout.cartReview

      • Type: initial
      • On UPDATE_CART: Stays (action: assignCart)
      • On NEXT: Transitions to shippingAddress (Guard: cartHasItems)
      • Entry Actions: trackStepViewed('cart')
      • Exit Actions: none
    • State: checkout.shippingAddress

      • Type: atomic
      • On UPDATE_SHIPPING: Stays (action: assignShipping)
      • On SUBMIT_SHIPPING: Transitions to payment (Guard: isShippingValid; action: assignShipping)
      • On BACK: Transitions to cartReview (no guard; context untouched)
      • Entry Actions: trackStepViewed('shipping')
      • Exit Actions: none (data already persisted via UPDATE_SHIPPING)
    • State: checkout.payment

      • Type: compound (parent of the payment sub-states)
      • Initial child: form

    On BACK: Transitions to shippingAddress (Guard: not isProcessing, enforced by only handling BACK on the form child, not on processing)

    • Entry Actions: trackStepViewed('payment')

    • Exit Actions: none

    • State: checkout.payment.form

      • Type: atomic
      • On UPDATE_PAYMENT: Stays (action: assignPayment)

    On SUBMIT_PAYMENT: Transitions to processing (Guard: isPaymentValid; actions: assignPayment, incrementAttempts)
    - On BACK: Transitions to shippingAddress
    - Entry Actions: none
    - Exit Actions: none

    • State: checkout.payment.processing
      • Type: atomic (invokes processPayment actor)
      • Invoke: processPayment with input { cart, shippingAddress, paymentDetails }
      • On done.invoke.processPayment: Transitions to success (action: assignOrderId)
      • On error.platform.processPayment: Transitions to failed (action: assignError)

    On BACK / NEXT / SUBMIT_PAYMENT: Ignored (no handler, which prevents double submission and mid-flight navigation)
    - Entry Actions: showProcessingOverlay, clearLastError
    - Exit Actions: hideProcessingOverlay

    • State: checkout.payment.failed
      • Type: atomic (transient decision point)
      • Always (eventless transitions), evaluated in order:
        1. Transitions to #checkout.locked (Guard: attemptsExhausted, i.e. paymentAttempts >= maxPaymentAttempts; action: assignLockReason)
        2. Otherwise stays and waits for user events

    On RETRY_PAYMENT: Transitions to processing (Guard: canRetry, i.e. paymentAttempts < maxPaymentAttempts; action: incrementAttempts)
    - On EDIT_PAYMENT: Transitions to form (Guard: canRetry)
    - On BACK: Transitions to form (Guard: canRetry)
    - Entry Actions: showPaymentErrorBanner, trackPaymentFailure
    - Exit Actions: dismissPaymentErrorBanner

    • State: checkout.success
      • Type: final
      • On RESET: Transitions to cartReview (action: resetContext)

    Entry Actions: clearPaymentDetails (purge token from context), trackOrderCompleted, clearPersistedCheckout

    • Exit Actions: none

    • Note: no BACK handler, so the user cannot return to payment after a completed order.

    • State: checkout.locked

      • Type: final (terminal for this session)

    On RESET: Transitions to cartReview (Guard: lockExpired or an explicit support/new-session policy; action: resetContext)

    Entry Actions: clearPaymentDetails, showLockedMessage, notifyBackend('session_locked'), trackSessionLocked

    • Exit Actions: none
    • Note: all payment events are intentionally unhandled here.

    Attempt counting note: incrementAttempts runs on every transition into processing (first submit and each retry), so after the third failed attempt paymentAttempts === 3, the attemptsExhausted guard passes, and the session locks. If your product definition is "initial try plus 3 retries" (4 total), set maxPaymentAttempts to 4.

    5. Implementation Notes

    Keep step data in context, not in component state. Because every UPDATE_* event writes to context, the BACK transitions need no special logic and no history state. Components should read defaults from snapshot.context so returning to a step repopulates the form. For refresh resilience, persist the snapshot with actor.getPersistedSnapshot() to sessionStorage and rehydrate via createActor(machine, { snapshot }). Exclude paymentDetails.token from persistence.

    1. Model the payment call as an invoked actor with fromPromise. Use setup({ types, guards, actions, actors }) for typed XState v5 code, e.g. processPayment: fromPromise(({ input, signal }) => api.pay(input, { signal })), and pass an idempotency key (derive it from cart plus the attempt number) so a retry after a network timeout cannot double-charge. Because processing ignores BACK, double submits and mid-flight navigation are impossible by construction; also disable the buttons from snapshot.matches({ payment: 'processing' }).

    2. Drive the UI from snapshot.matches and derive flags with selectors. Use useSelector(actor, s => s.matches(...)) to render each step, and compute values like attemptsRemaining = max - paymentAttempts for the retry banner. Enforce the lock server-side as well (notifyBackend('session_locked')), because a client-side lock can be bypassed by reloading or clearing storage.

    Connects securely to your tools. The creator never sees your data.

    About this skill

    Architecting complex UI logic in React often leads to "boolean soup" where dozens of useState hooks create impossible-to-debug edge cases. This skill eliminates logic errors by mapping out a formal XState machine architecture before you write a single line of component code.

    What it does

    • State mapping identifies all resting, loading, error, and transitional states to prevent unreachable UI configurations.
    • Transition logic defines exactly which user actions or system triggers move the component between specific states.
    • Context modeling outlines the extended state and data types required to track component data.
    • Guard specification documents conditional logic and business rules required for state transitions.
    • Side effect planning maps entry and exit actions for data fetching, logging, or DOM interactions.

    How it works

    1. Provide a detailed description of the UI feature and its intended behavior.
    2. Supply any specific edge cases or business requirements that must be handled.
    3. Review the generated machine overview and context schema.
    4. Use the state diagram outline to implement the logic in XState v5.

    Frameworks & tools

    Specifically designed for React applications using XState v5. It generates architecture compatible with @xstate/react and the Stately editor.

    Why this beats prompting it yourself

    Generic LLM prompts often miss intermediate transitional states or fail to account for complex guards, leading to "halted" machines. This skill uses a structured architectural pattern that forces the agent to account for every possible event-state pair, ensuring your finite state machine is actually finite and exhaustive.

    Use cases

    • Designing multi-step checkout flows with complex validation and payment states.
    • Architecting data-intensive dashboards with nested loading and filtering logic.
    • Building robust modal and overlay systems that handle interruptions and errors.
    • Modeling intricate drag-and-drop or drawing tool interactions.

    Known limitations

    Does not output executable TypeScript code or machine factory functions directly. It provides the architectural blueprint that the developer must then implement into a machine definition file.

    How to use

    Skills on Agensi run inside your AI agent. Copy the prompt, paste it into your agent, and it connects to Agensi and installs this skill for you. If a payment is needed, your agent shows it to you first.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill passes our trust checks below.

    Security scanned

    Passed our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    Money-back guarantee

    Doesn't do what its page promises? You get your money back.

    Trust & safety

    Security scanned

    Verified clean 3 days ago

    • Passed all security checks, Safe to install

    Listed3 days ago

    What's inside

    Frequently Asked Questions