Problem
flowr's current visualization is limited to mermaid text output. For complex workflows with subflows, guard conditions (when), and state attributes (attrs), a static Mermaid diagram is hard to navigate — you can't drill into subflows, see state details, or understand guard conditions at a glance.
There's no structured JSON output that external tools (visualizers, analyzers, integrations) can consume. Today, anyone building tooling around flowr must:
- Parse the raw YAML themselves
- Duplicate the
resolve_when_clause logic to expand named condition groups
- Resolve subflow references manually
- Build their own graph representation
This is error-prone and creates tight coupling to flowr's internal YAML format rather than its stable domain model.
Proposal
Add a flowr export --json CLI command that outputs all flow data as structured JSON, suitable for visualization and other tooling:
# Export a single flow
flowr export --json deploy.yaml
# Export all flows in a directory (resolves subflow references)
flowr export --json .flowr/flows/
Proposed JSON Schema
{
"schema": 1,
"defaultFlow": "main-flow",
"flows": {
"deploy": {
"flow": "deploy",
"version": "1.0.0",
"exits": ["deployed", "failed"],
"params": ["environment", "region"],
"attrs": {
"owner": "platform-team",
"slack_channel": "#deploys"
},
"nodes": [
{
"id": "prepare",
"type": "state",
"label": "Prepare",
"attrs": {
"description": "Set up the build environment",
"owner": "SE"
},
"subflow": null,
"subflowVersion": null
},
{
"id": "review",
"type": "subflow",
"label": "Review",
"attrs": { "description": "Peer review of artifacts" },
"subflow": "review-flow",
"subflowVersion": "^1"
},
{
"id": "deployed",
"type": "exit",
"label": "Deployed"
}
],
"edges": [
{
"source": "review",
"target": "deploy",
"label": "approved",
"kind": "transition",
"when": { "ci_passes": "true" }
},
{
"source": "deploy",
"target": "deployed",
"label": "done",
"kind": "exit"
}
]
}
}
}
Key design decisions
when conditions are resolved: Named refs to state-level conditions groups are expanded into flat dicts. Consumers don't need to understand the when resolution logic.
attrs are opaque: Passed through as-is. The library doesn't interpret them; neither should the export.
type differentiates node kinds: state, subflow, exit — so visualizers can style them differently.
kind differentiates edge kinds: transition (state-to-state) vs exit (to an exit point).
- Directory mode resolves subflows: When given a directory, the command loads all YAML files and resolves cross-references.
Use Cases
- Interactive visualization — D3.js/dagre renderers like flowr-viz can consume this directly
- Static analysis — Dead state detection, cycle analysis, coverage metrics
- Documentation generation — Auto-generating workflow docs from flow definitions
- CI/CD integration — Validating that flow changes don't break parent contracts
Reference Implementation
I've built a Python-based generator (generate-flowviz-data.py) that currently reads raw YAML and resolves when refs independently. It works, but duplicates logic that flowr already owns. A flowr export --json command would make this generator unnecessary — tools could consume flowr's output directly.
The generator and interactive visualizer are available at nullhack/flowr-viz as a reference implementation.
Questions
- Is the proposed JSON schema the right shape, or would you prefer a different structure?
- Should
--json be a flag on export, or a separate subcommand?
- Should the command accept a single file or a directory (or both)?
- Any preference on how
params with defaults are represented?
Problem
flowr's current visualization is limited to
mermaidtext output. For complex workflows with subflows, guard conditions (when), and state attributes (attrs), a static Mermaid diagram is hard to navigate — you can't drill into subflows, see state details, or understand guard conditions at a glance.There's no structured JSON output that external tools (visualizers, analyzers, integrations) can consume. Today, anyone building tooling around flowr must:
resolve_when_clauselogic to expand named condition groupsThis is error-prone and creates tight coupling to flowr's internal YAML format rather than its stable domain model.
Proposal
Add a
flowr export --jsonCLI command that outputs all flow data as structured JSON, suitable for visualization and other tooling:Proposed JSON Schema
{ "schema": 1, "defaultFlow": "main-flow", "flows": { "deploy": { "flow": "deploy", "version": "1.0.0", "exits": ["deployed", "failed"], "params": ["environment", "region"], "attrs": { "owner": "platform-team", "slack_channel": "#deploys" }, "nodes": [ { "id": "prepare", "type": "state", "label": "Prepare", "attrs": { "description": "Set up the build environment", "owner": "SE" }, "subflow": null, "subflowVersion": null }, { "id": "review", "type": "subflow", "label": "Review", "attrs": { "description": "Peer review of artifacts" }, "subflow": "review-flow", "subflowVersion": "^1" }, { "id": "deployed", "type": "exit", "label": "Deployed" } ], "edges": [ { "source": "review", "target": "deploy", "label": "approved", "kind": "transition", "when": { "ci_passes": "true" } }, { "source": "deploy", "target": "deployed", "label": "done", "kind": "exit" } ] } } }Key design decisions
whenconditions are resolved: Named refs to state-levelconditionsgroups are expanded into flat dicts. Consumers don't need to understand thewhenresolution logic.attrsare opaque: Passed through as-is. The library doesn't interpret them; neither should the export.typedifferentiates node kinds:state,subflow,exit— so visualizers can style them differently.kinddifferentiates edge kinds:transition(state-to-state) vsexit(to an exit point).Use Cases
Reference Implementation
I've built a Python-based generator (
generate-flowviz-data.py) that currently reads raw YAML and resolveswhenrefs independently. It works, but duplicates logic that flowr already owns. Aflowr export --jsoncommand would make this generator unnecessary — tools could consume flowr's output directly.The generator and interactive visualizer are available at nullhack/flowr-viz as a reference implementation.
Questions
--jsonbe a flag onexport, or a separate subcommand?paramswith defaults are represented?