fix(agent-setup): preserve Cursor identity through tool execution

Closed
OW
2mo ago
+341-8

What & why

Cursor imports Claude hook settings. Superset’s imported command sets SUPERSET_AGENT_ID=claude, so a duplicate event can relabel a Cursor terminal as Claude and change its runtime identity. This reproduces with a GPT model selected in Cursor; the terminal label identifies the agent application, not the model.

Suppress imported events only when the command identifies Claude, CURSOR_VERSION is present, and the event uses Cursor’s lowercase naming. Genuine Claude events remain supported, including Claude launched from Cursor’s environment. Bump the generated notification hook marker to v10.

Register native postToolUse and postToolUseFailure as Start so shell/MCP activity does not remain at PermissionRequest after the imported duplicate is suppressed. Match only Shell and MCP:<tool>, whose existing before-hooks set that state. Existing user hooks are preserved.

Cursor documents third-party hook imports and native hook matchers.

How I tested it

Real interactive Cursor CLI 2026.09.02-c22c1a3, launched inside Superset with gpt-5.6-terra-low. The same terminal shows Claude after a completed turn with the base notification hook, then Cursor with the candidate hooks. Captures are cropped to the terminal header and response; private metadata is omitted.

Before: Cursor running, Claude icon

Cursor incorrectly labeled Claude

After: Cursor running, Cursor icon

Cursor identity preserved after completion

  • Native CLI tool runs verified shell success/nonzero exit, MCP success/error results, file-read exclusion, and session-end detachment against host bindings. Temporary hook configuration was restored byte-for-byte. Tool qualification used print mode; completed-turn captures used the interactive CLI.
  • Regression fails before the post-tool registrations: PermissionRequest remains where Start is required. Removing the matcher in an isolated test copy fails both child Read assertions.
  • Bun 1.3.14, current commit a0ee299: 303 package tests passed, 1,262 assertions across 14 files. Repository lint and all 38 typecheck tasks passed locally. Executable hook tests also cover interruption, duplicate imports, genuine Claude events, and other providers. Interruption is replay coverage, not a live user-cancel claim.
  • CI on the current commit a0ee299: all 11 jobs passed, including lint, tests, typecheck, desktop build, and four CLI builds.
  • Locale regression: on macOS /bin/bash 3.2.57 with en_US.UTF-8, the old [a-z] range also suppressed uppercase Claude events. The regression fails before the correction and passes with [[:lower:]]. Hook tests now use the production shebang interpreter and exercise C plus an installed US English UTF-8 locale.
  • CodeRabbit review completed. Its suggestion to bypass the matcher in the child test was checked against the failing matcher-removal mutation; the test retains the provider boundary.
Scope and validation limits

Existing Cursor shell/MCP child hooks can overwrite a parent terminal’s session binding; captured child events reproduce this through the unchanged base hook. This change does not establish parent/child isolation or alter terminal-turn failure classification. Cursor IDE behavior is unverified.

The fork preview cannot deploy because its Neon api_key is absent. Local full-repository tests stop on missing service environment variables in four unchanged tRPC test files. A Bun 1.4.0 package run failed an existing endpoint fast-path test; the repository-pinned Bun 1.3.14 package run and current commit a0ee299’s full CI passed.

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass on the current commit in CI
  • "Allow edits from maintainers" is checked on fork PRs

Summary by cubic

Fixes Cursor terminals being relabeled as Claude when Cursor imports Claude hook settings, so Cursor's runtime identity is preserved through tool execution.

  • Suppresses imported lowercase Cursor events only when SUPERSET_AGENT_ID=claude and CURSOR_VERSION is present; genuine Claude events still dispatch.
  • Registers native postToolUse and postToolUseFailure as Start events with a matcher for Shell and MCP tools so tool activity doesn't remain at PermissionRequest.
  • Bumps the notification hook marker to v10; existing user hooks are preserved.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Cursor integration by limiting post-tool notifications to Shell and MCP tool events.
    • Prevented duplicate or incorrect lifecycle notifications when Cursor invokes Claude hooks.
    • Preserved accurate event types and agent identity in notifications across supported tools and environments.
    • Updated generated notification hooks so newer installations correctly recognize and apply the latest hook behavior.