Runs are persisted as JSON records in data/runs/.
- Pattern:
run_<runId>.json runIdis generated fromDate.now().toString().
{
"runId": "1772129193363",
"workflow": { "nodes": [], "connections": [] },
"logs": [],
"status": "completed",
"state": {},
"currentNodeId": null,
"waitingForInput": false
}Fields:
workflow: graph that actually ran.logs: ordered runtime log entries.status: current/terminal status.state: engine internal state snapshot.currentNodeId: active node when paused/running.waitingForInput: approval wait flag.
Records are saved after:
POST /api/runPOST /api/run-streamPOST /api/resumePOST /api/resume-stream
Persistence is best-effort; save failures are logged server-side.
Server keeps a map of active WorkflowEngine instances.
- Paused runs remain in memory.
- Completed/failed runs are removed from memory.
- Persisted records remain on disk.
GET /api/run/:runId lookup order:
- In-memory active run (if still running/paused).
- Persisted file from
data/runs/.
If both missing, API returns 404.
On server startup, persisted records are scanned and restored to active memory only if:
status === "paused"waitingForInput === truestateexistscurrentNodeId != null
This allows paused approval runs to survive restarts.
Web app stores active run ID in localStorage (agentflow-run-id) and on load:
- Calls
GET /api/run/:runId. - If
status === running, renders partial logs and polls every 2 seconds. - If
status === paused && waitingForInput, re-shows approval UI. - If run missing (
404), clears stored run ID.
data/runs/is gitignored and can grow quickly.- Remove stale run files periodically in local environments.
- Do not commit run data to source control.