Open Source · Python · draw.io

Turn diagrams into executable workflows. No process code required.

The draw.io Workflow Engine reads your business process diagrams and executes them as fully stateful, persistent workflows — runnable from the command line or as a containerised REST API.

Sample shipment workflow built in draw.io and executed by the engine
Sample shipment workflow — built in draw.io, executed by the engine
9
Supported node types
1
Python file to deploy
6
REST API endpoints
Workflow complexity

Everything you need to automate business processes

Designed for teams who want workflow automation without the complexity of enterprise BPM suites. Build visually, deploy instantly.

Draw, don't code

Use draw.io's standard flowchart shapes. The engine reads your diagram and executes it directly. Node behaviour is configured through draw.io's custom properties panel — no separate config files needed.

Deploy anywhere

Runs as a Python CLI tool on your laptop, as a containerised HTTP server on Kubernetes, or on serverless platforms like IBM Code Engine. One file. Zero infrastructure dependencies by default.

Persistent state

Every step is saved after every node. Workflows survive server restarts, manual interventions, and API timeouts. State is stored locally or in IBM Cloudant for multi-replica deployments.

Production ready

Parallel branch execution, nested sub-workflows, REST call integration, manual input gates, scheduled delays, Basic Auth, IBM COS model storage, and a full metrics endpoint — all built in.

From diagram to running workflow in five steps

Draw your process

Open draw.io and create a flowchart using the supported subset of flowchart shapes: Start, End, Process, Decision, Extract, Merge, Manual Input, Delay, and Predefined Process.

Configure nodes

Right-click any shape → Edit Data. Add key-value properties to control behaviour: set context values, configure REST calls (type: rest), or define routing conditions on connectors.

Save the model

Save your diagram as a .drawio file. Place it in the same directory as main.py, or configure IBM COS as the model backend.

Run the engine

Execute from the command line: python main.py mymodel. Or start an HTTP server: python main.py --server.

Observe & resume

The engine persists state after every node and prints a full execution summary. Paused workflows can be resumed with another run using the same instance ID.

Nine node types covering every workflow pattern

The engine supports a carefully chosen subset of draw.io's flowchart shapes. Each node type maps to a specific execution behaviour.

mxgraph.flowchart.start_1 / start_2
Start

Entry point of the workflow. Can carry default context values as custom properties. If context is passed by a parent workflow, start node values act as defaults only — they never overwrite inherited context.

mxgraph.flowchart.terminator
End

Terminal node. When reached, the workflow is marked completed. Its final context contains all key-value pairs accumulated across every executed node.

Shape: label (rounded rectangle)
Process

The workhorse node. Merges fixed key-value pairs into the workflow context, or calls an external REST API (type: rest) and optionally waits for the response in blocking or scheduled mode.

Shape: process (double-bar rectangle)
Predefined Process

Invokes another .drawio model as an independent sub-workflow. The parent passes its current context to the child and waits for completion before continuing.

mxgraph.flowchart.decision
Decision

Routes execution based on a context variable. Each outgoing connector carries a label matching an expected context value. If no connector matches, execution stops with an error. Supports wildcard routing.

mxgraph.flowchart.extract_or_measurement
Extract

Splits a single flow into parallel branches. By default, branches run as concurrent threads within the same request. When ENGINE_URL is set, each branch is dispatched as an independent HTTP child request.

mxgraph.flowchart.merge_or_storage
Merge

Rejoins parallel branches. Execution waits until all sibling branches have completed. Context from all branches is merged before the flow continues to subsequent nodes.

Shape: manualinput
Manual Input

Pauses the workflow and waits for an external action. The engine writes a manual_input_*.json file. When its status is set to completed and values added to input_data, the next run resumes from this point.

mxgraph.flowchart.delay
Delay

Pauses execution for a configured duration (delay: 30s / 5m / 2h / 1d). In blocking mode the request is held open; in scheduled mode the engine returns immediately and awaits an external resume call.

Three ways to run the engine

# Install dependencies pip install -r requirements.txt # Run a workflow (completes immediately) python3 main.py payment --context '{"amount_exceeds":"no"}' # Run a workflow that pauses at manual input python3 main.py payment --context '{"amount_exceeds":"yes"}' # → creates manual_input_<id>.json — fill it in, then: # Resume a paused instance python3 main.py payment --id <instance_id> # Pass initial context python3 main.py mymodel --context '{"key":"value"}' # Simulate manual inputs automatically (for testing) python3 main.py mymodel --simulate-manual-input

