Skip to content

Cursor 3.18.25 lineage gaps: subagentStart omits the child conversation id; child hooks carry no parent/root; MCP _meta carries no conversation; sessionStart not dispatched to plugin hooks on desktop #424

Description

@ScriptedAlchemy

Scope

Lineage only: who a Cursor conversation's parent is, what its root is, and — for subagents — the parent-of-subagent chain. Operator/user identity is out of scope for agent-bundle by maintainer decision (2026-09-03, see #391), so this issue tracks no identity fields; the framework passes them through inside the native payload unread.

What the host exposes (2026-09-03, live capture)

Evidence: docs/audits/2026-09-03-host-lineage-matrix.md §1–§5 and fixtures/host-lineage/cursor-3.18.25.ndjson (PR #421). Cursor 3.18.25 desktop, isolated --user-data-dir on Xvfb, plugin installed under ~/.cursor/plugins/local/host-test, Agents pane driven over CDP, one Task subagent that spawned a nested Task (depth 2).

Fact Observed
Root conversation on its own events conversation_id (= session_id) + generation_id, cursor_version, workspace_roots
subagentStart / subagentStop carried by the parent conversation: subagent_id = tool_call_id = the parent's Task tool_use_id (a two-line composite call-<uuid>-<n>\nfc_<id>_<k>), parent_conversation_id (= conversation_id), subagent_type, subagent_model, is_parallel_worker, task; generation_id equals the conversation id here. The child's conversation id is not included.
A subagent's own hooks a fresh conversation_id and nothing else: no parent_conversation_id, no subagent_id, no root; transcript_path is empty on the child (the root's names its own transcript, …/agent-transcripts/<root>/<root>.jsonl). Nested subagents likewise.
MCP tools/call _meta progressToken only; client cursor-vscode 1.0.0. preToolUse fires with tool_name: "MCP:<tool>" before the call and postToolUse after, so ordering is the only correlation.
Not delivered to plugin hooks in this run sessionStart (never fired; the sibling raw hooks probe on the same build saw none either). workspaceOpen fired to user-level hooks only and sessionEnd did not fire — but see the desktop evidence below: both do reach plugin-scoped hooks on the desktop. preToolUse was delivered twice for some Read/Grep calls with the same tool_use_id.
Environment hooks receive CURSOR_PLUGIN_ROOT, CURSOR_PROJECT_DIR, CURSOR_VERSION, CURSOR_WORKSPACE_LABEL, CURSOR_EXTENSION_HOST_ROLE, CLAUDE_PLUGIN_ROOT, CLAUDE_PROJECT_DIR; no conversation id (shell commands the agent runs do get CURSOR_CONVERSATION_ID/CURSOR_REQUEST_ID, hooks do not)

Desktop hooks-service evidence (2026-09-03, maintainer machine)

Cursor desktop writes ~/.config/Cursor/logs/<launch>/<window>/output_*/cursor.hooks.workspaceId-*.log and logs Hook step requested: <event> for every step before matching declared hooks (58,717 preToolUse steps were requested with no hook declared for them), so a missing step is non-dispatch, not non-registration. Across the retained logs (cursor_version 3.14.7, 2026-08-14 → 2026-08-25; 3.18.25 on 2026-09-03; 89,219 steps, 35 conversations, a local plugin declaring sessionStart/sessionEnd/workspaceOpen/stop/postToolUse/…):

Step Requested Delivered to the plugin-scoped hook
workspaceOpen 12 yes (from claude-plugin config, sessionless envelope)
sessionEnd 6 yes — reason: window_close, final_status: none, session_id = conversation_id, generation_id: "", transcript_path: null
beforeSubmitPrompt 7 yes
stop 8 yes
preCompact 4 yes
sessionStart 0

Only 7 of the 35 conversations ever produced beforeSubmitPrompt; 28 were first seen on a tool hook (Cursor restarted mid-conversation, or the plugin loaded mid-conversation). That is why root establishment cannot depend on sessionStart and why a blind child binding needs a correction path (below).

What the framework does about it

request.lineage (#421) is the single surface for parent/root/subagent on every host. On Cursor it binds by elimination and refuses when elimination is not possible:

  • A never-seen conversation_id on a tool hook binds to the pending subagentStart only when exactly one is pending in the same workspace_roots (resolution: 'inferred'); with several pending — parallel workers — it stays id-not-resolvable until all but one have stopped.
  • A blind binding is undone the moment the bound conversation carries any root-only event (beforeSubmitPrompt, stop, sessionEnd, preCompact — a subagent never does): the conversation is materialized as the root it is, anything it started meanwhile is re-rooted beneath it, and the pending child waits for its real conversation again. The correction runs before the event acts, so a sessionEnd on a misbound chat retires that chat, never the parent it was filed under.
  • Only root-shaped events (beforeSubmitPrompt, stop, sessionEnd, preCompact, sessionStart when delivered) establish a root; MCP calls resolve through the open MCP:<tool> pre-tool hook and are refused when open windows for that tool span several conversations.
  • Duplicate preToolUse deliveries replay the same journal entries (keys derive from the caller key and the payload digest).
  • Cursor cloud agents run no user hooks, so the axis reports cloud-agent-no-user-hooks there.

The workspace scoping and the root-only-event correction landed in #444 (merged as 284141958).

Host-side gaps (recorded for reference; not submitted to Cursor — maintainer decision 2026-09-03)

The Cursor lineage.parent/lineage.depth/lineage.root/mcp-correlation rows stay degraded (inferred / hook-correlated) until a Cursor build delivers:

  1. the child conversation_id on subagentStart/subagentStop;
  2. parent_conversation_id (and ideally the root) on every hook payload inside a subagent conversation;
  3. the conversation id (and the pre-tool tool_use_id) in tools/call _meta, as Claude and Codex do;
  4. sessionStart on the desktop (3.14.7 and 3.18.25 requested it 0× in 89,219 hook steps while dispatching sessionEnd, workspaceOpen, beforeSubmitPrompt, and stop; the cursor-agent CLI with trusted project hooks does dispatch it). workspaceOpen and sessionEnd are confirmed delivered to plugin-scoped hooks and are not part of this gap.

No feedback is sent to Cursor; the per-host write-up was removed in #467 (merged as 9d4fbd867) per maintainer decision, and docs/audits/2026-09-03-host-lineage-matrix.md plus the capability tables are the record a newer build is re-checked against.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    host-integrationAgent host capabilities, projection, discovery, and lifecycle

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions