Repository navigation
fix(init): --agent cursor installs Cursor only and creates ~/.cursor - #3000
Conversation
rtk init -g --agent cursor fell through to the shared init path with install_claude derived only from !opencode, so it created RTK.md, CLAUDE.md, and patched settings.json under ~/.claude in addition to patching .cursor/hooks.json. On machines without ~/.claude it failed outright when creating the temp file. Two fixes: - Gate install_claude on the absence of a sibling agent target (Cursor, Windsurf, Cline) so only the default or explicit Claude target installs Claude Code files. - Create ~/.cursor before patching hooks.json; atomic_write places its temp file in the target's parent, which failed on a fresh machine where the directory did not yet exist. Closes rtk-ai#2097
|
Tested E2E locally with my local rnoz/integration branch. All working as expected. See the capture. Ready for review/merge. |
|
@pszymkowiak please, let me know if I have to do anything else here (or it's just waiting), since another PR was closed in favor of my current one. I have also another one reviewed by some independent folk. Have a good one! |
|
@rNoz Curious if this fixes rtk-ai usage on the Cursor IDE vs. the Cursor CLI tool? Or is rtk-ai meant only for terminal-based coding agents like Claude Code and Cursor CLI? |
I focused on the cli for testing, but if I have to guess, it will work for both. |
There was a problem hiding this comment.
LGTM 👍
I've reviewed this PR and tested on my machine:
Macbook Pro M1 Max - Mac OS 15.5 (24F74) - Sequoia
Cursor Desktop (non CLI):
Version: 3.13.10
VS Code Extension API: 1.128.0
Commit: 4f02290ccd9304f0e6bf8ee85f6e9106f02ac1f0
Date: 2026-07-23T21:41:07.333Z
Layout: IDE
Build Type: Stable
Release Track: Default
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.256
OS: Darwin arm64 24.5.0
These changes expertly fix the original issue(s) described.
However, these changes alone do not solve the wider rtk usage on Cursor IDE (non CLI).
It seems that the rewrites made by rtk use "permission":"ask" in update_input which doesn't actually show a permission interrupt for users to decide. But it looks like #1173 solves for this issue (untested).
|
Friendly ping @aeppling. This has been open since July 14 with a community approval (@theabhinavdas tested it on Cursor IDE, MacOS Sequoia) but no maintainer review yet. It closes #2097: |
|
Is there any ETA on this MR? Cursor users would really appreciate it 😞 |
|
Yeah this is depressing (not only in this repo but others AI-powered as well), ETA hopefully by 2030. |
Carries the Cursor hunk into src/hooks/init/cursor.rs after the init.rs split (rtk-ai#3878). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tests set only HOME, so an exported CLAUDE_CONFIG_DIR made default_dry_run_still_installs_claude fail, and the non-dry-run install wrote its tracking database into the caller's XDG_DATA_HOME. Pin RTK_DB_PATH and XDG_* inside the temp home, drop CLAUDE_CONFIG_DIR, disable telemetry, and check the exit status of every dry run. Cover the two remaining inputs of the install_claude decision: an explicit --agent claude still installs Claude Code, and --agent cursor with --opencode installs the OpenCode plugin and the Cursor hook only. Also correct the Cursor comment in init::run: with --agent cursor no longer installing Claude Code, Cursor hooks go in on their own or next to the OpenCode plugin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KuSh
left a comment
There was a problem hiding this comment.
Round 1 of 3 — APPROVED, follow-ups filed
Claim: rtk init -g --agent cursor installs the Cursor hook only (no RTK.md, CLAUDE.md or settings.json under ~/.claude) and creates ~/.cursor before writing hooks.json, so it works on a machine that has neither directory (#2097).
Scope: accept, as a Cursor-only fix. Making every installer create its own parent directory is a separate follow-up and is not asked of this PR. (round 1, frozen)
Ran: all 3064 rtk init forms × 6 home seeds (empty, user content, env dirs, empty env, invalid JSON, existing backups) × install / re-run / uninstall, develop 91872ab vs this PR merged onto it. Every one of the 215 differences is an --agent cursor row, 20 of them go from exit 1 to exit 0, there are no crashes, and no other agent changes. On the seeds with user content, develop rewrites the user's ~/.claude/CLAUDE.md and this PR leaves it byte-identical. Also by hand: cursor with --claude-md, --hook-only, --opencode, --no-patch; ~/.cursor as a symlink, a dangling symlink and a regular file; project-scoped refusal; dry-run creates nothing. Five mutations (gate reverted, create_dir_all dropped, dir created in dry-run, gate narrowed to agent.is_none(), Cursor skipped with --opencode) are each caught by a test. Invariants: non-default targets, every decision, user content. No filter involved, so no savings figure.
Matrix: executed this round
CI @f29882be: all green (11/11, incl. macOS, Ubuntu, Windows)
Blocks merge (0, frozen at round 1)
None.
Optional — will not hold merge
src/main.rs:install_claudelists what to exclude (!install_cursor && !install_windsurf && !install_cline). The Windsurf and Cline terms never take effect, becausehooks::init::runsends both to their own modes before it readsinstall_claude. An allow-list,!opencode && matches!(agent, None | Some(AgentTarget::Claude)), has the same behaviour today and would stop a future agent that falls through to this branch from picking up Claude files.- Users who ran
--agent cursorbefore this fix still haveRTK.md, the@RTK.mdline and thesettings.jsonhook under~/.claude.rtk init -g --uninstallremoves them. That is worth a line in the release notes, not code here.
Filed as follow-ups
- #913 (false "No hook installed" warning): the check only looks for the Claude hook. After this PR, a Cursor-only install on a machine that has a
~/.claudedirectory hits it:rtk lsprints the warning and suggestsrtk init -g. Gemini-only installs already get it on develop. Evidence added there. - #4248: after this PR,
--agent cursorsilently ignores--claude-mdand--hook-only, as--agent windsurfand--agent clinealready do on develop.--no-patchstill patches Cursor'shooks.json, also as on develop. These are symptoms of the wayrtk initchooses its target, so #4248 proposes one--agent <name>form with a per-agent list of supported options, rather than one more guard per combination.
Checked and correct — no need to re-verify
- The
install_claude = false, install_cursor = truecase lands in the(false, false, _, _)arm ofrun, which develop already keeps from bailing when Cursor is requested.--opencodeinstalls the plugin and then the Cursor hook. create_dir_allruns only outside dry-run and before the legacy-script migration. A symlinked~/.cursoris followed exactly as develop'satomic_writefollows it. A dangling symlink or a regular file at~/.cursorfails withFailed to create …/.cursor: File exists; develop failed on those too.--agent cursor --uninstallwas already Cursor-only on develop, so install and uninstall now match.--agent claudeand a plain-ginstall exactly the same Claude files as before.--agent cursorno longer writes~/.config/rtk/filters.toml. Only the Claude path generates that template, and--opencodeon its own already skips it on develop, so Cursor now behaves like the other non-Claude installs.
Hypotheses built and dropped
- Reusing #2521's
ensure_parent_dirhere instead ofcreate_dir_all: this belongs to the follow-up that makes all the installers create their directories the same way, so it is not asked of this PR.
Your questions
- "please, let me know if I have to do anything else here" → nothing. I pushed the fixup below, which carries the rebase.
Next
Fixup pushed, then approving:
a2ab981fmerges develop and moves the~/.cursorhunk intosrc/hooks/init/cursor.rsafter theinit.rssplit (#3878).f29882bepins the new tests' environment inside the temp home. WithCLAUDE_CONFIG_DIRexported,default_dry_run_still_installs_claudefailed, and the real install wrotehistory.dbinto the caller'sXDG_DATA_HOME. The commit also checks the dry runs' exit status, adds tests for--agent claudeand--agent cursor --opencode, and corrects the "Cursor hooks (additive, installed alongside Claude Code)" comment ininit::run.
Rounds: 1/3. Threads: 0 open, 0 resolved this round.
|
Not bad: 2 MONTHS AND 11 DAYS to merge it. Good job, what a repo. |
Summary
Two defects made
rtk init -g --agent cursorfail / pollute the home dir:install_claudederived only from!opencode, so it createdRTK.md,CLAUDE.md, and patchedsettings.jsonunder~/.claudein addition to patching.cursor/hooks.json. On machines without~/.claudeit failed outright:Failed to create temp file in ~/.claude: No such file or directory..claudewrites, the Cursor path still failed on a fresh machine becauseinstall_cursor_hooksnever created~/.cursorbeforeatomic_writeplaced its temp file there.Fixes:
install_claudeon the absence of a sibling agent target (Cursor, Windsurf, Cline), so only the default or an explicit Claude target installs Claude Code files.~/.cursor(non-dry-run) before patchinghooks.json.Root cause
src/main.rs,Commands::Inithandler:install_claude = !opencode. Cursor is the only sibling agent that reaches the shared init path (Windsurf/Cline short-circuit earlier inhooks::init::run), so it incorrectly triggered the Claude install branch.src/hooks/init.rs,install_cursor_hooks: wrotehooks.jsonviaatomic_writewithout ensuring the parent directory exists.Fix
Test plan
cargo fmt --all && cargo clippy --all-targets && cargo test --all: pass.tests/init_agent_cursor_test.rs:agent_cursor_dry_run_never_touches_claude: asserts dry-run output contains no/.claude/path and does patch/.cursor/.agent_cursor_real_write_creates_no_claude_dir: non-dry-run install in a tempHOME: exits 0, never creates~/.claude, and writes.cursor/hooks.json.default_dry_run_still_installs_claude: regression: default init still installs Claude Code files.cargo test --bin rtk hooks::init: 169 existing init tests pass (no regression).E2E Validation
Tested locally and providing proofs (Screenshot). All working as expected: