Inconsistent Hook Payload

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

preToolUse hook stdin omits the documented agent_message field for Shell tool calls.

Docs (https://cursor.com/docs/hooks.md) show preToolUse input including agent_message (e.g. “Installing dependencies…”). On Cursor 3.13.25 (macOS), live Shell preToolUse payloads do not include agent_message at all.

The chat UI still shows the Shell title (“Ran …” / tool description), and that value exists internally as bubble toolFormerData.params.commandDescription in state.vscdb, but hooks cannot read it from stdin.

Also: tool_input.description is stripped from the hook payload (only command, cwd, timeout remain). Docs example uses tool_input.working_directory; live payload uses tool_input.cwd instead.

Steps to Reproduce

  1. Add a preToolUse Shell hook that dumps stdin, e.g. in ~/.cursor/hooks.json:

{
“version”: 1,
“hooks”: {
“preToolUse”: [
{
“command”: “/path/to/dump.sh”,
“matcher”: “Shell”
}
]
}
}

dump.sh:
#!/bin/bash
cat >> /tmp/pretooluse.jsonl
echo ‘{“permission”:“allow”}’

  1. In Agent chat, run a Shell tool that has a visible chat title/description (e.g. description “Run local test suite”, command bun test).

  2. Open /tmp/pretooluse.jsonl and inspect the JSON object for that call.

Expected Behavior

preToolUse stdin should include agent_message when available (as documented), matching the human-readable Shell title shown in chat.

Ideally tool_input.description should also be forwarded for Shell tools instead of being stripped.

Operating System

MacOS

Version Information

IDE:
Version: 3.13.25
VSCode Version: 1.128.0
Commit: 31e8d61c448c7472e371505838a0fe34083dad50

For AI issues: which model did you use?

grok-4.5 (also reproduced on normal Agent Shell tool calls; appears hook-side, not model-specific)

For AI issues: add Request ID with privacy disabled

N/A (hooks stdin issue; no single chat completion Request ID required to reproduce)

Additional Information

Actual live preToolUse payload (redacted) from Cursor 3.13.25:

{
“conversation_id”: “…”,
“generation_id”: “…”,
“model”: “grok-4.5”,
“tool_name”: “Shell”,
“tool_input”: {
“command”: “/Users/…/.bun/bin/bun test …”,
“cwd”: “”,
“timeout”: 30000
},
“tool_use_id”: “…”,
“cwd”: “”,
“session_id”: “…”,
“hook_event_name”: “preToolUse”,
“cursor_version”: “3.13.25”,
“workspace_roots”: [“…”],
“user_email”: “…”,
“transcript_path”: “…/agent-transcripts/….jsonl”
}

Missing vs docs/chat UI:

  • no agent_message key
  • no tool_input.description
  • chat still shows the Shell title; value exists internally as commandDescription on the tool bubble in ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb

Impact: hooks that need the same human-readable Shell label as the chat UI cannot use the documented field and must scrape local SQLite/transcripts as a workaround.

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the detailed report. I’ll go through it point by point.

  1. agent_message in preToolUse. This is a docs issue, not a payload issue. agent_message is an output field, meaning what your hook returns back to the model, for example on permission: deny. It has never been an input field for preToolUse. The doc example that shows agent_message in the incoming payload is wrong, I’ve already flagged it so it can be fixed.

  2. tool_input.working_directory vs cwd. Also a docs mistake. The real key is cwd, just like you see in the live payload. This is on the same list of docs fixes.

  3. tool_input.description for Shell. This one is valid. The human readable title you see in chat is the Shell tool’s description, and right now it’s not being forwarded to preToolUse. Only command/cwd/timeout are forwarded. We’re tracking this issue, and your report helps. No timeline yet, but I’ll reply here when there’s an update.

For now, since description isn’t forwarded, reading it from the transcript or state.vscdb (commandDescription on the tool bubble) is the only way to get the same title. Let me know if any of this behaves differently than I described.

Hey thanks for the prompt response.

I see there is not enough/incorrect documentation on hooks a lot, and I think cursor as a harness provides the best usable hooks, and love the hoook fire log in the UI as well through which it was easy to debug the docs issue.

You could have a look at watchty, where I was using these hooks primarily to get an idea of commands ran as an interactive ghostty TUI surface.

Thanks for sharing watchty. It looks great. Also really nice to hear the hook fire log in the UI helped with debugging, that’s exactly what it was made for.

On the hooks docs, you’re right. There are gaps and some mistakes, like agent_message in the input example and working_directory instead of cwd. It’s already on the list to fix.

No updates on description for Shell yet. Once there are, I’ll reply right here. For now, reading commandDescription from the transcript or state.vscdb is still a working option for the same title.

If you keep building on hooks and run into anything else weird in the payload, drop it here and we’ll take a look.