Build and verify from one behavioral contract.

Wirestate stores composable state machines, optional screens, interaction metadata, and human intent in simple YAML. The normalized project is plain JSON-compatible data that can be consumed by any language adapter.

Core concepts

Machine

A hierarchical finite state machine defines legal states and transitions. Nested machines let a repository model large applications without one enormous flat graph.

Screen

An optional low-fidelity layout attached to a state. Behavior-only services and CLI tools can omit screens entirely.

Interaction

Transition metadata links a component and interaction kind to a machine event. The local studio and CLI resolve that metadata through the same core interpreter.

Trace

A language-neutral stream of visited states, transitions, and touched components emitted by tests or the application under test.

Quick start

npm install
npm run build
node dist/cli.js check --cwd examples/habit-tracker
node dist/cli.js serve --cwd examples/habit-tracker --open

The studio opens with the state graph and interactive prototype side by side. Click the wireframe controls to follow legal transitions. Graph clicks inspect states; double-clicking performs an explicit runtime jump.

A small DSL

wirestate: 1
namespace: checkout

machines:
  app:
    initial: cart
    states:
      cart:
        screen: cart
        on:
          CHECK_OUT:
            target: payment
            interaction:
              kind: click
              component: checkout.submit
      payment:
        screen: payment

screens:
  cart:
    root:
      type: Container
      children:
        - type: Text
          props: { text: Your cart }
        - id: checkout.submit
          type: Button
          props: { label: Check out }

Files can import other files, allowing machines, shared component templates, screens, and comments to live near the modules they describe.

Prototype interactions

The initial interaction kinds are click, fill, toggle, submit, wait, and custom. Buttons and toggles can immediately drive transitions. Text inputs retain local prototype values and can submit a fill transition with Enter.

The browser does not choose transitions independently. It sends the component and interaction kind to the core, which resolves the legal transition for the current hierarchical state.
wirestate interact \
  --machine checkout.app \
  --state cart \
  --component checkout.submit \
  --kind click

Conformance and coverage

Conformance rejects observed states or transitions that do not exist in the model. Coverage reports expected states and transitions that tests have not demonstrated. A project can conform while still having incomplete coverage, so CI policies should treat them separately.

{"type":"state","machine":"checkout.app","state":"cart"}
{"type":"transition","machine":"checkout.app","from":"cart","event":"CHECK_OUT","to":"payment"}
{"type":"component","id":"checkout.submit","action":"click"}

Run wirestate check to validate specs, scan source bindings in both directions, parse configured traces, and enforce coverage thresholds.

Agentic development workflow

A coding agent receives explicit desired states, allowed transitions, wireframe structure, stable component identifiers, comments, and prior verification evidence. A typical change becomes:

  1. Change the spec and review its filesystem diff.
  2. Observe newly uncovered behavior in CI.
  3. Generate or modify code against the normalized contract.
  4. Exercise the application and collect traces.
  5. Verify conformance, coverage, and source synchronization.

Colocated TypeScript example

The included habit tracker is split by feature, with implementation and specification files living together. The browser application tracks measurable chunks against daily or weekly goals; a separate export CLI demonstrates a behavior-only machine that is still part of the same product repository.

examples/habit-tracker/
  src/shell/       app.ts + app.wire.yml
  src/habits/      model.ts, store.ts + habits.wire.yml
  src/goals/       progress.ts + goals.wire.yml
  src/sync-cli/    index.ts + sync.wire.yml
npm run example:build
npm run example:app
npm run example:sync
npm run example:check

The app and CLI both emit the same JSON trace protocol, so the verifier remains independent of language and surface.

CLI surface

wirestate validate [--json]
wirestate inspect [--json]
wirestate graph [MACHINE] [--dot|--json]
wirestate simulate --machine ID --events EVENT,EVENT
wirestate jump --machine ID --state ID
wirestate interact --machine ID --state ID --component ID --kind click
wirestate sync [--json]
wirestate coverage [TRACE...]
wirestate check [--json]
wirestate serve [--port PORT] [--open]
wirestate comment list|add|update|remove
wirestate smoke generate --machine ID --out FILE

Why derived artifacts are not manually editable

Wirestate is intentionally specification-first. The YAML specification is the source of truth; visual graphs, prototypes, generated tests, scaffolds, and reports are deterministic projections of it.

Manual edits to derived output cannot be reproduced, may be overwritten, and introduce ambiguity about what a coding agent should trust. Humans and agents should edit the specification or application source, then regenerate and verify derived artifacts.

This boundary does not remove human control. It moves control to reviewable intent rather than untracked modifications to generated output. The current studio writes specification comments; machine and screen structure remain filesystem-authored.

Deployment

GitHub Pages

The site is a static directory under site/. The included Pages workflow uploads that directory and deploys it on changes to main. Enable GitHub Actions as the Pages source in repository settings, then push or dispatch the workflow.

python3 -m http.server 8080 --directory site

npm

Confirm the final package name and repository metadata before the first public release. Verify the build and tarball before publishing.

npm install
npm run check
npm pack --dry-run
npm login
npm publish --access public