Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# Flowprint

Visual service blueprint editor. Produces `.flowprint.yaml` files consumed by code-search.
Visual service blueprint editor and workflow execution engine. Produces `.flowprint.yaml` specifications that can be edited visually, validated in CI, executed via the dev runner, and used to generate Temporal workflow code.

## Monorepo Structure

```
packages/
schema/ @ruminaider/flowprint-schema (tsup -> ESM + CJS + .d.ts)
editor/ @ruminaider/flowprint-editor (Vite lib mode -> ESM + .d.ts + CSS)
cli/ flowprint (tsup -> CJS Node.js binary)
app/ flowprint-app (private) (Vite -> static site)
schema/ @ruminaider/flowprint-schema (tsup -> ESM + CJS + .d.ts)
engine/ @ruminaider/flowprint-engine (tsup -> ESM + CJS + .d.ts)
editor/ @ruminaider/flowprint-editor (Vite lib mode -> ESM + .d.ts + CSS)
cli/ flowprint (tsup -> CJS Node.js binary)
app/ flowprint-app (private) (Vite -> static site)
homepage/ @ruminaider/flowprint-homepage (private) (Vite -> static site)
```

Dependency graph: `schema` has zero dependents. `editor` and `cli` depend on `schema`. `app` depends on `editor` + `schema`. Editor and CLI are siblings -- neither depends on the other.
Dependency graph: `engine` depends on `schema`. `cli` depends on `engine` + `schema`. `editor` depends on `schema`. `app` depends on `editor` + `schema`. `homepage` is standalone. Editor and engine are siblings -- neither depends on the other.

## Commands

Expand Down Expand Up @@ -66,11 +68,11 @@ Both CLI and editor use tree-sitter WASM grammars. Pin exact versions to prevent
- Node IDs in blueprints: `snake_case` (e.g., `complete_consultation`, `evaluate_treatment`)
- npm scope: `@ruminaider`
- File extension: `*.flowprint.yaml`
- Package names: `@ruminaider/flowprint-schema`, `@ruminaider/flowprint-editor`, `flowprint` (CLI)
- Package names: `@ruminaider/flowprint-schema`, `@ruminaider/flowprint-engine`, `@ruminaider/flowprint-editor`, `flowprint` (CLI)

## Node Types

Six types: `action`, `switch`, `parallel`, `wait`, `error`, `terminal`. Edges are implicit in node definitions (`next`, `cases[].next`, `branches[]`, `join`, `error.catch`), not stored separately.
Seven types: `action`, `switch`, `parallel`, `wait`, `error`, `terminal`, `trigger`. Edges are implicit in node definitions (`next`, `cases[].next`, `branches[]`, `join`, `error.catch`, `default`, `timeout_next`), not stored separately. Trigger nodes declare how a workflow starts (`trigger_type`: `schedule`, `webhook`, `event`, `manual`) and point to the first node via `next`.

## Code Style

Expand Down
2 changes: 2 additions & 0 deletions docs/adr/002-six-typed-node-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Accepted (amended 2026-03-02 to add trigger node)

Note: The filename retains the original `002-six-typed-node-types` for URL stability. The ADR was amended to add the seventh node type (trigger).

## Date

2025-01-15
Expand Down
95 changes: 95 additions & 0 deletions docs/adr/008-design-time-specification-architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# ADR-008: Design-Time Specification Architecture

## Status

Accepted (amended by ADR-011)

## Date

2026-03-03

## Context

Business workflows — the rules governing how orders are processed, patients are routed, claims are adjudicated — are among the highest-value logic in any application. Yet this logic is routinely buried inside application source code, invisible to the people who define it and difficult to reason about for the people who maintain it.

This creates three compounding problems:

1. **Business logic is invisible.** A 200-line TypeScript function implementing an order routing workflow encodes critical business decisions, but a product manager, operations lead, or even a new developer cannot look at the source and understand the flow. The "what" and "why" of the business process are lost in implementation details — error handling, SDK calls, type conversions, retry logic. Reviewing changes to this logic in a pull request requires deep familiarity with the codebase.

2. **Design artifacts and running code are disconnected.** Teams frequently design workflows in tools like Mermaid, Lucidchart, or Notion — but these diagrams are documentation, not specifications. They cannot be validated, tested, or executed. The diagram and the code diverge within days of implementation. There is no tool that produces a visual design artifact that is also the source of truth for code generation.

