eve version
eve@0.13.0 (observed); paths and behavior verified unchanged on main @ 1fd8a02 (@workflow/core 5.0.0-beta.26)
Node.js version
v26.3.1
Where does the bug occur?
Local dev (eve dev)
Description
The local workflow world persists every run, event, step, and hook as an individual JSON file under .workflow-data, and nothing ever deletes them. Combined with two scan behaviors, an always-on eve dev agent degrades steadily:
- Per-operation directory scans in the local queue.
@workflow/core's local world lists whole directories with suffix filters per queue operation (readdir + libuv scandir sort + per-filename V8 string internalization). Operation cost grows with lifetime accumulated files, not live work.
- Boot-time full-store scan in eve itself.
pruneDevelopmentRuntimeArtifactsSnapshots → collectWorkflowDataSnapshotPaths recursively readdirs and readFiles every file in .workflow-data (≤1MB each) to protect non-terminal runs' snapshots, so eve dev boot cost also grows with store size.
Observed impact
After roughly one week of an always-on agent (Discord bot + several coding agents driving it):
.workflow-data: ~10,900 files / 315 MB — 8,466 events, 1,460 steps, 500 runs, 459 hooks
- 247 of 500 runs were stuck in
running status forever — stranded by killed/restarted dev servers
- Under sustained workflow traffic the dev server held ~2.9 CPU cores; a 2s
sample of the process is dominated by __getdirentries64, qsort/strcmp (libuv scandir), and V8 InternalizeString/GC — directory enumeration churn, not agent work
- A freshly restarted server idles at 0% over the same store, then burns again as soon as workflow traffic resumes
- After pruning stale runs externally (store → 12 MB / ~400 files), the same traffic runs quietly
Reproduction
- Run
eve dev for an agent that receives steady workflow traffic for days (or synthetically populate .workflow-data with ~10k run/event/step files in the local-world file format).
- Drive concurrent workflow traffic.
sample <pid> / observe CPU: enumeration cost scales with total accumulated files.
Expected behavior
Dev-mode workflow history is bounded by a retention policy, and queue/boot cost does not scale with lifetime traffic.
Proposed direction
A boot-time background retention pass for terminal-status runs (completed / failed / cancelled), mirroring the existing pruneDevelopmentRuntimeArtifactsSnapshotsInBackground and pruneLocalSandboxTemplatesInBackground seams in startNitroDevelopmentServer: delete terminal runs older than a retention window together with their linked events, steps, hooks, and stream files. Non-terminal runs are never touched, so parked HITL runs survive (the property #172 established).
Two follow-on questions this does not answer, flagged for maintainer direction:
I have a PR implementing the terminal-run retention piece — happy to rework the approach per discussion here.
eve version
eve@0.13.0 (observed); paths and behavior verified unchanged on
main@ 1fd8a02 (@workflow/core5.0.0-beta.26)Node.js version
v26.3.1
Where does the bug occur?
Local dev (
eve dev)Description
The local workflow world persists every run, event, step, and hook as an individual JSON file under
.workflow-data, and nothing ever deletes them. Combined with two scan behaviors, an always-oneve devagent degrades steadily:@workflow/core's local world lists whole directories with suffix filters per queue operation (readdir+ libuvscandirsort + per-filename V8 string internalization). Operation cost grows with lifetime accumulated files, not live work.pruneDevelopmentRuntimeArtifactsSnapshots→collectWorkflowDataSnapshotPathsrecursivelyreaddirs andreadFiles every file in.workflow-data(≤1MB each) to protect non-terminal runs' snapshots, soeve devboot cost also grows with store size.Observed impact
After roughly one week of an always-on agent (Discord bot + several coding agents driving it):
.workflow-data: ~10,900 files / 315 MB — 8,466 events, 1,460 steps, 500 runs, 459 hooksrunningstatus forever — stranded by killed/restarted dev serverssampleof the process is dominated by__getdirentries64,qsort/strcmp(libuv scandir), and V8InternalizeString/GC — directory enumeration churn, not agent workReproduction
eve devfor an agent that receives steady workflow traffic for days (or synthetically populate.workflow-datawith ~10k run/event/step files in the local-world file format).sample <pid>/ observe CPU: enumeration cost scales with total accumulated files.Expected behavior
Dev-mode workflow history is bounded by a retention policy, and queue/boot cost does not scale with lifetime traffic.
Proposed direction
A boot-time background retention pass for terminal-status runs (
completed/failed/cancelled), mirroring the existingpruneDevelopmentRuntimeArtifactsSnapshotsInBackgroundandpruneLocalSandboxTemplatesInBackgroundseams instartNitroDevelopmentServer: delete terminal runs older than a retention window together with their linked events, steps, hooks, and stream files. Non-terminal runs are never touched, so parked HITL runs survive (the property #172 established).Two follow-on questions this does not answer, flagged for maintainer direction:
runningruns stranded by killed dev servers accumulate forever and are untouched by terminal-only retention. Shouldeve devreconcile or expire them? They are exactly what Parked HITL turn crashes on resume withLoadCompiledManifestErroraftereve devrebuild/restart GCs its snapshot #172 protects, so this needs a deliberate policy rather than an age cutoff.@workflow/coreterritory; retention bounds the pain but an index would fix the shape.I have a PR implementing the terminal-run retention piece — happy to rework the approach per discussion here.