diff --git a/src/plugins/claude/content/plugins/trace-claude-code/.cursor-plugin/plugin.json b/src/plugins/claude/content/plugins/trace-claude-code/.cursor-plugin/plugin.json new file mode 100644 index 00000000..c0ec639a --- /dev/null +++ b/src/plugins/claude/content/plugins/trace-claude-code/.cursor-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "trace-claude-code", + "description": "Claude Code tracing only. Use the Braintrust Cursor plugin for Cursor tracing.", + "hooks": { + "version": 1, + "hooks": {} + } +} diff --git a/src/plugins/claude/content/plugins/trace-claude-code/README.md b/src/plugins/claude/content/plugins/trace-claude-code/README.md index e62229ed..dbcaaa41 100644 --- a/src/plugins/claude/content/plugins/trace-claude-code/README.md +++ b/src/plugins/claude/content/plugins/trace-claude-code/README.md @@ -15,6 +15,11 @@ journaling, trace construction, and delivery. ## Supported surfaces This plugin supports Claude Code CLI and Claude Code mode in the desktop app. +Cursor automatically imports installed Claude plugins when third-party imports +are enabled. This plugin includes a Cursor manifest with no hooks so that +Cursor uses the native Braintrust Cursor integration for tracing. Enable that +integration with `bt trace enable cursor --project `. + It does not support the Cowork tab. Cowork executes hooks in a separate VM that does not inherit the host's `bt` binary, saved Braintrust route, or credentials, so installing this plugin there does not enable tracing. diff --git a/src/plugins/claude/validate.sh b/src/plugins/claude/validate.sh index a7d7e608..e322c487 100755 --- a/src/plugins/claude/validate.sh +++ b/src/plugins/claude/validate.sh @@ -31,6 +31,7 @@ check_json "$MARKETPLACE" # Required files for each shipped plugin. required=( "plugins/trace-claude-code/.claude-plugin/plugin.json" + "plugins/trace-claude-code/.cursor-plugin/plugin.json" "plugins/trace-claude-code/hooks/hooks.json" ) for rel in "${required[@]}"; do @@ -65,6 +66,14 @@ import sys with open(sys.argv[1]) as f: hooks = json.load(f)["hooks"] +# Cursor prefers its own manifest when importing an installed Claude plugin. +# An explicit empty hook config prevents fallback to the Claude hook file. +from pathlib import Path +plugin = Path(sys.argv[1]).parent.parent +cursor = json.loads((plugin / '.cursor-plugin/plugin.json').read_text()) +assert cursor['name'] == 'trace-claude-code' +assert cursor['hooks'] == {'version': 1, 'hooks': {}} + expected_events = { "PermissionDenied", "PostCompact", "PostToolUse", "PostToolUseFailure", "PreToolUse", "SessionEnd", "SessionStart", "Stop", "StopFailure", diff --git a/src/plugins/cursor/content/README.md b/src/plugins/cursor/content/README.md index 7cd12bc2..39332c0c 100644 --- a/src/plugins/cursor/content/README.md +++ b/src/plugins/cursor/content/README.md @@ -40,6 +40,8 @@ Cursor's `PATH` when hooks run. `bt trace enable cursor` also installs capture hooks in `~/.cursor/hooks.json`. These user hooks work with third-party imports disabled and when a marketplace installation takes precedence over the local plugin. Plugin hooks skip capture for events covered by these user hooks. +The Braintrust Claude Code plugin exposes no hooks when Cursor imports it; +Cursor tracing uses this integration's native hooks. ## Quickstart