3. **Runtime platforms own your logic.** Tools that do bridge visual design and execution — n8n, Camunda, AWS Step Functions, Windmill — require running your workflow on their platform. The visual representation is coupled to their runtime. If you outgrow the platform, migrate to a different execution model, or need to embed the logic in your own application, you face a rewrite. Business logic becomes a platform dependency rather than an engineering asset.

### Competitive landscape

We evaluated the existing ecosystem of workflow tools and found that no existing tool simultaneously provides:

- A **visual editor** for designing workflows
- A **human-readable, declarative artifact** (not BPMN XML, not proprietary JSON) designed for version control
- **Code generation** targeting developer-owned application code (not platform-locked execution)
- **Integrated decision tables** for business rules
- A **dev runner** for local testing without infrastructure
- **Zero vendor lock-in** — the artifact is portable, the generated code runs on standard infrastructure

| Tool | Visual editor | Readable artifact | Code generation | Decision tables | Vendor-free |
|------|--------------|-------------------|----------------|----------------|-------------|
| n8n | Yes | No (JSON export) | No | No | Yes |
| Temporal | No | N/A (code-first) | N/A | No | Yes |
| Windmill | Yes | Yes (YAML) | No | No | Yes |
| AWS Step Functions | Yes | Partial (ASL) | No | No | No |
| Camunda | Yes | No (BPMN XML) | No | Yes (DMN) | Partial |
| GoRules | Yes (rules only) | Yes (JSON) | No | Yes | Yes |

Windmill comes closest with YAML-based flow definitions and a visual editor, but its YAML is coupled to the Windmill runtime — it cannot generate portable application code. Camunda shares the philosophy of separating design from implementation and includes DMN decision tables, but its artifact format (BPMN XML) is verbose and unreadable in version control diffs, and it requires deploying the Zeebe engine. AWS Step Functions Workflow Studio produces a declarative artifact (ASL), but ASL mixes business logic with AWS infrastructure references and is locked to the AWS ecosystem.

The gap is a tool that treats workflow design as a **specification activity** — producing a portable, human-readable artifact that bridges business stakeholders and developers — and then generates code targeting the team's own infrastructure.

## Decision

We adopt a design-time specification architecture where the blueprint is a portable, declarative artifact that bridges business intent and executable code:

1. **Flowprint is an integrated design-to-execution pipeline.** The YAML artifact flows through every stage — visual editing, validation, simulation, execution — and each stage adds value without modifying the artifact's canonical form. No single stage is the product; the seamless chain from design through execution is. *(Planned per ADR-011: the pipeline now includes direct runtime execution via an embedded engine, not just code generation.)*

2. **The specification is runtime-agnostic.** Blueprints and rules files describe business logic without encoding runtime-specific semantics. The embedded execution engine loads blueprints at runtime and orchestrates them directly. Durability adapters (Temporal, plain in-process) are pluggable — the blueprint does not change based on the execution target. Code generation to Temporal is retained as an optional eject path. Runtime-specific metadata (timeouts, retry policies, task queues) lives in namespaced sections that adapters consume and other tools ignore. *(Planned per ADR-011: the primary developer experience shifts from code generation to engine execution.)*

3. **Business stakeholders own flow logic; developers own execution.** The visual editor and decision table editor are designed so that business analysts, operations leads, and service managers can define processes, routing rules, and SOPs without developer involvement. Developers register handler functions for side-effect nodes (API calls, database writes) and choose a durability adapter. Neither audience depends on the other for their core work, but both collaborate on the same artifact — the engine is the bridge.

4. **Keep the schema lean; push complexity into tooling.** The YAML specification stays flat, declarative, and readable in a pull request diff. Sophistication belongs in the editor (visual abstractions, simulation), the engine (expression evaluation, rule interpretation), and the code generators (idiomatic output) — not in the file format. A business stakeholder should be able to read a `.flowprint.yaml` and understand the flow without technical context.

5. **Git is the system of record.** Blueprints and rules are plain files designed for version control — deterministic serialization produces clean diffs, separate `.rules.yaml` files enable independent changesets, and the canonical serializer enforces consistent formatting. There is no database, no server state, and no proprietary storage format. If it's not in the repository, it doesn't exist.

## Consequences

### Positive

- Business workflows are visible and reviewable. A product manager can look at a `.flowprint.yaml` file (or its visual rendering) and understand the flow without reading application code. Pull requests that change business logic show readable YAML diffs, not opaque code changes.

