Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- On 0.1.3 with the Claude provider, start a thread whose agent runs a Claude Workflow that fans out to many agents (here: one workflow with 486 agents over ~28 h, another with 314).
- Let it run. Every workflow progress tick produces a
subagent.updatedevent. - Open
statev2.sqliteread-only and measure the stored bytes per workflow subagent:
SELECT count(*) AS updates,
round(sum(length(payload_json)) / 1048576.0) AS stored_mib,
round(max(length(payload_json)) / 1024.0) AS last_kib,
json_array_length(payload_json, '$.workflow.agents') AS agents
FROM orchestration_events
WHERE event_type = 'subagent.updated'
AND json_type(payload_json, '$.workflow.agents') = 'array'
GROUP BY json_extract(payload_json, '$.id')
ORDER BY stored_mib DESC
LIMIT 5;Expected behavior
The event store grows roughly in proportion to what changed. A tick that changes one workflow member stores that member (or a small delta), not the whole member list again. Superseded subagent.updated snapshots are compacted like node.updated and message.updated.
Actual behavior
Each subagent.updated for a workflow subagent stores the complete workflow.agents array. Each member carries its own prompt, result, childThreadId, timings and token counts. Between two consecutive updates, on average 1.04 members change (max 2; 1 of 4,470 updates changed nothing). The array grows as agents are queued, so total stored bytes grow roughly quadratically with workflow size.
Results from the query above on one install (aggregate numbers only):
| updates | stored | last snapshot | agents |
|---|---|---|---|
| 4,461 | 1,422 MiB | 594 KiB | 486 |
| 2,829 | 585 MiB | 385 KiB | 314 |
| 276 | 24 MiB | 120 KiB | 102 |
| 246 | 11 MiB | 83 KiB | 68 |
| 103 | 8 MiB | 96 KiB | 81 |
- The largest workflow stored 1,422 MiB for a final state of 594 KiB, about 2,400×.
- Over the last ~36 h,
subagent.updatedwas 2.07 GB, and 98.9 % of it is$.workflow.agents. Inside that array, the members'promptfields are the largest part, followed bychildThreadIdandresult. - Over 7 days, by event type (count, payload MiB):
subagent.updated43,654 / 2,595;turn-item.updated260,695 / 682;node.updated183,693 / 220. Everything else is under 50 MiB. - Daily
orchestration_eventspayload went from ~200–350 MiB/day to 1,805 MiB on the day these workflows ran.statev2.sqliteis now 10.0 GB, withorchestration_eventsat 6.95 GB.auto_vacuumis 0 and the freelist is 0. - No compaction happens. History compaction (fix(server): compact superseded history in the background #19435) keeps the first and newest rows only for
node.updatedandmessage.updated, so every workflow snapshot stays permanently. The corresponding rows inorchestration_v2_projection_subagentsare small (276 rows, 13 MiB), so only the event log is affected.
Related but different: #18204 removed the repeated top-level subagent prompt (fixed by #18375). The per-member prompt/result inside workflow.agents is still re-stored on every tick. Retention and compaction in general: #21371, #24789, #18559.
Impact
Major degradation or frequent failure
Version or commit
t3 v0.1.3
Environment
Ubuntu 26.04.1 LTS (kernel 7.0), Node v22.22.1, shared headless dev server, Claude provider (claudeAgent driver) running Workflow fan-outs.
Logs or stack traces
# subagent.updated, last ~150k events (2026-10-28 18:00 → 2026-10-30 13:00 UTC)
events: 12,141 payload: 2,069.7 MiB
$.workflow.agents 2,097.8 MiB 98.9 %
$.workflow.phases 7.8 MiB 0.4 %
everything else < 3 MiB each
workflow subagents: 17, events: 9,003
changed agents per update (largest workflow): mean 1.04, max 2Workaround
None in-product. Compaction does not touch subagent.updated, so these rows stay. Avoiding very large Workflow fan-outs on long-lived servers limits the growth. The disk space is only reclaimed by deleting the rows and running an offline VACUUM (t3 doctor).
Activity
juliusmarminge commentedon Nov 12, 2026
I tried to reproduce this on the current build and could not.
Commit ed54f30 (origin/main). Not seen in a running app: that needs the Claude provider running a real Workflow fan-out, and no worker has a Claude provider (a large Workflow would also cost real money). Reproduced through the production OrchestrationEventStore layer on in-memory SQLite instead: added the test 'stores a workflow tick without re-storing its unchanged members' to apps/server/src/persistence/OrchestrationEventStore.test.ts. It appends 60 subagent.updated events for one workflow subagent with 60 members (each member has a roughly 1 KB prompt), and each tick completes one more member, matching the reporter's measured 1.04 changed members per tick. Stored payload_json totals 3,328,029 bytes for a final snapshot of about 56 KB, roughly 60 times. Total storage grows quadratically with member count, as the reporter measured (1,422 MiB for a 594 KiB final state). Replay decodes correctly.
vp test run src/persistence/OrchestrationEventStore.test.ts: the new test fails ('expected 3328029 to be below 168258') and the other 10 pass. The 'never compacted' half is no longer true on main: #29806 (merged 2026-11-03, after the reporter's 0.1.3) prunes events older than about 24 to 30 h, keeping stream heads. The per-tick full-array write and up to a day of it on disk remain.Closing as not planned. If it still happens for you, reply with the exact steps and the version you are on and it will be looked at again.