Machina Machine Authoring
Guidance for writing state-machine definitions that open cleanly in the Machina simulator and
score well against its compliance scorer.
Glossary
Use these terms consistently — in prompts, output, and code comments:
| Term |
Meaning |
| Machina |
Brand name covering both the simulator app (served by the machina-simulator extension) and its machine schema spec. Qualify which: "Machina simulator" (the app) vs "Machina schema spec" (the JSON contract). Never use bare "Machina" where the referent is ambiguous. |
| State machine |
The modeled FSM itself. Always write "state machine", never bare "machine". |
| Machine definition |
The JSON document that encodes a state machine (the artifact you author). A file contains one definition. |
| Schema spec / spec version |
The versioned field contract (v1.0.0, v2.0.0, v3.0.0) a definition targets via spec_version. Distinct from the definition's own version field. |
| Final state |
A state typed "type": "final" (or with no outgoing transitions). Prefer "final state" over "terminal" — matches UML/XState. |
| Event |
Named trigger (UPPER_SNAKE) that fires a transition from a state's on map. |
| Transition |
{ EVENT: { target, guard?, actions? } } — moves between states. |
| Guard |
Declarative predicate { type:"compare", key, op, value } gating a transition. Matches SCXML/XState semantics. |
| Action |
Declarative side effect { type:"increment"|"assign" } on context. No code strings, ever. |
| Context |
Extended state data available to guards/actions; supports dotted paths. |
| Scenario / entry point |
A named start into the state machine (scenarios[] with initial, interface ∈ UI·API). |
| Compliance scorer |
The deterministic 23-check evaluator producing score/grade/gaps (in-app or via machine-validator.py). 22 checks are weighted (total weight 100 at v2, 119 at v3); tools-exist is a weight-0 informational review check. Not "checker", "linter", or "validator" (validation is only its blocking subset). |
| Gap |
A failing check finding: auto (deterministically fillable) or review (needs human judgment). |
Minimal viable machine
Every state machine definition needs at minimum: id, non-empty states, initial resolving
to a state key, and every transition target pointing at an existing state key.
{
"id": "order-fulfillment",
"name": "Order Fulfillment",
"version": "1.0.0",
"spec_version": "3.0.0",
"initial": "pending",
"context": { "attempts": 0 },
"scenarios": [
{ "id": "default", "label": "Default", "initial": "pending", "interface": "API" }
],
"states": {
"pending": {
"description": "Awaiting payment confirmation.",
"on": {
"PAY": { "target": "paid", "actions": [{ "type": "assign", "key": "attempts", "value": 0 }] },
"RETRY_PAY": { "target": "pending", "guard": { "type": "compare", "key": "attempts", "op": "lt", "value": 3 }, "actions": [{ "type": "increment", "key": "attempts" }] }
}
},
"paid": { "description": "Payment confirmed.", "on": { "SHIP": { "target": "shipped" } } },
"shipped": { "type": "final", "description": "Order delivered to carrier." }
}
}
Authoring workflow
- Read references/schema-spec.md — full field reference, naming
conventions, guard/action semantics.
- Model states first: identify every distinct status, mark true final states
"type": "final"
explicitly (never rely on implicit finals).
- Wire events with declarative objects only — guards
{type:"compare",…}, actions
{type:"increment"/"assign",…}. Never embed code strings; the format must stay shareable and
safe to ingest.
- Add
scenarios[] entry points ({id, label, initial, interface ∈ "UI"|"API"}) — one per
meaningful way the workflow starts.
- If any path can loop (retry, rework), add a genuine counter in
context
(retry/attempt naming) and gate the looping transition with a compare lt guard against
it — this is the only pattern the compliance scorer recognizes as cycle protection.
- Give every state a real, human
description — placeholder text is auto-detectable
(generated: true) and reads as a gap.
- Validate & score — use the bundled deterministic engine (see below) or open in Machina:
validate → iterate → target ≥90 ("Excellent") via score --text.
- Gaps flagged
auto can be applied deterministically with the script's apply
(or "Generate missing" in-app).
- Gaps flagged
review need your judgment: missing transitions, convention renames, event/state
naming, unreachable states. Fix these by hand — see references/machine-quality.md
for what each check demands.
Hard rules
- Declare
"spec_version": "3.0.0" explicitly so scoring never assumes latest silently.
- Event names
UPPER_SNAKE; state keys kebab-case.
- Guard
value may be a literal number/string or a context-key name (resolved then numeric-coerced).
- Context paths support dotted notation (
"payment.attempts").
- Terminal =
type:"final" or no outgoing transitions — prefer an explicit final state.
Deterministic tooling — use the bundled script
All deterministic authoring logic from the Machina simulator (validation, the 23-check
compliance scorer, gap analysis, autofill patching, scenario generation, cycle detection,
coverage building) is bundled as a standalone CLI. Run it instead of re-deriving logic or
loading simulator source:
# From workspace root; python3 on Linux/WSL
python3 skills/machina-authoring/scripts/machine-validator.py <command> <machine.json> [options]
| Command |
Purpose |
validate <file> |
Hard structural errors (blocking) — run first, always |
score <file> [--text] [--spec V] |
Full compliance report; JSON by default, --text for summary |
gaps <file> |
Ordered list of deterministic auto-fillable patches |
apply <file> id… [-o out.json] |
Apply selected patches (fixed order); default overwrites input |
scenarios <file> |
DFS-generated terminal paths + transition coverage % |
cycles <file> |
Cycle findings (CRITICAL depth / HIGH unguarded / MEDIUM valid) |
coverage <file> |
Exact coverage block "Generate missing" would embed |
Typical authoring loop: validate → iterate → score --text until ≥90 → gaps for remaining
auto-fillable items → apply (or hand-fix review items) → final score.
Known divergence (deliberate): the simulator source's check-inclusion filter
(specRank(since) <= specRank(target) over newest-first ranks) inverts v1/v2 inclusion versus
§14's documented model. The ported script implements the documented semantics (all 17 checks at
v2.0.0, weight = 100). When editing the simulator itself, follow
the machina-simulator extension's canonical maintenance docs
and keep this divergence in mind.
Compliance boundary — what the scorer does and does not verify
The scorer analyzes the machine declaration only; it never executes anything:
| What it verifies |
What it does NOT verify |
Schema structure, internal consistency, reference resolution (targets, tools, else_target) |
That any declared tool's runtime behavior actually holds |
tools[] registrations are well-formed and referenced correctly |
That a checks[]/requires[]/ensures[] predicate will pass when run |
tools-exist — each tool cmd's machine-relative path resolves to a file on disk (weight-0 review check; static file-stat, no execution) |
That a present script is correct, safe, or even runnable |
Consequences to teach authors and consumers alike:
- "Score 100 / Excellent" means declaration-sound, not runtime-sound. A machine can score
100 while a tool's script fails in practice — the scorer never runs it.
- The scorer never executes checker scripts. Only the driver actually runs them; see the
companion
machina-driving skill's "Trust boundary" for where runtime verification happens.
tools-exist is informational (weight 0): a dangling cmd reports a warn/review gap
without lowering the score, because the scorer has no execution context. When the machine file
is scored from disk (score <file>), its machine-relative paths are stat'd; in in-memory or
workspace-copied contexts with no resolvable directory the check passes trivially.
validate + --blocking findings are the soundness gate; the semantic checks above are quality
guidance.
Reference map (load on demand)
| File |
Load when |
| references/schema-spec.md |
Any authoring work — field tables, versioning, guard/action semantics |
| references/machine-quality.md |
Scoring below target, or proactively before finishing a definition — per-check author guidance, grade bands, review-vs-auto gaps |
Naming discipline in generated output
When authoring definitions or writing about them: say "state machine" or "machine definition"
(never bare "machine"), qualify "Machina simulator" vs "Machina schema spec", and use "final
state", "compliance scorer", and "gap (auto/review)" per the glossary. Field-level vocabulary
(guard, action, event, transition, context, scenario) is already industry-standard —
keep it verbatim.
1---2name: machina-authoring3description: Author valid, high-scoring state machines in Machina machine JSON format (spec v3.0.0 / v2.0.0 / v1.0.0). USE WHEN: writing or generating a machine definition (states, transitions, guards, actions, context, scenarios); modeling a real workflow (order fulfillment, refunds, signup, retries) as a Machina state machine; fixing or upgrading a machine JSON for validation or higher compliance score; explaining validation failures or low scores; running the bundled machina-validator.py CLI to validate, score, or generate gaps/scenarios; adding retry guards or cycle protection; or preparing machines for the compliance scorer ("Excellent" ≥90). DO NOT USE FOR: modifying the Machina simulator app, its engine, UI, or SPEC_REGISTRY (use machina-simulator-maintenance), debugging machine-validator.py scripts, XState config authoring, SCXML documents, or general diagramming.4---56# Machina Machine Authoring78Guidance for writing state-machine definitions that open cleanly in the Machina simulator and9score well against its compliance scorer.1011## Glossary1213Use these terms consistently — in prompts, output, and code comments:1415| Term | Meaning |16|---|---|17| **Machina** | Brand name covering both the simulator app (served by the `machina-simulator` extension) and its machine schema spec. Qualify which: "**Machina simulator**" (the app) vs "**Machina schema spec**" (the JSON contract). Never use bare "Machina" where the referent is ambiguous. |18| **State machine** | The modeled FSM itself. Always write "state machine", never bare "machine". |19| **Machine definition** | The JSON document that encodes a state machine (the artifact you author). A file contains one definition. |20| **Schema spec / spec version** | The versioned field contract (`v1.0.0`, `v2.0.0`, `v3.0.0`) a definition targets via `spec_version`. Distinct from the definition's own `version` field. |21| **Final state** | A state typed `"type": "final"` (or with no outgoing transitions). Prefer "final state" over "terminal" — matches UML/XState. |22| **Event** | Named trigger (`UPPER_SNAKE`) that fires a transition from a state's `on` map. |23| **Transition** | `{ EVENT: { target, guard?, actions? } }` — moves between states. |24| **Guard** | Declarative predicate `{ type:"compare", key, op, value }` gating a transition. Matches SCXML/XState semantics. |25| **Action** | Declarative side effect `{ type:"increment"\|"assign" }` on context. No code strings, ever. |26| **Context** | Extended state data available to guards/actions; supports dotted paths. |27| **Scenario / entry point** | A named start into the state machine (`scenarios[]` with `initial`, `interface ∈ UI·API`). |28| **Compliance scorer** | The deterministic 23-check evaluator producing score/grade/gaps (in-app or via `machine-validator.py`). 22 checks are weighted (total weight 100 at v2, 119 at v3); `tools-exist` is a weight-0 informational review check. Not "checker", "linter", or "validator" (validation is only its blocking subset). |29| **Gap** | A failing check finding: `auto` (deterministically fillable) or `review` (needs human judgment). |3031## Minimal viable machine3233Every state machine definition needs at minimum: `id`, non-empty `states`, `initial` resolving34to a state key, and every transition `target` pointing at an existing state key.3536```json37{38 "id": "order-fulfillment",39 "name": "Order Fulfillment",40 "version": "1.0.0",41 "spec_version": "3.0.0",42 "initial": "pending",43 "context": { "attempts": 0 },44 "scenarios": [45 { "id": "default", "label": "Default", "initial": "pending", "interface": "API" }46 ],47 "states": {48 "pending": {49 "description": "Awaiting payment confirmation.",50 "on": {51 "PAY": { "target": "paid", "actions": [{ "type": "assign", "key": "attempts", "value": 0 }] },52 "RETRY_PAY": { "target": "pending", "guard": { "type": "compare", "key": "attempts", "op": "lt", "value": 3 }, "actions": [{ "type": "increment", "key": "attempts" }] }53 }54 },55 "paid": { "description": "Payment confirmed.", "on": { "SHIP": { "target": "shipped" } } },56 "shipped": { "type": "final", "description": "Order delivered to carrier." }57 }58}59```6061## Authoring workflow62631. Read [references/schema-spec.md](references/schema-spec.md) — full field reference, naming64 conventions, guard/action semantics.652. Model states first: identify every distinct status, mark true final states `"type": "final"`66 explicitly (never rely on implicit finals).673. Wire events with declarative objects only — guards `{type:"compare",…}`, actions68 `{type:"increment"/"assign",…}`. Never embed code strings; the format must stay shareable and69 safe to ingest.704. Add `scenarios[]` entry points (`{id, label, initial, interface ∈ "UI"|"API"}`) — one per71 meaningful way the workflow starts.725. If any path can loop (retry, rework), add a genuine counter in `context`73 (`retry`/`attempt` naming) and gate the looping transition with a `compare lt` guard against74 it — this is the only pattern the compliance scorer recognizes as cycle protection.756. Give every state a real, human `description` — placeholder text is auto-detectable76 (`generated: true`) and reads as a gap.777. Validate & score — use the bundled deterministic engine (see below) or open in Machina:78 `validate` → iterate → target **≥90 ("Excellent")** via `score --text`.79 - Gaps flagged `auto` can be applied deterministically with the script's `apply`80 (or "Generate missing" in-app).81 - Gaps flagged `review` need your judgment: missing transitions, convention renames, event/state82 naming, unreachable states. Fix these by hand — see [references/machine-quality.md](machine-quality.md)83 for what each check demands.8485## Hard rules8687- Declare `"spec_version": "3.0.0"` explicitly so scoring never assumes latest silently.88- Event names `UPPER_SNAKE`; state keys `kebab-case`.89- Guard `value` may be a literal number/string or a context-key name (resolved then numeric-coerced).90- Context paths support dotted notation (`"payment.attempts"`).91- Terminal = `type:"final"` or no outgoing transitions — prefer an explicit **final state**.9293## Deterministic tooling — use the bundled script9495All deterministic authoring logic from the Machina simulator (validation, the 23-check96compliance scorer, gap analysis, autofill patching, scenario generation, cycle detection,97coverage building) is bundled as a standalone CLI. Run it instead of re-deriving logic or98loading simulator source:99100```powershell101# From workspace root; python3 on Linux/WSL102python3 skills/machina-authoring/scripts/machine-validator.py <command> <machine.json> [options]103```104105| Command | Purpose |106|---|---|107| `validate <file>` | Hard structural errors (blocking) — run first, always |108| `score <file> [--text] [--spec V]` | Full compliance report; JSON by default, `--text` for summary |109| `gaps <file>` | Ordered list of deterministic auto-fillable patches |110| `apply <file> id… [-o out.json]` | Apply selected patches (fixed order); default overwrites input |111| `scenarios <file>` | DFS-generated terminal paths + transition coverage % |112| `cycles <file>` | Cycle findings (CRITICAL depth / HIGH unguarded / MEDIUM valid) |113| `coverage <file>` | Exact coverage block "Generate missing" would embed |114115Typical authoring loop: `validate` → iterate → `score --text` until ≥90 → `gaps` for remaining116auto-fillable items → `apply` (or hand-fix review items) → final `score`.117118**Known divergence (deliberate):** the simulator source's check-inclusion filter119(`specRank(since) <= specRank(target)` over newest-first ranks) inverts v1/v2 inclusion versus120§14's documented model. The ported script implements the documented semantics (all 17 checks at121v2.0.0, weight = 100). When editing the simulator itself, follow122[the machina-simulator extension's canonical maintenance docs](../../copilot-extensions/machina-simulator/simulator/docs/maintenance.md)123and keep this divergence in mind.124125### Compliance boundary — what the scorer does and does not verify126127The scorer analyzes the machine **declaration** only; it never executes anything:128129| What it verifies | What it does NOT verify |130|---|---|131| Schema structure, internal consistency, reference resolution (targets, tools, `else_target`) | That any declared tool's **runtime behavior** actually holds |132| `tools[]` registrations are well-formed and referenced correctly | That a `checks[]`/`requires[]`/`ensures[]` predicate will **pass when run** |133| `tools-exist` — each tool `cmd`'s machine-relative path resolves to a file on disk (weight-0 **review** check; static file-stat, no execution) | That a present script is correct, safe, or even runnable |134135Consequences to teach authors and consumers alike:136137- **"Score 100 / Excellent" means *declaration-sound*, not *runtime-sound*.** A machine can score138 100 while a tool's script fails in practice — the scorer never runs it.139- The scorer **never executes** checker scripts. Only the driver actually runs them; see the140 companion `machina-driving` skill's "Trust boundary" for where runtime verification happens.141- `tools-exist` is **informational** (weight 0): a dangling `cmd` reports a `warn`/review gap142 without lowering the score, because the scorer has no execution context. When the machine file143 is scored from disk (`score <file>`), its machine-relative paths are stat'd; in in-memory or144 workspace-copied contexts with no resolvable directory the check passes trivially.145- `validate` + `--blocking` findings are the soundness gate; the semantic checks above are quality146 guidance.147148## Reference map (load on demand)149150| File | Load when |151|---|---|152| [references/schema-spec.md](references/schema-spec.md) | Any authoring work — field tables, versioning, guard/action semantics |153| [references/machine-quality.md](references/machine-quality.md) | Scoring below target, or proactively before finishing a definition — per-check author guidance, grade bands, review-vs-auto gaps |154155## Naming discipline in generated output156157When authoring definitions or writing about them: say "state machine" or "machine definition"158(never bare "machine"), qualify "Machina simulator" vs "Machina schema spec", and use "final159state", "compliance scorer", and "gap (`auto`/`review`)" per the glossary. Field-level vocabulary160(`guard`, `action`, `event`, `transition`, `context`, `scenario`) is already industry-standard —161keep it verbatim.