moon run cli -- <schema.yaml> [output.json]
moon run cli -- validate <schema.yaml>
moon run cli -- presets
moon run cli -- runtime available <schema.yaml> --state <state> [--input <json>]
moon run cli -- runtime execute <schema.yaml> --state <state> --transition <id> [--input <json>]
- If
output.jsonis omitted, JSON IR is printed to stdout. - Example input:
examples/schema_v1.yaml.
moon run cli -- validate <schema.yaml> --json
moon run cli -- validate <schema.yaml> --format json
moon run cli -- validate <schema.yaml> --baseline <baseline.yaml> --json
stdoutis JSON only (no extra human-readable text).- Exit code is
0on success,1on failure. - Expected validation failures are reported as JSON with
"ok": false.
v6 の最初の実装は、guided form builder -> validate -> runtime preview をつなぐ authoring-first workbench surface です。
GET /v6/workbenchGET /v6/workbench?case=purchase-requestGET /v6/workbench?format=mxPOST /v6/workbench/previewPOST /v6/workbench/preview?format=mx
- entity name / initial state / states / transitions を guided form で入力
- schema lifecycle (
Draft | Reviewing | Released | Deprecated) を workbench 上で保持する - rollout mode (
simulation | shadow | assisted | enforced) を workbench 上で保持する - hidden
state_slots/transition_slotsで可変 slot 数を保持する - 内部では
@schema.Schemaを直接組み立てる - validate error は Reason をそのまま表示
- preview は state ごとの available transitions を表示
- rollout section で「今は simulation/shadow/assisted/enforced のどこまで進めるべきか」を表示する
case=purchase-requestで、備品購入申請を想定した 6 state / 6 transition の preset builder を読み込める- fixture:
examples/workbench_v6/purchase_request_expected.html - preset は
schemaStatus=Released/rolloutMode=shadowを持ち、 「設計思想を保ったまま shadow で実運用を始める」導線をそのまま確認できる
examples/workbench_v6/expected.htmlexamples/workbench_v6/expected_mx.htmlexamples/workbench_v6/expected_invalid.html
- 既存の
api_v2〜api_v5frozen surface は変更しない - YAML export / graph editor / persistence は first slice の対象外
Compute available/blocked transitions from IR and a current state snapshot.
This is pure computation: no state mutation or side effects.
--input accepts an object of rule results (e.g. { "canApprove": true })
or { "rules": { ... } }.
Example output:
{
"availableTransitions": [
{ "id": "approve", "to": "Approved" }
],
"blockedTransitions": [
{
"id": "reject",
"reasons": [
{
"reasonVersion": 1,
"code": "RULE_NOT_SATISFIED",
"level": "info",
"target": "rule",
"message": "Rule not satisfied",
"hint": "Provide rule result true for this transition"
}
]
}
]
}
Execute a specific transition (pure computation only). Output is deterministic JSON.
Example output:
{
"ok": true,
"transition": {
"id": "approve",
"from": "Draft",
"to": "Approved"
},
"effects": []
}
Execute applies a single transition to the current state in a pure, deterministic way and returns a JSON envelope.
fwd runtime execute <schema.yaml> --state <state> --transition <id> --input <json>0: request is valid; outcome is encoded in JSON (executedorblocked)1: invalid transition request (not_foundornot_available)2: invalid--inputJSON (input/usage error)
See examples/runtime_execute/:
expected_executed.jsonexpected_blocked.jsonexpected_not_found.jsonexpected_not_available.json
Execute applies a single transition to the current state in a pure, deterministic way and returns a JSON envelope.
fwd runtime execute <schema.yaml> --state <state> --transition <id> --input <json>0: request is valid; outcome is encoded in JSON (executedorblocked)1: invalid transition request (not_foundornot_available)2: invalid--inputJSON (input/usage error)
See examples/runtime_execute/:
expected_executed.jsonexpected_blocked.jsonexpected_not_found.jsonexpected_not_available.json
hypermedia/resource is a new contract layered on top of runtime results.
It does not replace the frozen runtime/CLI JSON.
- Projection only: no evaluation, no classification, no inference.
- Reason v1 is passed through as-is.
- JSON and HTML are two projections of the same resource.
Fixture path: examples/hypermedia_show/.
v2 では resource を first-class な契約として追加し、JSON / HTML / MX の各投影を resource v2 から決定的に生成します。
v1 の resource / runtime / Reason 契約は保持され、新しい surface として併存します。
GET /v2/resource?state=...&format=v2-json|v2-html|v2-mxv2-json: resource v2 JSON(input schema / payload state / field errors を含む)v2-html: tmpx による決定的 HTMLv2-mx: mhx 向け mx-* 属性付き HTML
POST /v2/resource/validate- payload を検証し、エラー時は Reason v1 を返却
- 成功時は resource v2 HTML(Execute CTA を含む)を返却
examples/resource_v2/expected.jsonexamples/resource_v2/expected.htmlexamples/resource_v2/expected_mx.html
- no-inference:投影層は推測しない
- deterministic:順序・構造は fixture で固定
- v1 untouched:既存の v1 契約は変更しない
v2.1 は entity の保存・履歴・実行を 新しい surface として提供します。
POST /v2.1/entities(create)GET /v2.1/entities/:id(get)GET /v2.1/entities/:id/history(history JSON)GET /v2.1/entities/:id/history?format=v2_1_html(history HTML, swap target:.fwd-history)POST /v2.1/entities/:id/execute(execute-and-persist)
examples/api_v2_1/examples/api_v2_1/history_html/expected.html
Generate a deterministic effects plan (no I/O). This is a planning-only surface: it lists what effects would be executed for a transition, without executing them.
fwdc effects plan <schema.yaml> --entity <id> --state <state> --transition <id> --input <json>
Fixtures (contract locks):
examples/effects_v2_2/cli_planned/expected.jsonexamples/effects_v2_2/cli_skipped/expected.json
Execute an effects plan using the deterministic stub runner (no external I/O). This surface consumes a plan JSON and emits a fixture-locked execution result.
fwdc effects execute --plan <plan.json>
Fixtures (contract locks):
examples/effects_v2_2/execute/expected_executed.jsonexamples/effects_v2_2/execute/expected_skipped.json
v2.2 exposes effects planning and execution over a pure HTTP adapter surface.
POST /v2.2/effects/plan→ EffectsPlan JSON (same shape asfwdc effects plan)POST /v2.2/effects/execute→ EffectsExecutionResult JSON (same shape asfwdc effects execute)
Contract locks:
examples/api_v2_2/effects_plan/expected.jsonexamples/api_v2_2/effects_execute/expected.json
Notes:
- Execution uses an adapter boundary; the HTTP runner enforces an allowlist and sends an idempotency header.
v2.2 includes a deterministic replay harness for HTTP effects execution. Tests use a cassette-driven transport to avoid real network calls.
Fixtures (contract locks):
examples/effects_v2_2/record_replay/cassette_example.jsonexamples/effects_v2_2/record_replay/expected_executed.json
Replay is used by injecting the cassette transport into the HTTP runner’s transport boundary.
Record HTTP effect execution into a cassette file (developer workflow). The command requires an allowlist prefix and writes a deterministic cassette JSON.
fwdc effects record --plan <plan.json> --cassette <cassette.json> --allow https://api.example.com/
Optional:
--out <execution.json>writes the execution result to a file (the result is also printed to stdout).
Contract locks:
examples/effects_v2_2/record_cli/expected_cassette.jsonexamples/effects_v2_2/record_cli/expected_execution.json
fwdc effects run --plan <plan.json> --config <config.json>
Optional:
--cassette <cassette.json>: replay recorded HTTP interactions.
Config example (v2.2):
{
"allowlist": ["https://api.example.com/"],
"timeoutMs": 5000
}
Contract locks:
examples/effects_v2_2/real_runner/config.jsonexamples/effects_v2_2/real_runner/expected_execution.json
v3 introduces hardened execution surfaces (policy, effects hardening, unified timeline) as new immutable contracts.
See IMPLEMENTATION_PLAN.md → “v3 Implementation Plan” and “Frozen Contracts (v3)”.
Fixtures live under examples/api_v3/.
v3.1 adds a detailed executor surface for effects execution.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.1)”.
Fixtures live under examples/api_v3_1/.
v3.2 exposes timeline HTML as a standalone surface.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.2)”.
Fixtures live under examples/api_v3_2/.
v3.3 adds filter and paging controls for the timeline UI.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.3)”.
Fixtures live under examples/api_v3_3/.
v3.4 adds a timeline event detail partial (/v3.4/timeline/event/:id).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.4)”.
Fixtures live under examples/api_v3_4/.
v3.4 adds an mx-enabled timeline view that swaps event detail partials.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.4)”.
Fixtures live under examples/v3_4/timeline_mx/.
v3.5 adds /v3.5/timeline/export.jsonl (deterministic export).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.5)”.
Fixtures live under examples/api_v3_5/.
v3.6 adds /v3.6/metrics (deterministic metrics snapshot).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.6)”.
Fixtures live under examples/api_v3_6/.
v3.7 adds /v3.7/metrics/export.jsonl (deterministic metrics export).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.7)”.
Fixtures live under examples/api_v3_7/.
v3.8 adds /v3.8/timeline/events (filtered event list HTML).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.8)”.
Fixtures live under examples/api_v3_8/.
v3.9 adds /v3.9/timeline/event/:id with prev/next paging.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v3.9)”.
Fixtures live under examples/api_v3_9/.
v4 defines a canonical JSON surface (draft fixtures).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4)”.
Fixtures live under examples/v4/canonical/.
v4 HTML/MX projections are fixture-locked.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4)”.
Fixtures live under examples/v4/html/.
v4 adds read-only HTTP endpoints under /v4/* (resource + timeline list/detail).
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4)”.
Fixtures live under examples/api_v4/.
v4.2 adds a read-only metrics HTML/MX surface under /v4.2/metrics.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.2)”.
Fixtures live under examples/api_v4_2/.
v4.3 adds read-only metrics export endpoints for JSONL and CSV.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.3)”.
Fixtures live under examples/api_v4_3/.
v4.4 adds drilldown partials for metrics by kind under /v4.4/metrics/kind/:kind.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.4)”.
Fixtures live under examples/api_v4_4/.
v4.5 adds time-range metrics export and cursor-based timeline export under /v4.5/*.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.5)”.
Fixtures live under examples/api_v4_5/.
v4.6 adds async-style export jobs under /v4.6/* with job status + download URLs.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.6)”.
Fixtures live under examples/api_v4_6/.
v4.7 adds progress, cancel, and retention semantics for export jobs under /v4.7/*.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.7)”.
Fixtures live under examples/api_v4_7/.
v4.7 adds progress, cancel, and retention semantics for export jobs under /v4.7/*.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.7)”.
Fixtures live under examples/api_v4_7/.
v4.6 adds async-style export jobs under /v4.6/* with job status + download URLs.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.6)”.
Fixtures live under examples/api_v4_6/.
v4.5 adds time-range metrics export and cursor-based timeline export under /v4.5/*.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts (v4.5)”.
Fixtures live under examples/api_v4_5/.
M8 adds a minimal browser harness to verify that mx-enabled HTML is interpreted by mhx
and that clicking an mx control triggers a network request.
moon build ui/client/main --target js
Serve src/ui/client/main/index.html via any static server (a file:// URL will not work because the
script path must resolve).
Example:
# from repo root
python3 -m http.server 8000
Then open:
http://localhost:8000/src/ui/client/main/index.html
- The page loads
_build/js/.../main.js. main.jscalls@client.init_mhx_client().- Clicking the mx-enabled button/link triggers a request to the deterministic endpoint pattern:
/hypermedia/transition/<id>
- The rendered HTML uses:
mx-target=".fwd-resource"mx-swap="outerHTML"
- This harness is a smoke test only; it proves client wiring and request triggering.
- Server-side endpoints can be stubbed; the harness is valid as long as the network request fires.
All validation, baseline, and runtime failures must be normalized to the same Reason shape. This is the cross-cutting, machine-readable vocabulary for v1.
reasonVersion: fixed to1code: stable identifier (SCREAMING_SNAKE)level:error | warn | infotarget:schema | state | transition | rule | effect | baseline | runtimemessage: human explanation (non-localized)hint(optional): fix guidance
src/schema/reason.schema.v1.json
{
"reasonVersion": 1,
"code": "STATE_NOT_FOUND",
"level": "error",
"target": "transition",
"message": "Transition refers to an undefined state",
"hint": "Define the state or fix the transition.from value"
}
This project follows a strict contract-freeze discipline. All stable JSON/HTML/CLI surfaces are locked by fixtures and tests.
See IMPLEMENTATION_PLAN.md → “Frozen Contracts” for the full index.
These preset rule names are reserved and provided by the compiler resolve stage:
hasAtLeastOneStatehasAtLeastOneTransitionallReferencesResolvednoBreakingChangesnoBreakingChangesOrMigrationDefined
Notes:
- Preset rules can be referenced in
transitions.rulesby name. - A schema-defined rule cannot reuse a builtin name; the resolve stage will fail.
- Reserved-name conflicts are reported as
RESERVED_WORD_CONFLICT. - Schema-defined rules are allowed and live in
rules:.
Breaking changes must return a stable Reason.code and are machine-detectable
via baseline diff.
- State removed ->
STATE_REMOVED - Transition removed ->
TRANSITION_REMOVED - Transition modified ->
TRANSITION_MODIFIED - Schema version incompatible ->
SCHEMA_VERSION_INCOMPATIBLE
Old:
states:
- Draft
- Released
New:
states:
- Draft
Reason:
{
"reasonVersion": 1,
"code": "STATE_REMOVED",
"level": "error",
"target": "state",
"message": "State 'Released' was removed",
"hint": "Add a migration or restore the state"
}
{
"reasonVersion": 1,
"code": "TRANSITION_REMOVED",
"level": "error",
"target": "transition",
"message": "transition removed",
"hint": "Transition removed; re-add transition or define migration mapping"
}
{
"reasonVersion": 1,
"code": "TRANSITION_MODIFIED",
"level": "error",
"target": "transition",
"message": "transition modified",
"hint": "Transition modified; review compatibility and add migration if needed"
}
{
"reasonVersion": 1,
"code": "MIGRATION_REQUIRED",
"level": "error",
"target": "baseline",
"message": "breaking change requires migration",
"hint": "Breaking changes detected; provide migration definitions"
}
Minimal YAML (v1):
fwdVersion: "1.0"
schemaVersion: "1.0"
states:
- Draft
- Released
transitions:
- name: submit
from: Draft
to: Released
rules:
- hasAtLeastOneState