Skip to content

[bug] Cursor: every file Read sends a skill-use webhook with empty data #1238

Closed

Description

@SaulMoro

This was generated by AI during triage.

Summary

On Cursor, every Read tool call sends a skill-use webhook, including reads of ordinary files. When the file is not a SKILL.md, the payload carries data: {}. A team subscribed to skill-use gets one notification per file read, and none of them names a skill.

Found while triaging #1236. It does not depend on #1236 and predates it.

Observed

Reproduced locally on macOS with the built CLI at main (8487c34). The team teamai.yaml had a webhook endpoint pointed at a local listener, and the host simulator ran the installed Cursor hook entries.

Cursor PostToolUse payload track webhook received
Read of .../skills/demo-skill/SKILL.md records demo-skill skill-use, data: {"skillName":"demo-skill"}
Read of README.md records nothing skill-use, data: {}
Shell not dispatched none

Claude Skill and Read calls behave correctly. Only the Skill call sends a webhook.

Cause

  • The built-in Skill hook entry is rendered for Cursor with host matcher Read (SKILL_TOOL_MATCHER, src/builtin-hooks.ts), because Cursor loads skills by reading SKILL.md (fix(hooks): Cursor skill usage not tracked — trackHandler only matches Skill, not Read #1156). Every Cursor Read therefore runs the post-tool-use Skill dispatch.
  • track filters through resolveSkillUse and returns when the read is not a skill.
  • webhookHandler (src/hook-handlers.ts) maps any PostToolUse to skill-use and always sends. buildWebhookData returns {} when resolveSkillUse finds no skill, but an empty result does not stop the send. The comment in buildWebhookData says it "never [fires] for a normal file Read". The behavior does not match that comment.

Expected

A skill-use webhook is sent only for a real skill use. This is the same rule track already applies.

Approach

  • One rule for "is this a skill use". The webhook should follow the same verdict track reaches through resolveSkillUse, so the two cannot drift apart. It should not get a second recognizer.
  • No skill means no event. An unrecognized payload must not be sent as skill-use with empty data.
  • Leave other webhook events alone. session-start and session-stop stay as they are.

This also matters for #1236. Merging the * and Skill dispatches there would move the webhook onto every tool call on every host, so this fix should land first or together with it.

Proof of done. With a webhook endpoint configured, a Cursor Read of an ordinary file sends nothing, and a Cursor Read of a SKILL.md and a Claude Skill call each send one skill-use with the skill name.

Activity

  1. wang2-lat commented on Oct 20, 2026

    @wang2-lat

    Hi! I'd like to pick this up, following the approach in the issue.

    Plan: make the skill-use path in src/hook-handlers.ts report "no skill" instead of {} when resolveSkillUse finds nothing, and have webhookHandler return without sending in that case, so the webhook uses the same verdict as track and no second recognizer is added. session-start / session-stop stay as they are. I'll add unit tests for a Cursor Read of a SKILL.md (sends skill-use with skillName) and a Read of an ordinary file (sends nothing), and check the Claude Skill case still sends.

    I work with AI assistance and will run lint, tsc --noEmit and vitest before opening the PR.

  2. SaulMoro commented on Oct 20, 2026

    @SaulMoro
    CollaboratorAuthor

    Thanks @wang2-lat, the plan matches the issue.

    One addition to your checks. This change alters runtime behavior, so the PR needs an end-to-end record from the real CLI on top of the unit tests, lint and tsc. AGENTS.md requires it under "Testing before a PR". One representative run is enough. After npm run build, configure a webhook endpoint, run the Cursor hook dispatch, and paste the result into the PR description. A Cursor Read of an ordinary file must send nothing, and a Cursor Read of a SKILL.md must send one skill-use with the skill name. If you add an e2e test, npm run test:e2e -- <test-file> runs just that file.

  3. SaulMoro commented on Oct 21, 2026

    @SaulMoro
    CollaboratorAuthor

    @wang2-lat I've unassigned this. It hadn't been started, so the issue is available again.

  4. added
    help wantedExtra attention is needed
    and removed
    help wantedExtra attention is needed
    on Oct 21, 2026
  5. jayhemnani9910 commented on Oct 24, 2026

    @jayhemnani9910
    Contributor

    This looks fixed on main by #1245 (22dfe27). webhookHandler now maps only session start/stop (WEBHOOK_EVENT_BY_HOOK in src/hook-handlers.ts has sessionstart, stop, sessionend), so a PostToolUse no longer becomes skill-use. The skill-use webhook is sent from skillUseHandler, once per skill creditToolCall returns, and a Read of README.md credits none.

    I haven't re-run the hook simulator from the issue; worth one run of the README.md row before closing.

  6. SaulMoro commented on Oct 25, 2026

    @SaulMoro
    CollaboratorAuthor

    This was generated by AI during triage.

    Thanks @jayhemnani9910. Confirmed: fixed by #1245 (22dfe276).

    We ran the simulator from #1236 through the built CLI on macOS. On main (13c891e0) and on 0.28.0-beta.8, a Cursor Read of README.md sends no webhook, and a Cursor Read of a SKILL.md sends one skill-use with skillName. On 0.28.0-beta.7 the same README.md read sent skill-use with data: {}.

    Only betas were affected. The Cursor Read mapping that caused it (#1157, 7b71316b) first shipped in 0.28.0-beta.5, and 0.28.0-beta.8 has the fix. 0.27.0 (latest) never sent the empty webhook, but it does not count a Cursor SKILL.md read as a skill use either, because its Cursor tool entry matches Skill, which Cursor never sends. Only /skill prompt mentions are counted there. The next stable release gets both. On a beta, upgrade to 0.28.0-beta.8 or later (npm i -g teamai-cli@0.28.0-beta.8) and run teamai pull once to replace the old hook entry; no configuration change is needed.

    Closing as completed. Reopen if a Cursor read of a non-skill file still sends skill-use on 0.28.0-beta.8 or later.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions