Skip to content

Feature: flowr export --json for visualization and tooling #3

@nullhack

Description

@nullhack

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:

  1. Parse the raw YAML themselves
  2. Duplicate the resolve_when_clause logic to expand named condition groups
  3. Resolve subflow references manually
  4. 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

  1. Interactive visualization — D3.js/dagre renderers like flowr-viz can consume this directly
  2. Static analysis — Dead state detection, cycle analysis, coverage metrics
  3. Documentation generation — Auto-generating workflow docs from flow definitions
  4. 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

  1. Is the proposed JSON schema the right shape, or would you prefer a different structure?
  2. Should --json be a flag on export, or a separate subcommand?
  3. Should the command accept a single file or a directory (or both)?
  4. Any preference on how params with defaults are represented?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions