Skip to content

Cursor hook silently drops all rewrites — rtk rewrite exit code 3 treated as failure #2372

Description

@euclidesgc

Summary

The Cursor integration (rtk init --global --agent cursor) does not rewrite shell commands. Both rtk hook cursor and hooks/cursor/rtk-rewrite.sh treat rtk rewrite exit code 3 as a failure and return {} (pass-through), so commands run unchanged and RTK filtering never applies.

This appears to be the same root cause as #2200 (OpenClaw plugin), but it also affects the official Cursor hook shipped with RTK.

Environment

  • RTK: 0.42.3
  • OS: macOS (darwin 25.4.0)
  • Agent: Cursor IDE (Agent mode, preToolUse hook)
  • Hook config: ~/.cursor/hooks.json with matcher: "Shell" and command: "rtk hook cursor"

Steps to reproduce

  1. Install RTK and run:
    rtk init --global --agent cursor
  2. Restart Cursor.
  3. Ask the agent to run:
    git status
  4. Observe raw git status output instead of RTK-compact output.

Expected behavior

git status should be transparently rewritten to rtk git status, and the agent should see compact output like:

* branch-name
clean — nothing to commit

Actual behavior

The command runs as plain git status. rtk gain --history does not record the command. Simulating the hook also returns {}:

printf '%s' '{"tool_input":{"command":"git status"}}' | rtk hook cursor
# → {}

Root cause

rtk rewrite returns exit code 3 when it has a rewrite suggestion, but the hook treats any non-zero exit as failure:

# hooks/cursor/rtk-rewrite.sh (line 47)
REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null) || { echo '{}'; exit 0; }

Even though stdout contains the correct rewrite (rtk git status), the || branch runs and discards it.

Verified manually:

$ rtk rewrite "git status"
rtk git status
$ echo $?
3

The script comment says "rtk rewrite exits 1 when there's no rewrite", but successful rewrites also use a non-zero exit code (3), which breaks the hook logic.

Workaround (confirmed working)

Replace the hook command with a wrapper that captures stdout regardless of exit code:

REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null || true)

if [ -z "$REWRITTEN" ] || [ "$CMD" = "$REWRITTEN" ]; then
  echo '{}'
  exit 0
fi

jq -n --arg cmd "$REWRITTEN" '{
  "permission": "allow",
  "updated_input": { "command": $cmd }
}'

After applying this workaround, git status is correctly rewritten and RTK-compact output is returned.

Suggested fix

  1. Fix rtk rewrite to exit 0 on successful rewrite (breaking change for callers that rely on exit 3), or
  2. Update all hook integrations (hooks/cursor/rtk-rewrite.sh, rtk hook cursor, OpenClaw, etc.) to read stdout on exit code 3 instead of treating it as an error.

Related: #2200, PR #2202

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions