Skip to content

fix: attribute Cursor-hosted hooks correctly#139

Merged
yyiilluu merged 3 commits into
ReflexioAI:mainfrom
wenchanghan:codex/cursor-host-attribution
Jul 17, 2026
Merged

fix: attribute Cursor-hosted hooks correctly#139
yyiilluu merged 3 commits into
ReflexioAI:mainfrom
wenchanghan:codex/cursor-host-attribution

Conversation

@wenchanghan

@wenchanghan wenchanghan commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What's broken / annoying

Cursor loads the Claude Code plugin directly, so claude-smart currently receives a hook command that says claude-code even when Cursor launched it. New local session rows and hook telemetry are therefore mislabeled, and project-scoped learnings can fall back to a plugin-version project ID when Cursor omits cwd.

What's changing

  • Refine a declared claude-code hook to cursor only when positive Cursor signals are present and Claude Code's own entrypoint is absent.
  • Fill a missing Cursor cwd from CURSOR_PROJECT_DIR before resolving project identity.
  • Treat cursor as a supported local host in session JSONL and dashboard parsing.
  • Reuse the existing request-ID join so project-specific skills and preferences show Generated via Cursor.
  • Add a Cursor badge using the warm-neutral palette from the official Cursor brand assets, distinct from OpenCode's black badge.
Cursor fires Claude Code plugin hook
              |
              v
    one dispatcher detection
              |
              +--> session JSONL: host = cursor
              +--> hook.log: host = cursor
              +--> request ID join
                         |
                         +--> project skill origin
                         +--> preference origin

How the product behaves afterwards

Before Changed After
Cursor sessions appeared as Claude Code. The dispatcher checks layered Cursor signals once. New Cursor session/tool rows and hook telemetry say cursor.
Missing Cursor cwd could create a junk project scope. CURSOR_PROJECT_DIR supplies the missing working directory. Project identity follows the active Cursor workspace.
Cursor was unknown to the dashboard. The existing host type, parser, and shared badge catalog include Cursor. Cursor appears on dashboard/session views and as project-skill/preference provenance.
OpenCode used its own black treatment. Cursor gets its official warm-gray treatment. Cursor and OpenCode remain visually distinct.

Real Claude Code remains Claude Code when CLAUDE_CODE_ENTRYPOINT is present. Explicit Codex and OpenCode hooks are never reclassified. Host metadata stays local and is still removed before interactions are published to Reflexio; the shared learning namespace is unchanged. Existing records are not rewritten, and shared skills remain host-free because they can aggregate multiple sessions.

Verification

  • 693 passed, 1 skipped in the full Python suite.
  • New red/green coverage proves Cursor JSONL + hook-log attribution, missing-cwd recovery, layered detection, explicit-host protection, and Claude Code precedence.
  • Ruff passed for all touched Python files.
  • Dashboard ESLint, TypeScript, and production build passed.
  • Sanitized browser fixtures validated dashboard recents, session list/detail, project-skill list/detail, and preference list/detail.
  • Rendered colors were checked directly: Cursor rgb(214, 213, 210) / rgb(38, 37, 30); OpenCode rgb(19, 16, 16) / white.

A sanitized browser screenshot is attached in the PR conversation.

Summary by CodeRabbit

  • New Features

    • Added Cursor as a recognized host and expanded host/runtime resolution.
    • Cursor badge/provenance now reflects the new host.
    • Cursor sessions include project directory context when available.
    • Cursor can share learnings while preserving correct attribution.
    • Explicit Claude Code configuration takes precedence over Cursor signals.
  • Bug Fixes

    • Improved recorded-host parsing and attribution consistency across Cursor and Claude Code workflows.
  • Tests

    • Added regression coverage for Cursor/Claude Code attribution, precedence rules, and telemetry logging.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: df3d5af1-9f2d-4069-9f57-6fbfe2fddedc

📥 Commits

Reviewing files that changed from the base of the PR and between 0cf4a42 and a7262af.

📒 Files selected for processing (1)
  • tests/test_cursor_support.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_cursor_support.py

📝 Walkthrough

Walkthrough

Cursor is added as a supported host across runtime detection, hook attribution, session parsing, dashboard display, and regression tests. Hook events can derive Cursor metadata from environment variables and transcript paths while preserving Claude Code precedence.

Changes

Cursor attribution

Layer / File(s) Summary
Host contracts and dashboard support
plugin/src/claude_smart/runtime.py, plugin/dashboard/lib/types.ts, plugin/dashboard/lib/session-reader.ts, plugin/dashboard/components/common/host-badge.tsx
Adds cursor to supported host values, recorded-host parsing, and dashboard badge metadata.
Hook host resolution and metadata wiring
plugin/src/claude_smart/runtime.py, plugin/src/claude_smart/hook.py
Resolves Cursor from environment and transcript signals, preserves declared non-Claude hosts, and fills missing cwd from CURSOR_PROJECT_DIR.
Cursor attribution regression coverage
tests/test_cursor_support.py
Tests host precedence, session and hook-log attribution, Cursor project metadata, explicit host handling, and agent version reporting.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Hook as hook.main
  participant Runtime as runtime.resolve_hook_host
  participant State as Session state
  participant Log as Hook log
  Hook->>Runtime: Resolve declared host and payload
  Runtime-->>Hook: Return effective host
  Hook->>State: Set host and Cursor cwd
  Hook->>Log: Record attribution and metadata
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: correctly attributing Cursor-hosted hooks.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@wenchanghan

Copy link
Copy Markdown
Contributor Author

Sanitized UI validation

Synthetic Cursor, Claude Code, and OpenCode sessions verify the host labels and distinct badge colors. No local session or preference data is included.

Sanitized Cursor host attribution validation

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_cursor_support.py`:
- Around line 145-153: Extend
test_explicit_non_claude_host_is_not_reclassified_as_cursor to cover the
explicit "codex" host, either by adding a separate assertion or parameterizing
the existing test. Preserve the CURSOR_TRANSCRIPT_PATH setup and verify
runtime.resolve_hook_host returns "codex" unchanged under Cursor signals.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 442bf1b7-7a3e-4f16-b81a-70f1217c1593

📥 Commits

Reviewing files that changed from the base of the PR and between e71343f and 0cf4a42.

📒 Files selected for processing (2)
  • plugin/dashboard/components/common/host-badge.tsx
  • tests/test_cursor_support.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugin/dashboard/components/common/host-badge.tsx

Comment thread tests/test_cursor_support.py Outdated
@wenchanghan

Copy link
Copy Markdown
Contributor Author

Review follow-up

Applied the accepted non-behavioral feedback in 0cf4a42:

  • Added the three required Cursor test docstrings.
  • Restored per-host contrast documentation, including Cursor at 10.48:1.
  • Removed the unused CURSOR_USER_EMAIL test-fixture cleanup.

A clean-context GPT-5.6 Terra High simplification review found no safe core refactor; the existing detection order, path containment, hook-level payload normalization, and typed dashboard contracts are the leanest low-regression shape.

Validation: 693 passed, 1 skipped; Ruff, dashboard lint/build, all GitHub integration jobs, and CodeRabbit passed.

@yyiilluu
yyiilluu merged commit 045d8b3 into ReflexioAI:main Jul 17, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants