Flowforge is a multi-tenant AI workflow engine built with NestJS, PostgreSQL, Redis, BullMQ, and LangGraph.
- Stores workflow definitions as JSON.
- Runs workflows asynchronously.
- Supports
llm,tool, andconditionnodes. - Tracks run status, retries, traces, artifacts, and webhook delivery.
- Isolates every workflow and run by tenant API key.
- Install dependencies:
npm install-
Copy
.env.exampleto.envand fill in the values you need. For Docker Compose local dev, PostgreSQL is exposed on host port55432. -
Start PostgreSQL and Redis:
docker compose up -d- Apply migrations:
npm run migration:run- For local schema bootstrapping only, if you explicitly want TypeORM to create tables automatically instead of using migrations, set:
DATABASE_SYNCHRONIZE=true- Start the API:
npm run start:dev- Open the built-in operator console:
http://localhost:3000/app
The high-level architecture diagram is available at docs/hld_workflow_engine.svg.
The repo now includes a lightweight frontend served by the Nest app at /app. It covers:
- tenant creation and API key capture
- workflow list, create, update, and delete
- raw JSON workflow editing with a Gemini sample
- run trigger, status refresh, history loading, and trace viewing
npm run build
npm test
npm run test:e2e{
"id": "wf_lead_qualify_v1",
"name": "Lead qualification workflow",
"trigger": "api",
"artifact_keys": ["score", "result"],
"webhook": {
"url": "https://example.com/workflow-events",
"include_traces": true
},
"nodes": [
{
"id": "score_lead",
"type": "llm",
"model": "gpt-4o-mini",
"prompt": "Score this lead: {{input.lead}}",
"output_key": "score"
},
{
"id": "route_lead",
"type": "condition",
"depends_on": ["score_lead"],
"branches": {
"high": { "condition": "score >= 70", "next": "notify_sales" },
"low": { "condition": "score < 70", "next": "log_low_score" }
}
},
{
"id": "notify_sales",
"type": "tool",
"tool": "webhook",
"params": {
"url": "https://example.com/sales",
"body": { "score": "{{score}}" }
},
"output_key": "result"
}
]
}POST /tenantsPOST /workflowsGET /workflowsGET /workflows/:idPUT /workflows/:idDELETE /workflows/:idPOST /workflows/:id/runGET /runs/:runIdGET /runs/:runId/tracesGET /workflows/:id/runs
All workflow and run endpoints require x-api-key.
Workflow definitions with llm nodes are validated against configured provider API keys during create/update, so unsupported model prefixes or missing provider keys fail before a run is queued.
Create a tenant:
curl -X POST http://localhost:3000/tenants \
-H "Content-Type: application/json" \
-d '{"name":"Demo Tenant","plan":"pro"}'Create a workflow:
curl -X POST http://localhost:3000/workflows \
-H "Content-Type: application/json" \
-H "x-api-key: <TENANT_API_KEY>" \
-d '{
"name":"Lead Qualification",
"status":"active",
"definition":{
"id":"wf_lead_qualify_v1",
"name":"Lead qualification workflow",
"trigger":"api",
"artifact_keys":["score"],
"nodes":[
{
"id":"score_lead",
"type":"llm",
"model":"gpt-4o-mini",
"prompt":"Score this lead: {{input.lead}}",
"output_key":"score"
}
]
}
}'Trigger a run:
curl -X POST http://localhost:3000/workflows/<WORKFLOW_ID>/run \
-H "Content-Type: application/json" \
-H "x-api-key: <TENANT_API_KEY>" \
-H "idempotency-key: demo-run-1" \
-d '{
"input":{
"lead":"ACME Corp wants a pricing quote"
}
}'Poll run status:
curl http://localhost:3000/runs/<RUN_ID> \
-H "x-api-key: <TENANT_API_KEY>"Fetch traces:
curl http://localhost:3000/runs/<RUN_ID>/traces \
-H "x-api-key: <TENANT_API_KEY>"List workflow runs:
curl "http://localhost:3000/workflows/<WORKFLOW_ID>/runs?page=1&limit=20" \
-H "x-api-key: <TENANT_API_KEY>"The Postman collection for the planned API contract is available at docs/postman_collection.json.
http_requestlogformatjson_parsejson_stringifypickmergesleepartifactwebhook
- LangGraph is used as the execution runtime.
- Condition evaluation is intentionally limited to safe comparison syntax.
- BullMQ retries failed runs and moves final failures into a dedicated DLQ queue.