AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

State Machine Design

skill-amethystluna-embedded-workbench-state-machine-design · by AmethystLuna

Use when reviewing or fixing async protocols, retries, ACK/NACK handling, pending flags, timeout logic, or state-machine lockups in embedded firmware. NOT for generic network protocol design (TCP/HTTP/MQTT) unless targeting embedded firmware stack.

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-amethystluna-embedded-workbench-state-machine-design

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-amethystluna-embedded-workbench-state-machine-design)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
26d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of State Machine Design? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

This is a domain implementation skill. If you are planning, designing, or entering plan mode — load Skill("embedded-workbench") first to activate the workflow gates (Plan Verification Gate, Approval Gate, Closure Gate). Domain skills carry implementation guidance, not workflow enforcement.

State Machine Design

Core Rules

  • Fix the state model, not the symptom. Every in-progress or pending flag must have explicit success, failure, timeout, and reset exits.
  • Timeout logic must be gated on real pending work. Idle states must not trigger retry, recovery, or error transitions.
  • Do not trust a low-level send return value as proof of delivery when an application-layer ACK exists. Use the protocol's completion signal.
  • When adding retries, also define attempt timestamps, backoff rules, and cleanup paths so the state machine cannot lock up silently.
  • If pause, stop, or reconnect can interrupt the normal flow, add an explicit recovery or re-drive branch instead of assuming the old path will naturally resume.

Transition Gates

  • When a state transition depends on multiple preconditions, verify every one explicitly at the transition gate. Do not rely on implicit assumptions (e.g., "the timer expired, therefore everything must be healthy"). A single unchecked precondition is the most common source of silent state corruption.
  • If a target state's preconditions can become false while already in that state, define a reverse transition back to the source state. One-way state latches without fallback paths will eventually leak incorrect state to downstream consumers.

Transient Tolerance

  • Distinguish between genuine state-changing events and transient perturbations during mode switches, direction reversals, or re-initialization windows. The latter need a tolerance or grace window; only the former should advance the state machine or increment error counters.

Implementation Patterns

Pattern A: Per-State Handlers + Unified Error Gate

Each state gets its own handler function. The dispatcher is a pure switch(state). A unified fault-threshold check runs after all state handlers — no handler triggers the error transition itself. This keeps handlers simple and fault logic centralized.

// === State enum: exactly one valid state at all times ===
typedef enum {
    COMM_STATE_INIT,
    COMM_STATE_IDLE,
    COMM_STATE_SAMPLE_STARTING,
    COMM_STATE_SAMPLING,
    COMM_STATE_ERROR,
    COMM_STATE_RECOVERING,
} comm_state_t;

// === Runtime context: all flags explicit in one struct ===
typedef struct {
    comm_state_t state;
    uint32_t     command_fail_count;
    bool         data_ready;
    bool         communication_lost;
} comm_runtime_t;

// === Per-state handlers: each reads only what it needs ===
static void comm_handle_idle(comm_runtime_t *rt) {
    rt->warmup_start_time = sys_tick();
    comm_start_sample();
    rt->state = COMM_STATE_SAMPLE_STARTING;
}

static void comm_handle_error(comm_runtime_t *rt) {
    static uint32_t retry_tick = 0;
    if (retry_tick == 0) {
        retry_tick = sys_tick();
        rt->data_ready = false;
    }
    comm_power_off();
    if (sys_tick() - retry_tick state = COMM_STATE_RECOVERING;
}

static void comm_handle_recovering(comm_runtime_t *rt) {
    comm_handle_initializing(rt);   // Recovery RE-USES init — no duplicated paths
}

// === Dispatcher: pure switch, single exit ===
static void comm_state_process(comm_runtime_t *rt) {
    switch (rt->state) {
    case COMM_STATE_INIT:            comm_handle_initializing(rt);   break;
    case COMM_STATE_IDLE:            comm_handle_idle(rt);           break;
    case COMM_STATE_SAMPLE_STARTING: comm_handle_sample_starting(rt);break;
    case COMM_STATE_SAMPLING:        comm_handle_sampling(rt);       break;
    case COMM_STATE_ERROR:           comm_handle_error(rt);          break;
    case COMM_STATE_RECOVERING:      comm_handle_recovering(rt);     break;
    default:
        rt->state = COMM_STATE_INIT;  // Unknown state → safe fallback
        break;
    }

    // Unified error gate: checked AFTER every state, not buried inside handlers.
    // A new state cannot accidentally bypass this check.
    if (rt->command_fail_count >= COMM_MAX_FAILS) {
        rt->state = COMM_STATE_ERROR;
        rt->command_fail_count = 0;
        rt->communication_lost = true;
    }
}

Key properties:

  • Fault logic is centralized — the error gate runs exactly once, after every state. New states cannot bypass it.
  • Recovery reuses initcomm_handle_recovering() calls comm_handle_initializing(). No duplicated paths to drift apart.
  • All exits are explicitError has a cooldown period (500ms), then transitions to Recovering. No fall-through, no implicit assumption.
  • Unknown state → safe fallback — the default case resets to Init.

Pattern B: Function-Pointer Table Dispatch

Heavier than switch-case, but useful when states are added/removed frequently or handlers need different signatures.

static const struct {
    comm_state_t state;
    void (*process)(void);
} comm_state_table[] = {
    {COMM_STATE_INIT,       comm_init_process},
    {COMM_STATE_IDLE,       comm_idle_process},
    {COMM_STATE_CONNECTED,  comm_connected_process},
    {COMM_STATE_ERROR,      comm_error_process},
    {COMM_STATE_RECOVERING, comm_recovering_process},
};

void comm_state_dispatch(void) {
    for (size_t i = 0; i  TIMEOUT) { retry(); }
// t0 is always running, even when no work is in flight

// BAD: retry loop with no exit condition
void retry_forever(void) {
    while (!send_packet()) { delay(100); }  // Will lock up if HW is dead
}

// BAD: recovery path duplicates init logic instead of reusing it.
// The copy drifts over time — one path gets a fix, the other doesn't.

// BAD: Error handler directly calls power_off() without cooldown period.
// Power-cycling faster than the hardware spec causes unpredictable state.

When To Escalate

  • When diagnostics point to an architecture-level or state-machine design defect, proactively offer high-level remediation focused on boundary clarity, lifecycle contracts, and reversible transitions — don't just propose ad-hoc runtime patches.

REQUIRED SUB-SKILL: If you find a state machine bug, also load Skill("debug-methodology") to apply structured root-cause analysis. If the bug involves async lifecycle flags or hardware events, load Skill("embedded-firmware-dev"). If the state machine lockup triggers a watchdog reset or HardFault, load Skill("hardfault-triage").

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.