# SMCraft / Stateloom — State Machine Craft > Design, validate, generate and run hierarchical state machines. One declarative format (SMDF) read by an engine, a code generator, an MCP server, a terminal CLI, a socket.io hub and a browser canvas — so an agent, a person at a shell and a person at a canvas can all edit the same document while it is open. **Engine:** `@miadi/stateloom-engine` — 0.4.3 (npm; renamed from `smcraft`, deprecated) / `miadi-stateloom-engine` 0.2.1 (PyPI, CLI `smcg`) **Loom packages:** `@miadi/stateloom-*` — protocol, client, hub, react, cli, mcp, skills **Framework:** RISE v1.2 (Reverse-engineer → Intent-extract → Specify → Export) **Repository:** https://github.com/jgwill/smcraft **Published at:** https://docs.smcraft.jgwill.com ## Packages Nine published npm packages, plus the Python engine on PyPI. The designer source (`web/`) stays `"private": true`; its prebuilt standalone build ships as `@miadi/stateloom-web`. | Install | What it is | |---|---| | `npm i @miadi/stateloom-engine` (0.4.3) | The engine. SMDF parser, validator V001–V014, hierarchical runtime, SMDF interpreter, Python + TypeScript code generators. | | `pip install miadi-stateloom-engine` (0.2.1) | The Python twin of the engine, plus the `smcg` generator CLI. | | `npm i @miadi/stateloom-protocol` (0.1.5) | Zero-runtime-dependency foundation: patch ops, diff/apply, wire envelopes, layout, edge routing, viewport math, ASCII/Mermaid render, export naming, env aliasing. | | `npm i @miadi/stateloom-client` (0.1.2) | Framework-agnostic socket.io-client wrapper: join / patch / full / presence with auto-resync. | | `npm i @miadi/stateloom` (0.1.1) | The socket.io hub. Bin `smcraft-bridge`. | | `npm i @miadi/stateloom-react` (0.1.6) | React 19 binding: `useSmcraftBridge`, session core. Re-exports the protocol's viewport helpers at the address the web designer has always imported them from. | | `npm i @miadi/stateloom-canvas` (0.1.1) | The design surface as a mountable component: `` — wheel/⌃wheel/middle-drag/Space+drag/pinch navigation, composite drill-down, box dragging, routed edges, settled event chips, zoom HUD. Props in, callbacks out; every colour a `--slc-*` CSS variable. Ship `@miadi/stateloom-canvas/styles.css` with it. | | `npm i -g @miadi/stateloom-cli` (0.1.2) | Bin `smcx` — drive the loom from a terminal. | | `npx -y @miadi/stateloom-mcp` (0.2.0) | The MCP server. Bins `stateloom-mcp` and legacy `smcraft-mcp`. | | `npx -y @miadi/stateloom-skills` (0.2.0) | Bin `stateloom` — installs agent skills into `.claude/skills/`. | | `npx -y @miadi/stateloom-web` (0.1.0) | Bin `stateloom-web` — the visual designer, prebuilt. Serves on 4598; reads its bridge URL at runtime from `GET /api/config`. | Dependency direction: everything points at `@miadi/stateloom-protocol`. Nothing points back. ``` stateloom-protocol ──┬── stateloom-client ──┬── stateloom-react ──┬── web/ (designer) │ └── stateloom-mcp │ ├── stateloom-canvas ───────────────────────┬─┘ │ └── forgewright ├── stateloom (hub) ─── stateloom-cli ── stateloom-mcp └── (render, layout, viewport, exportName, env used by all) stateloom-engine ── generated code imports the runtime at execution time ``` ## The engine — `@miadi/stateloom-engine` npm subpath exports: - `@miadi/stateloom-engine` — barrel: model types, parser, runtime, codegen - `@miadi/stateloom-engine/runtime` — `ContextBase`, `Context`, `ContextAsync`, `State`, `StateKind`, `TransitionHelper`, `IObserver`, `ObserverNull`, `ObserverConsole` - `@miadi/stateloom-engine/machine` — `Machine`, the SMDF interpreter: runs a definition directly, no codegen (`new Machine(def)`, `machine.send(eventId)`, `machine.state`, `machine.done`) - `@miadi/stateloom-engine/parser` — `parseJson`, `parseFile`, `enrich`, `validate` - `@miadi/stateloom-engine/codegen` — `TypeScriptCodeGenerator` Python mirrors this as `stateloom.model`, `stateloom.parser`, `stateloom.runtime`, `stateloom.codegen`, `stateloom.cli`. `ObserverLogger` (Python `logging`) exists on the Python side only. ## SMDF — State Machine Definition Format Extension `.smdf.json` (also `.smdf.xml`, legacy `.fsm`). Three top-level sections: - `settings` — `namespace`, `name`, `asynchronous`, `objects[]`, `context`, `using[]` - `events` — event sources, each with `feeder`, `events[]` (typed `parameters`) and `timers[]` - `state` — one hierarchical tree, Root → composite → leaf State classification is derived from structure, not declared: leaf (no children), composite (`states[]`), final (`kind: "final"`), history (`kind: "history"`), parallel (`parallel`), root (top of tree). Validation rules V001–V014 cover uniqueness, reference integrity, final-state and parallel-region constraints, and timer references. Full schema: [Spec 70 — SMDF Format](./rispecs/70-smdf-format.spec.md) ## MCP server — 15 tools `@miadi/stateloom-mcp`, stdio by default (Streamable HTTP optional — see Transport below). Registration: ```json { "mcpServers": { "stateloom": { "command": "npx", "args": ["-y", "@miadi/stateloom-mcp"], "env": { "STATELOOM_PROJECT_FILE": "/absolute/path/to/machine.smdf.json", "STATELOOM_BRIDGE_URL": "http://127.0.0.1:4599" } } } } ``` **Build** — `create_state_machine(namespace, name, asynchronous?)`, `add_state(name, parent?, kind?, description?)`, `add_event(id, description?)`, `add_transition(state, event, nextState?, condition?, description?)`, `remove_state(name)` **Read** — `get_definition()`, `load_definition(json)`, `list_states()`, `list_events()` **Act** — `validate_definition()`, `generate_code(language)`, `generate_rispec(intent?)`, `render_diagram(format?, path?, scale?, theme?, stamp?, open?)` **Document** — `set_project_file(path)`, `get_project_file()` Plus resource `smcraft://definition` and prompt `design-state-machine(domain?, name?)`. **Transport.** Stdio by default — the server runs as a child process beside one agent. Setting `STATELOOM_MCP_HTTP_PORT` serves Streamable HTTP at `POST /mcp` instead (plus `GET /health`), for agents on other machines. HTTP mode requires `STATELOOM_MCP_TOKEN` and refuses to start without it, binds loopback unless told otherwise, and is **not multi-tenant**: the active document is process state, so every client shares one board. `STATELOOM_MCP_ROOT` bounds where that document can move and `STATELOOM_MCP_LOCK_PROJECT` pins it. Three of these carry more than their names say: - `render_diagram` writes the picture next to the project document and returns its absolute path; for `png` the image itself rides back inside the tool result, so an agent can look at what it just designed. `stamp: true` names each render instead of overwriting one file. - `generate_rispec` folds a PDE's intent, directions and ambiguities into the spec when the SMDF carries `settings._source.pdeId` / `pdeFolder`. - `set_project_file` re-points the active document mid-session — the disk target and the live bridge room both move, because the hub keys rooms by absolute project-file path. Details: [Spec 73 — MCP Server](./rispecs/73-mcp-server.spec.md), [Spec 76 — RISE Rispec Generator](./rispecs/76-rise-rispec-generator.spec.md) ## Terminal — `smcx` Global options: `--bridge `, `--doc `, `--name