Spawning fork/self-fork agents geometrically duplicates subagent records → state.vscdb 30+ GB, freezes

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Repeatedly calling the Task tool with resume:“self” (a “self-fork” subagent that inherits the current thread’s full conversation) in a single thread makes Cursor deep-copy every prior self-fork’s records on each new call. Each self-fork call DOUBLES the stored subagent records: N sequential self-fork calls produce 2^N − 1 subagent conversation records in state.vscdb — byte-identical clones that share one toolCallId/parentRequestId per genuine call (not real agents).
Because each cloned record carries the whole inherited conversation, a handful of self-fork calls in a normal-sized thread balloons state.vscdb by many GB, slows agent spawns to minutes, and freezes the UI.

Steps to Reproduce

Deterministic, from an EMPTY chat. Paste this as the first message of a NEW chat:

Controlled experiment — follow literally, don't batch or optimize.
Make exactly 10 Task calls, ONE AT A TIME (wait for each to finish). For N = 1..10:
Task(subagent_type:"generalPurpose", resume:"self", run_in_background:false, description:"repro leaf N", prompt:"OVERRIDE all inherited context: reply only 'OK'. Call no tools. Do not spawn, fork, or resume any agent.")
After each returns, print "spawned N/10".
Rules: exactly 10 calls, all made by YOU; no child may spawn anything; use no other tools; print "done" after the 10th.

Observed: the subagent-record count DOUBLES on every call. By call 10 the thread holds 1023 subagent records (2^10 − 1) instead of 10. Lag becomes severe around call 8–9, as each new self-fork must deep-copy 256 → 512 → 1024 prior records.

Expected Behavior

Each Task call — including resume:“self” — should create exactly ONE new subagent record and must not re-copy previously created subagents. Subagent-record count and state.vscdb size should grow linearly (O(N)) with the number of calls, never geometrically (O(2^N)).

Operating System

MacOS

Version Information

Version: 3.11.2
VS Code Extension API: 1.125.0
Commit: 8406a18de147860db9b3a1cf20cfa760a4e72e60
Date: 2026-07-07T06:40:11.039Z
Layout: Agent Window
Build Type: Stable
Release Track: Nightly
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.256
OS: Darwin arm64 25.5.0

Additional Information

Reproduced deterministically from an empty chat: 10 sequential Task(resume:“self”, run_in_background:false) calls → exactly 2^N − 1 = 1023 subagent records.

How to confirm in the DB (global state.vscdb at ~/Library/Application Support/Cursor/User/globalStorage/, table cursorDiskKV):

  1. Find the experiment chat’s composerId in ItemTable[‘composer.composerHeaders’] → allComposers.
  2. Count the subagent records whose lineage resolves to that chat → 1023 (not 10).
  3. Group those subagents by subagentInfo.toolCallId → exactly 10 genuine ids, with copy counts that are EXACT powers of two: 512, 256, 128, 64, 32, 16, 8, 4, 2, 1. (The earliest self-fork is re-copied by every later one.) This powers-of-two curve is the signature.
  4. Every duplicate is a full composerData: row plus its bubbleId:/checkpointId: rows, all sharing the same toolCallId/parentRequestId; conversationLengthAtSpawn > 0 on all (they inherited the thread).

Note on file size — experiment vs. real usage:
In this minimal experiment each duplicated conversation is trivial (“OK”), so even 1023 cloned records add only tens of MB. That’s by design — the repro isolates the 2^N record MULTIPLIER cleanly, without a large payload hiding it. Real usage is far heavier: you’re working in a normal thread with a long conversation (hundreds of messages, large tool outputs) and you call self-fork agents from time to time. Every self-fork then deep-copies that entire heavy conversation, so the same doubling multiplies GIGABYTES instead of kilobytes. That is how ordinary day-to-day work — a handful of self-fork spawns across a real session — reaches 30+ GB in state.vscdb, multi-minute agent spawns, and UI freezes.

Note: “Developer: GC Agent KV Blobs” does NOT remove these live duplicate composer/bubble rows.

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey there,
You’ve got this right, and we’ve been able to confirm it: repeated resume:"self" self-fork calls in a single thread re-copy every previously created subagent record on each new call, so the stored records grow geometrically instead of once per call. That’s what balloons state.vscdb, slows agent spawns, and can eventually freeze the UI. I’ve shared your reproduction with the team and we’re looking into it.

To keep you unblocked in the meantime:

  1. Avoid repeated resume:"self" calls within a single long thread - that’s the specific trigger for the doubling. If you need a fork of the current context, a fresh chat (or a regular subagent) sidesteps the re-copy.
  2. On reclaiming space: you’re right that “GC Agent KV Blobs” won’t clear these, since the duplicated rows are still referenced. If your state.vscdb has already grown large, the reliable reset today is to fully quit Cursor, back up ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb, then delete it (Cursor regenerates it on restart). Please back it up first - deleting it clears your local chat history.

I’ll follow up here as we make progress.