Zero infrastructure

The CLI mode is the fastest path to running a workflow. It reads the .drawio model from the current directory, executes it, prints a full summary, and exits.

State is persisted to process_state_<id>.json files locally. On a pause, run again with --id to resume.

  • No server required
  • Full execution summary printed to stdout
  • Structured JSON logging
  • WAIT STATES shows child instance IDs directly
# Start the HTTP server on port 8080 python3 main.py --server # Start a workflow curl -X POST http://127.0.0.1:8080/workflows/start \ -H "Content-Type: application/json" \ -d '{"model":"payment","context":{"amount_exceeds":"no"}}' # 200 = completed, 201 = paused/waiting {"instance_id":"abc123...","status":"completed"} # Resume a paused instance curl -X POST http://127.0.0.1:8080/workflows/start \ -H "Content-Type: application/json" \ -d '{"model":"payment","instance_id":"abc123...","context":{}}' # Read full state curl http://127.0.0.1:8080/workflows/abc123...?model=payment

REST API mode

In server mode the engine exposes a small REST API. Any system that can make HTTP requests can start, resume, and monitor workflows.

HTTP 200 → completed this call. HTTP 201 → paused (manual input, delay, or parallel wait).

  • 6 REST endpoints
  • Optional Basic Auth
  • CORS enabled (flask-cors)
  • Gunicorn WSGI for production
# Build the container image podman build -t workflow-engine -f Containerfile . # Run on port 8080 podman run -p 8080:8080 workflow-engine # Mount CREDENTIALS.txt at runtime podman run -p 8080:8080 \ -v "$(pwd)/CREDENTIALS.txt:/app/CREDENTIALS.txt:Z" \ workflow-engine # Pass credentials as environment variables podman run -p 8080:8080 \ -e API_USERNAME=admin \ -e API_PASSWORD=changeme \ -e MODEL_BACKEND=cos \ -e COS_APIKEY=... \ -e COS_BUCKET=my-bucket \ -e ENGINE_URL=https://my-engine.example.com \ workflow-engine

Container deployment

The included Containerfile produces a minimal Python 3.11 container image. Deploy on any container platform: Kubernetes, OpenShift, IBM Code Engine, or local Podman.

All settings in CREDENTIALS.txt can be overridden by environment variables — the recommended approach for containers.

  • Podman & Docker compatible
  • Works on IBM Code Engine
  • Kubernetes + OpenShift ready
  • ENV vars take priority over CREDENTIALS.txt

Six endpoints, one primary entry point

All endpoints except GET /health require Basic Auth credentials when enabled in CREDENTIALS.txt. Add -u username:password to any curl command when auth is on.

MethodPathAuthDescription
POST/workflows/startRequiredStart or resume a workflow. Body: {"model":"name","instance_id":"opt","context":{}}. Returns 200 (completed) or 201 (paused/waiting).
POST/workflows/<id>/continueRequiredExplicitly advance a paused instance. Intended for form submissions and manual approvals.
POST/workflows/<id>/callbackRequiredDeliver an asynchronous event to a waiting instance. Used internally for parallel branch coordination.
GET/workflows/<id>?model=<name>RequiredRetrieve full persisted state: context, history, wait states, and status. The model query parameter is required.
GET/healthOpenLiveness probe. Returns {"status":"ok","uptime_seconds":N}. Always accessible — suitable for load balancer and Kubernetes readiness probes.
GET/metricsRequiredRuntime counters: total requests, completed, waiting, errored, currently in-flight instances.
curl
# Run a workflow (no server needed)
python3 main.py <model> --context '{"key":"value"}'

# Resume a paused instance
python3 main.py <model> --id <instance_id>

# Start HTTP server (default port 8080)
python3 main.py --server

# Start server on a custom port
python3 main.py --server --port 9090

# Skip manual input gates automatically
python3 main.py <model> --simulate-manual-input

# Cap sub-workflow nesting depth
python3 main.py <model> --max-call-depth 3

# Add inter-node delay (useful for tracing)
python3 main.py <model> --process-delay-seconds 0.5

# Show all available flags
python3 main.py --help

Command-line interface