- The blueprint is a shared language between roles. Developers, architects, and business stakeholders collaborate on the same artifact. The visual editor makes it accessible; the YAML makes it precise; the schema makes it validatable.

- Teams own their code and their infrastructure. Generated code is standard TypeScript that lives in the team's repository and runs on their infrastructure. There is no runtime dependency on Flowprint itself — if the team stops using Flowprint tomorrow, their generated code continues to work unchanged.

- Code generation targets are extensible. Because the blueprint is a declarative specification (not an execution format), new code generation targets can be added without changing the blueprint format. A team could generate Temporal workflows today and Inngest functions tomorrow from the same `.flowprint.yaml`.

- Decision tables bring business rules into the specification. Rules that would otherwise be buried in conditional logic are expressed declaratively in `.rules.yaml` files, linked to workflow nodes, and evaluated during both simulation and code generation. Business stakeholders can read and validate these rules directly.

- The dev runner and browser simulator provide fast feedback. Teams can test workflow logic locally in milliseconds without deploying infrastructure, reducing the iteration cycle from "deploy and observe" to "edit and simulate."

### Negative

- ~~Flowprint is not a runtime. Teams must still choose, deploy, and operate an execution engine (Temporal, or a future supported target). Flowprint reduces the cost of writing the workflow code but does not eliminate the operational complexity of running it.~~ *(Planned per ADR-011: Flowprint is now an embeddable execution engine. Teams embed the engine directly; Temporal is an optional durability adapter.)*

- ~~The "design then generate" model introduces a synchronization gap. After initial generation, changes to the blueprint require regenerating code and manually merging with any hand-written modifications. There is no incremental update mechanism.~~ *(Planned per ADR-011: the engine loads blueprints at runtime, eliminating the generate-then-own synchronization gap.)*

- ~~The target audience sits at an intersection that may be narrow. Teams comfortable with Temporal tend to be code-first and may not see value in a visual design layer. Teams wanting visual workflow design tend to expect an integrated runtime. Flowprint must convince both groups that the specification-first model is worth the extra step.~~ *(Planned per ADR-011: Flowprint now provides both the visual design layer AND an integrated runtime, addressing both audience expectations.)*

- ~~Supporting multiple code generation targets adds maintenance burden. Each target requires its own generator, its own test suite, and its own documentation. The blueprint format must remain general enough to map to different execution models without becoming lowest-common-denominator.~~ *(Planned per ADR-011: the engine executes blueprints directly. Durability adapters are thin wrappers around the same engine, not full parallel code generators.)*

- The visual editor is a significant engineering investment. Building and maintaining a production-quality React-based workflow editor is a substantial ongoing commitment, independent of the specification and code generation work.

## Amendments

