# Machina Authoring

> 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.

- Skill: `arisng/machina-authoring` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add arisng/machina-authoring`
- Raw SKILL.md: https://api.skillmd.com/api/skills/arisng/machina-authoring/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: arisng (https://skillmd.com/u/arisng)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/arisng/machina-authoring

---


# 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.

```json
{
  "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

1. Read [references/schema-spec.md](references/schema-spec.md) — full field reference, naming
   conventions, guard/action semantics.
2. Model states first: identify every distinct status, mark true final states `"type": "final"`
   explicitly (never rely on implicit finals).
3. 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.
4. Add `scenarios[]` entry points (`{id, label, initial, interface ∈ "UI"|"API"}`) — one per
   meaningful way the workflow starts.
5. 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.
6. Give every state a real, human `description` — placeholder text is auto-detectable
   (`generated: true`) and reads as a gap.
7. 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](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:

```powershell
# 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](../../copilot-extensions/machina-simulator/simulator/docs/maintenance.md)
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](references/schema-spec.md) | Any authoring work — field tables, versioning, guard/action semantics |
| [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 |

## 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.