The CLI mode runs a single workflow synchronously and prints a full execution summary. No server, no database, no configuration needed beyond a .drawio model file in the same directory.

State is written to process_state_<id>.json on disk. On a pause, re-run with --id to resume from the exact point it stopped.

  • --context  JSON initial context object
  • --id  Resume a paused instance by ID
  • --server  Switch to HTTP server mode
  • --port  Server port (default: 8080)
  • --simulate-manual-input  Auto-advance manual gates
  • --max-call-depth  Subprocess nesting cap (default: 5)
  • --process-delay-seconds  Inter-node delay

All settings in one file — or via environment variables

CREDENTIALS.txt holds all runtime configuration. Every setting can be overridden by an environment variable with the same key name — recommended for containers and serverless.

Model & State Backends

Control where workflow model files and execution state are stored.

MODEL_BACKENDlocal (default) or cos — where .drawio files are loaded from
STATE_BACKENDSet in model custom properties. Use cloudant for multi-replica deployments.
COS_APIKEYIBM COS IAM API key (required when MODEL_BACKEND=cos)
COS_ENDPOINTIBM COS endpoint URL, e.g. https://s3.us-south.cloud-object-storage.appdomain.cloud
COS_BUCKETBucket name containing your .drawio model files

Authentication & Engine

Control access and parallel branch dispatch behaviour.

API_USERNAMEEnable Basic Auth — set together with API_PASSWORD
API_PASSWORDBasic Auth password. If either field is absent, all endpoints are open.
ENGINE_URLPublic base URL of the engine. When set, parallel branches are dispatched as independent HTTP child requests — required for serverless platforms with request timeouts.
PORTHTTP port for server mode. Default: 8080. Env var takes priority over --port.

Designed for low-to-medium complexity use cases

01
Parallel branches — thread mode timeout

By default, branches run as threads within a single HTTP request. On serverless platforms with short request timeouts, set ENGINE_URL to dispatch branches as independent HTTP requests instead.

02
Scheduled wait mode — no self-waking

Workflows paused at scheduled delay or manual input nodes require an external trigger to resume. Use blocking mode for time-based delays where possible; otherwise design a cron or polling mechanism.

03
File-based state — single replica only

Local file state is not compatible with multi-node deployments. Use IBM Cloudant as the state backend for clustered or multi-replica setups.

04
Basic Auth only

The engine supports HTTP Basic Authentication. More advanced schemes (OAuth, JWT, API keys) are not built in. Terminate TLS at an ingress controller or reverse proxy.

05
Configurable hard limits

Sub-model nesting depth capped at 5 levels. History entries capped at 500 per instance. Request body capped at 1 MB. All limits are adjustable via CLI flags.

06
Scheduled REST — design for idempotency

Scheduled REST Process nodes fire one-at-a-time across parallel branches. Additionally, concurrent resume requests arriving before the first response is written may call the external endpoint twice. Design REST endpoints to be idempotent as a general best practice.

Free & Open Source

Get started in minutes

The complete engine is a single Python file. Download the package, install the dependencies, place a .drawio model file next to main.py, and run.

v1.0Release
Python 3.11+Requirement
MITLicense
✓ 78 testsCLI & HTTP verified

Includes: main.py · CREDENTIALS.txt template · Containerfile · PODMAN.md · wsgi.py · requirements.txt · User Guide (PDF) · three sample .drawio workflow models (payment, shipment, review)

📦
drawio-workflow-engine.zip
Includes engine, sample workflows & User Guide PDF
↓   Download ZIP
📄
User Guide — Draw.io Workflow Engine
Complete documentation · PDF
↓   Download PDF

Extract the archive and run pip install -r requirements.txt. Refer to CREDENTIALS.txt and PODMAN.md for configuration.

Minimal dependencies, maximum flexibility

Required

  • Python 3.11 or higher
  • flask — HTTP server framework
  • flask-cors — CORS headers
  • requests — outbound REST calls from Process nodes
  • gunicorn — production WSGI server
  • A .drawio model file to execute

Optional

  • ibm-cos-sdk — load models from IBM COS
  • boto3 — S3-compatible / MinIO model storage
  • ibmcloudant — Cloudant state backend for multi-replica
  • ibm-cloud-sdk-core — IBM IAM authentication
  • Podman or Docker — container deployment
  • IBM Code Engine / Kubernetes — orchestrated deployment