This project is an npm workspace monorepo for building, running, and reviewing agentic workflows.
apps/server: Express API server and Vite middleware integration.apps/web: Vite SPA workflow editor and run console.packages/types: Shared TypeScript contracts used by server, web, and engine.packages/workflow-engine: Pure workflow runtime with pluggable LLM adapter.design-system/: Git submodule for UI tokens and components.data/runs/: Persisted run records (run_<runId>.json)..config/config.json: Provider/model config served by API..config/default-workflow.json: Optional startup workflow (gitignored).
- Web app calls
POST /api/run-stream. - Server creates a
WorkflowEngine, attachesonLog, and streams SSE events. - Engine emits
WorkflowLogEntryevents as nodes execute. - Server persists final result to
data/runs/run_<runId>.json. - Server sends a final
doneevent and closes the stream.
- Web app calls
POST /api/resume-streamwithrunIdand approval input. - Server resumes an in-memory paused engine.
- Server streams log events and final result.
- Server persists updated run record.
A per-run resume lock prevents concurrent resume calls (409 if duplicated).
POST /api/run: same execution model as stream, returned as one JSON response.POST /api/resume: same resume model as stream, returned as one JSON response.
The workflow engine supports:
- Node types:
start,agent,if,approval. - Branching with condition handles (
condition-<index>) and fallback (false). - Approval pause/resume semantics with
waitingForInputandcurrentNodeId. - Subagent tool-delegation edges (
sourceHandle: "subagent") separate from execution edges. - Deferred downstream execution queues when a pause occurs mid-branch.
Subagent links are validated as a strict DAG of agent-to-agent tool relationships:
- Source must be an
agentwithtools.subagents = true. - Target must be an
agentconnected on input handle. - Target cannot be part of normal execution edges.
- A target can have only one subagent parent.
- Cycles are rejected.
During agent execution, subagent calls are logged as runtime events:
subagent_call_startsubagent_call_endsubagent_call_error
At startup, server scans data/runs/ and rehydrates paused runs into memory when all are true:
status === "paused"waitingForInput === truestateexistscurrentNodeIdis not null
This enables resume endpoints to keep working after restart.
The web editor:
- Persists canvas graph in localStorage key
agentflow-workflow. - Persists active run ID in localStorage key
agentflow-run-id. - On load, restores graph from localStorage first, then falls back to
/api/default-workflow. - On load, attempts run recovery via
GET /api/run/:runId. - Polls every 2s while recovered run status is
running.
Build/type dependencies flow from shared packages to apps:
packages/typespackages/workflow-engineapps/serverandapps/web
Use npm run build:packages before server/app typecheck or build when running targeted commands.