Cursor agent identity/resume: residual gaps after the SUPERSET_HOOK_HARNESS fix
Summary
- Terminal agent bindings record
agent_id = "claude"forcursor-agentsessions, while storing Cursor's real session id. - Reopening the workspace therefore runs
claude --permission-mode auto --model sonnet --resume <cursor-session-uuid>, which fails withNo conversation found with session ID: .... The Cursor session can never be resumed. - Happens for every Cursor CLI session. Across my two org databases, all 79
terminal_agent_bindingsrows sayclaudeand zero saycursor-agent, yet 4 of 6 stored session ids are genuine Cursor sessions (they exist under~/.cursor/projects/*/agent-transcripts/<id>/and~/.cursor/chats/*/<id>/, and not under~/.claude/projects). - Likely the same root cause as #5259 (Cursor Agent "Task complete" notification on every model turn) — different symptom, same mechanism.
Steps to reproduce
- Create a workspace using the Cursor Agent (
cursor-agent) preset. - Let the agent run at least one turn.
- Quit Superset, reopen it, and reopen that workspace's terminal.
Expected
Resume uses the cursor-agent config, i.e. cursor-agent --resume <id>.
Actual
Resume uses Claude's config with Cursor's session id, and fails immediately.
Cause
cursor-agent loads Claude Code's hook config in addition to its own — it resolves claudeUserConfigPath = ~/.claude/settings.json (plus project .claude/settings.json / settings.local.json) alongside ~/.cursor/hooks.json, parses them with parseClaudeConfig, and runs them.
Superset's managed Claude hook command hardcodes the agent id as an env prefix:
[ -n "$SUPERSET_HOME_DIR" ] && [ -x "$SUPERSET_HOME_DIR/hooks/notify.sh" ] && SUPERSET_AGENT_ID=claude "$SUPERSET_HOME_DIR/hooks/notify.sh" || true
That prefix overrides the correct SUPERSET_AGENT_ID=cursor-agent exported by Superset's own cursor-agent wrapper. Verified: the live cursor-agent process has SUPERSET_AGENT_ID=cursor-agent in its environment, and its terminal id matches a binding row that says claude.
So notify.sh POSTs {agentId: "claude", sessionId: "<cursor session id>"}. Server-side recordEvent does nextAgentId = agentId ?? existing?.agentId (last write wins), and Claude's PostToolUse hook fires on every tool call, so claude is continuously re-asserted for the lifetime of the session.
The two hook sets are not deduplicated, because dedupeClaudeHooksAgainstCursorHooks keys on exact command string plus event name — cursor-hook.sh … and notify.sh differ, and the event names differ too (beforeSubmitPrompt vs UserPromptSubmit).
Suggested fixes
- In
getManagedNotifyHookCommand, useSUPERSET_AGENT_ID=${SUPERSET_AGENT_ID:-claude}so the wrapper's value wins when another Claude-config-compatible agent executes the hook. - Better: treat the launch preset as authoritative for the binding's
agent_id. It is already known at terminal creation time (bindResumedSessionrecordsagentId: presetId), so a foreign agent's hook should not be able to overwrite it. - Possibly also guard the resume builder: if the stored session id does not belong to the resolved agent, prefer starting fresh over emitting a command that cannot succeed.
Separate, smaller bug
cursor-hook.sh's fallback identity detection checks $CURSOR_AGENT / $CURSOR_CLI:
if [ -n "$CURSOR_AGENT" ] || [ -n "$CURSOR_CLI" ]; then AGENT_ID="cursor-agent"; else AGENT_ID="cursor-composer"; fi
cursor-agent 2026.09.10 sets neither; it sets CURSOR_INVOKED_AS=cursor-agent. So whenever SUPERSET_AGENT_ID is absent, a CLI session is mislabelled as cursor-composer (which is not in BUILTIN_AGENT_IDS at all).
Environment
Superset 1.26.0, macOS Darwin arm64, cursor-agent 2026.09.10-fd3934a
Source: superset-sh/superset