- **ADR-011** (2026-03-08, status: Proposed): Flowprint transitions from a
specification compiler to an embeddable execution engine with GoRules ZEN.
The amendments below reflect the intended future state once ADR-011 is
implemented. See ADR-011 for the full rationale and current implementation
status.
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ We follow the [Nygard ADR template](https://cognitect.com/blog/2011/11/15/docume
| [008](008-design-time-specification-architecture.md) | Design-Time Specification Architecture | Accepted | 2025-12-01 |
| [009](009-decision-tables-and-rules-engine.md) | Decision Tables and Rules Engine | Accepted | 2026-03-02 |
| [010](010-browser-safe-simulation-engine.md) | Browser-Safe Simulation Engine | Accepted | 2026-03-02 |
| [011](011-execution-engine-with-embedded-gorules.md) | Execution Engine with Embedded GoRules | Proposed | 2026-03-08 |
97 changes: 80 additions & 17 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Flowprint CLI Reference

The `flowprint` CLI validates, lints, diffs, and scaffolds `.flowprint.yaml` service blueprints.
The `flowprint` CLI validates, lints, diffs, runs, generates, tests, and scaffolds `.flowprint.yaml` service blueprints.

## Installation

Expand Down Expand Up @@ -108,22 +108,6 @@ Reports:
| ---- | ------------------------------ |
| 0 | Always (informational command) |

### `flowprint migrate`

Migrate `.flowprint.yaml` files to the latest schema version.

```sh
flowprint migrate
```

Currently a placeholder that reports the latest version.

**Exit codes:**

| Code | Meaning |
| ---- | ------------------------- |
| 0 | Already at latest version |

### `flowprint init [name]`

Create a starter `.flowprint.yaml` blueprint with interactive prompts.
Expand Down Expand Up @@ -156,6 +140,85 @@ Uses `serialize()` from `@ruminaider/flowprint-schema` to produce canonical YAML
| 0 | Blueprint created successfully |
| 2 | File already exists |

### `flowprint run <file>`

Execute a blueprint using the dev runner. Validates schema and expressions first, then walks the graph — evaluating switch conditions via sandboxed expressions, running parallel branches concurrently, and loading entry point functions via dynamic import. Produces an execution trace showing the path taken and output at each step.

```sh
flowprint run my-service.flowprint.yaml
flowprint run my-service.flowprint.yaml --input '{"customer": "test"}'
flowprint run my-service.flowprint.yaml --fixtures fixtures.json --json
```

**Options:**

| Option | Description |
| --------------------------- | -------------------------------------------------- |
| `--input <json>` | Workflow input as JSON string (default: `"{}"`) |
| `--fixtures <path>` | Path to JSON fixtures file for wait nodes |
| `--json` | Output structured JSON trace |
| `--expression-timeout <ms>` | Expression evaluation timeout in ms (default: `1000`) |

**Engine functions used:** `runGraph()`, `validateExpressions()`, `loadFixtures()`, `formatTrace()`

Comment on lines +162 to +163

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runGraph calls findRoots but then unconditionally seeds the walk with roots[0] (packages/engine/src/runner/walker.ts), so documents with multiple trigger roots only execute the first trigger and other trigger-driven subgraphs are ignored. Can we iterate over all roots when seeding the walk in walker.ts, or alternatively reject multi-root documents at validation time, and update yaml-format-reference.md to reflect the chosen runtime behavior?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents:

In packages/engine/src/runner/walker.ts around the code that seeds the walk from
findRoots (the logic used by runGraph, referenced in docs at docs/cli-reference.md lines
162-163), the implementation currently seeds only roots[0] and ignores additional
trigger roots. Fix this by changing the seeding logic to iterate over all found roots
and enqueue/seed each root so every trigger-type root is executed; add unit tests that
exercise a blueprint with multiple trigger nodes to verify all trigger branches run.
Alternatively, if the intended runtime behavior is to forbid multiple triggers, instead
add a validation check in the engine’s schema/validation (and update
yaml-format-reference.md and docs/cli-reference.md) to reject multi-root documents with
a clear error. Update documentation to match the chosen behavior and add tests for the
new validation or multi-root execution behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid observation about the walker seeding only roots[0] — this is existing engine behavior, not introduced by this PR. The docs accurately describe what runGraph does today.

Worth tracking as a future engine task: either iterate all roots when seeding the walk, or add a structural validation rule rejecting multi-root documents.

No doc change needed — the documentation correctly reflects current behavior.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks for clarifying that this reflects existing engine behavior and not a change in this PR—I'll remember this nuance about runGraph and potential future engine tasks once the PR is merged.

**Exit codes:**

| Code | Meaning |
| ---- | ----------------------------- |
| 0 | Success |
| 1 | Execution failure |
| 2 | File not found or parse error |

### `flowprint generate <file>`

Generate Temporal TypeScript workflow code from a blueprint. Creates workflow definitions, activity stubs, worker configuration, type definitions, and test fixture files in the output directory.

```sh
flowprint generate my-service.flowprint.yaml
flowprint generate my-service.flowprint.yaml --output ./src/workflows
```

**Options:**

| Option | Description |
| ---------------- | --------------------------------------- |
| `--output <dir>` | Output directory (default: `./generated`) |

**Engine functions used:** `generateCode()`

**Exit codes:**

| Code | Meaning |
| ---- | ----------------------------- |
| 0 | Success |
| 1 | Validation errors |
| 2 | File not found or parse error |

### `flowprint test [glob]`

Run decision table test files against their corresponding rules. Auto-derives `.rules.yaml` from `.rules.test.yaml` filenames (e.g., `pricing.rules.test.yaml` tests `pricing.rules.yaml`).

```sh
flowprint test
flowprint test "src/**/*.rules.test.yaml"
```

**Arguments:**

| Argument | Description |
| -------- | ------------------------------------------------------- |
| `[glob]` | Glob pattern for test files (default: `**/*.rules.test.yaml`) |

**Engine functions used:** `runRulesTests()`

**Exit codes:**

| Code | Meaning |
| ---- | ----------------------------- |
| 0 | All tests passed |
| 1 | Test failures |
| 2 | File not found or parse error |

## Global Exit Codes

| Code | Meaning |
Expand Down
Loading
Loading