RISE Framework Specification References: Spec 70 (SMDF), Spec 73 (MCP Server), Spec 74 (Web Designer), Spec 75 (Bridge) Origin: Issue #10 / PR #11 (2026-04-16) — “get to the end where we shall have something we can actually try” Implementation:
mcp/src/server.ts(generate_rispectool),web/src/app/api/rispec/route.ts(HTTP mirror),web/src/components/Toolbar.tsx(📜 RISE button)
Spec ID: 76 Version: 1.1 Status: implemented (minimum-viable generator; PDE enrichment wired) Revised: 2026-09-20 (v1.1) — env name and the ERD’s absence from the generator stated; the rest holds as written
What This Enables Users to Create:
A two-way loop between design (SMDF state machine) and specification (RISE rispec). An agent — or a human at the canvas — can emit a RISE framework rispec directly from the current state machine, closing the Miaco chain (PDE → STC → SMDF → codegen) with a proper E (Exportation) step that is neither source code nor raw JSON.
Desired Outcome:
Any SMDF on disk can be rendered, in one step, as a RISE rispec markdown document containing the four sections — Reverse Engineering, Intent, Specifications, Exportation — with full traceability back to the originating PDE (when one is linked via settings._source).
.pde/<ts>--<uuid>/pde-<uuid>.json) hold the originating prompt, the Four Directions decomposition, action stack, and ambiguities — but they live next to the SMDF, not inside it.Given:
def: a SMDF Definition (possibly with settings._source = { pdeId, pdeFolder, originalPrompt })pde: an optional PdeSource loaded via settings._source.pdeFolder + pdeIdintent: an optional string override supplied by the callerprojectFile: absolute path of the SMDF on disk (for the Exportation section)Produce a markdown document with this structure:
# {name} — RISE rispec
> {tagline: intent ?? pde.primary.target ?? _source.originalPrompt ?? "{name} state machine"}
**Namespace:** `{namespace}` · **Async:** {asynchronous}
**Source PDE:** `{pdeId}` ← only when _source.pdeId is present
---
## R — Reverse Engineering
{count summary: N non-root states across M level(s), Events: E, Transitions: T}
Originating prompt: ← only when pde.prompt is present
> {pde.prompt}
## I — Intent
**Desired Outcome**
{intent ?? pde.primary.target ?? "_(no intent supplied)_"}
**Vision (🌅 East)** ← only when pde.directions.east has entries
- {each east direction.text}
**Structural Tension**
- *Current:* {name} {has-final-state → "terminal state reachable" / else "no terminal state declared"}
- *Desired:* {intent ?? pde.primary.target ?? "{name} runs end-to-end..."}
## S — Specifications
### States
{recursive tree render: indent per depth, mark kind when != "normal", list transitions inline}
### Events
{grouped by source: sourceName → bullet list of `{id}` — {description}}
### Transitions (flat)
{one line per transition: `from` --[event]-- → next (or "internal") *(when: condition)*}
### Action Steps ← only when any East/South/West/North child exists
{for each direction in [South, East, North, West]:
{glyph} {direction} — {description}
1. {each child's description ?? name}
}
### Open Questions ← only when pde.ambiguities has entries
- {each ambiguity.text}
→ *{suggestion}*
## E — Exportation
- Code: smcg / `generate_code` mcp tool (python | typescript)
- Visual: this file is bound to `{projectFile}` via SMCRAFT_PROJECT_FILE
- SMDF: the canonical JSON is the file above
Definition.settings._source (optional) carries:
{
pdeId?: string // UUID of the PDE artefact
pdeFolder?: string // path to the PDE folder (absolute or relative to SMDF)
originalPrompt?: string // fallback tagline when no PDE is loadable
}
loadPde(smdfPath, def) tries, in order:
resolve(dirname(smdfPath), pdeFolder, "pde-{pdeId}.json")resolve(pdeFolder, "pde-{pdeId}.json")and returns null on any failure — the generator degrades gracefully to a PDE-less rispec.
| Surface | Entry point | Input | Output |
|---|---|---|---|
| MCP tool | generate_rispec in mcp/src/server.ts |
{ intent?: string } |
content: [{ type: "text", text: markdown }] |
| HTTP API | POST /api/rispec in web/src/app/api/rispec/route.ts |
{ intent?: string } body |
{ rispec: string, projectFile: string } |
| Web UI | 📜 RISE button in Toolbar.tsx |
— | Code preview panel shows rendered markdown |
All three paths resolve the same file via STATELOOM_PROJECT_FILE (legacy twin SMCRAFT_PROJECT_FILE) and produce byte-identical output for the same inputs.
Machines only. generate_rispec narrates a .smdf.json. An ERD (.erdf.json, Spec 80) has no rispec generator — the data document is not yet re-narratable, and an agent holding an active ERD should switch documents before asking for one.
| # | Current Reality | Desired Outcome | Resolution |
|---|---|---|---|
| 1 | SMDF → code is the only emission; PDE → SMDF has no “back to narrative” step | Any SMDF can be re-narrated as a RISE rispec at any time | generate_rispec reads current SMDF + optional linked PDE, renders markdown |
| 2 | PDE artefacts live beside SMDF but aren’t woven into specs | Vision, ambiguities, and directions appear in the rispec when a PDE is linked | settings._source.{pdeId,pdeFolder} + loadPde() graceful degradation |
| 3 | Agent has no “Exportation” tool that isn’t code | Agent emits RISE rispec as the final artefact of a design session | MCP generate_rispec tool with optional intent override |
| 4 | Designer canvas can only export code or JSON | User clicks one button, sees a RISE rispec | 📜 RISE button → POST /api/rispec → code preview panel |
intent to scope which states/transitions are rendered (e.g. “focus on the fire-keeper path”).generate_rispec that reads a .erdf.json — the entities, their keys and the machines their stateOf attributes name — so the data half of a design can also leave as prose.settings._source references a ceremony (future field), pull the ceremony’s opening/closing into the Exportation section.generate_rispec toolmcp-pde: The PDE artefacts this generator weaves into the Intent section