Skip to main content

State Machine

Project-scoped state machine designs with a two-role workflow: developers define the vocabulary, product managers wire it into diagrams. Available in the web UI at embedhub.com/tools/StateMachine.

Useful for firmware control flows, onboarding flows, protocol handshakes — anything where a designer and an implementer need to agree on what states exist and how the system moves between them.

The two-role model

A state machine in EmbedHub is split into two files in your project:

FileOwnerContains
state-machines/palette/palette.yamlDeveloperThe list of legal states and events
state-machines/diagrams/<slug>.yamlProduct managerA diagram wiring palette states with transitions

There is exactly one palette per project, and as many diagrams as you want — for example happy-path.yaml, error-recovery.yaml, setup.yaml — all sharing the same vocabulary.

A diagram can only use states and events that the palette declares. Saving a diagram that references something the palette doesn't define is rejected with a field-level validation error.

The palette

A small YAML file listing the states and events your firmware (or system) supports. The developer owns it because each id corresponds to something they've actually implemented. The palette is authored and updated via the EmbedHub CLI — the web UI only displays it.

version: "2.0"
states:
- id: init
description: "Boot-time initialization"
- id: calibration
description: "Sensor calibration routine"
- id: idle
description: "Ready, waiting for activity"
- id: sleep
description: "Low-power state"

events:
- id: init_success
description: "Initialization completed without errors"
- id: calibration_success
description: "Calibration finished within tolerance"
- id: calibration_fail
description: "Calibration outside tolerance; retry from init"
- id: idle_timeout
description: "No activity for the configured idle window"

Field rules:

  • id is lowercase, starts with a letter or digit, then letters, digits, or _. Must be unique within states (and within events). Ids are also what diagrams reference and what shows up on the canvas — keep them short and readable.
  • description is optional, shown next to the id when picking events in the diagram editor.

A diagram

Each diagram is a separate YAML file. The slug in the filename becomes the diagram's identifier in the UI and in URLs.

version: "2.0"
name: "Boot and idle"
description: "Power-on through calibration into the idle/sleep loop"

initial_state: init

transitions:
- from: init
to: calibration
event: init_success
- from: calibration
to: idle
event: calibration_success
- from: calibration
to: sleep
event: calibration_fail
- from: idle
to: sleep
event: idle_timeout

layout:
nodes:
- id: init
x: 120
y: 80
- id: calibration
x: 320
y: 80
- id: idle
x: 520
y: 80
- id: sleep
x: 720
y: 80

What gets validated when you save:

  • Every from, to, and event must exist in the palette.
  • initial_state must be one of the palette's states.
  • name is required.

layout is editor-managed positions for the drag-and-drop canvas and doesn't affect the semantics — feel free to omit it when writing by hand.

A paired <slug>.svg is generated and saved alongside the YAML so the diagram can be embedded in other project docs (see In your docs below).

Permissions

Access is controlled by the project role permission system, scoped by folder prefix. Roles you'd typically configure on a project:

RolePermission
Developerwrite on state-machines/palette/* and state-machines/diagrams/*
Product Managerwrite on state-machines/diagrams/* only
Viewerread (default for project members)

The organization owner always has full access regardless of role.

Splitting the two folders is what lets you give a PM the right to edit diagrams without also giving them the keys to the vocabulary.

In the web UI

The State Machine page has two tabs that follow the two-role model:

  • Palette — a read-only listing of the states and events available on the project. Editing happens through the EmbedHub CLI; the tab shows the exact commands to pull, edit, and push palette.yaml.
  • Diagrams — a drag-and-drop canvas. Pick states from the sidebar to add them to the canvas, drag between handles to connect, and the editor prompts for the event from the palette. The Mark initial button sets the selected state as the entry point. Auto-layout runs a left-to-right graph layout. Read-only if you lack write permission on the diagrams folder.

The project page shows a State Machines section listing every diagram with a link into the editor, and inlines the most recent diagram as an image.

In your docs

Project documentation can embed a diagram by relative path — useful for design docs that should always show the current state machine. The file must use the .mdx extension; plain .md is handed to the browser as-is and the relative path won't resolve.

The onboarding flow is captured here:

![Onboarding](../state-machines/diagrams/onboarding.svg)

When the markdown viewer renders the page, the image resolves to the diagram's SVG from the same project. Update the diagram, refresh the doc, and the embedded image updates with it. See Markdown & MDX for the full set of MDX features.

From the CLI

Because the palette and diagrams are just files in your project, the standard file commands work:

# Pull the current palette and edit it locally
embedhub pull myorg/myproject state-machines/palette/palette.yaml
$EDITOR palette.yaml
embedhub push myorg/myproject state-machines/palette/palette.yaml

# List existing diagrams
embedhub list myorg/myproject --prefix state-machines/diagrams/

# Create or update a diagram from a local file
embedhub push myorg/myproject state-machines/diagrams/onboarding.yaml

See the CLI documentation for the full command reference.

For AI agents

An AI agent with the EmbedHub CLI installed can author both files the same way it would any other project file. The recommended flow:

# 1. Read the existing vocabulary so the agent knows what's available.
embedhub pull myorg/myproject state-machines/palette/palette.yaml

# 2. Generate or update a diagram referencing only ids that exist in the palette.
embedhub push myorg/myproject state-machines/diagrams/proposed-flow.yaml

The same prefix-based permissions described above apply: an agent operating with a project role that has write on state-machines/diagrams/* but not on state-machines/palette/* can freely add diagrams but cannot extend the vocabulary on its own — exactly the same boundary a human PM would hit.

When a diagram references states or events that aren't in the palette, the push is rejected with 422 and a list of the offending paths, so the agent gets immediate, structured feedback to fix the file.

The accompanying <slug>.svg rendered by the web editor is not required for the YAML to be valid — agents can push a diagram YAML without one and re-render later by opening the diagram in the web UI.