Skip to content

fix: rtk init -g --agent cursor fails when ~/.claude directory is missing - #3014

Closed
mvanhorn wants to merge 1 commit into
rtk-ai:developfrom
mvanhorn:fix/3009-init-agent-missing-claude-dir
Closed

mvanhorn wants to merge 1 commit into
rtk-ai:developfrom
mvanhorn:fix/3009-init-agent-missing-claude-dir

Conversation

@mvanhorn

Copy link
Copy Markdown
Contributor

Summary

The single choke point is atomic_write(path, content) in src/hooks/init.rs: it computes parent = target.parent() and immediately calls NamedTempFile::new_in(parent), which returns os error 2 when parent does not exist. Every other write site in this file already calls fs::create_dir_all(...) before writing (e.g.

Why this matters

Running rtk init -g --agent cursor (global install targeting Cursor) crashes with Failed to write RTK.md: .../.claude/RTK.md: Failed to create temp file in .../.claude: No such file or directory (os error 2) whenever the user does not already have a ~/.claude directory. It is reproduced on rtk 0.43.0 on macOS 15.7.3, macOS 26.5.1, and Arch Linux by three separate reporters. The reporter confirms that manually creating a .claude directory makes the command succeed, so the failure is purely the missing parent directory. Because the global default path also installs Claude Code awareness files (Cursor hooks are additive on top of Claude Code) and fails fast on that first write, the Cursor portion never runs.

Testing

  • Happy path: atomic_write (or global default init via a temp CLAUDE_CONFIG_DIR whose .claude subdir does not yet exist) creates the missing parent directory and writes the file successfully, mirroring the existing test_default_mode_creates_rtk_md pattern.
  • Idempotence / existing dir: writing when the parent directory already exists still succeeds and overwrites atomically (no regression to the existing atomic-rename behavior or the write_if_changed no-op-when-unchanged path).
  • Error path: writing to a path with no parent (root) still returns the existing "path has no parent directory" error, and a genuinely unwritable parent still surfaces a contextual error rather than panicking.

Fixes #3009

AI was used for assistance.

@pszymkowiak

Copy link
Copy Markdown
Collaborator

Thanks for the fix and the thorough write-up — the root-cause analysis of atomic_write is spot on, and I confirmed the fix resolves the crash. Before merging, I want to flag a design concern, because as it stands this PR makes the crash disappear by doubling down on behavior that arguably shouldn't happen.

The problem: rtk init -g --agent cursor installs a Claude Code integration. I verified this empirically by running the PR binary against a fresh HOME with no ~/.claude:

File created When
~/.claude/RTK.md always
~/.claude/CLAUDE.md (patched with @RTK.md) always
~/.claude/settings.json (hook rtk hook claude) on consent (--auto-patch / interactive y)
~/.cursor/hooks.json (rtk hook cursor) always — the only Cursor-native artifact

None of the ~/.claude/* files are read by Cursor. So a user who asked for Cursor gets Claude Code awareness files (and, with auto-patch, a wired-up Claude hook) they never requested.

This traces to install_claude = !opencode (main.rs:2034) combined with Cursor not being intercepted before the default mode (init.rs:308-311) — unlike Windsurf/Cline. It's inconsistent with every other non-Claude agent, all of which are standalone and never touch ~/.claude:

Agent Writes Touches .claude?
Cline .clinerules ❌
Windsurf .windsurfrules ❌
Kilo Code .kilocode/rules/rtk-rules.md ❌
Codex AGENTS.md ❌
Cursor (this PR) .claude/RTK.md + CLAUDE.md (+ settings.json) ✅

The issue reporter said it themselves: "--agent cursor is completely ignored" — their real complaint is that a Cursor install populates ~/.claude. Fix A turns the crash into silent ~/.claude writes rather than fixing the surprising behavior.

Suggested alternative (Fix B): intercept Cursor before the Claude default path, matching Windsurf/Cline — e.g.

// main.rs
let install_claude = !opencode && agent != Some(AgentTarget::Cursor);

or add an else if install_cursor { install_cursor_hooks(ctx)?; } branch in the init.rs:308 chain. That installs only ~/.cursor/hooks.json, creates no Claude files, and still fixes #3009 — closer to what the reporter expects.

Separate gap: hooks/cursor/ has no native awareness doc, so today Cursor gets the hook but no instructions (awareness was piggybacking on ~/.claude/RTK.md, which Cursor can't read). A complete fix would add a Cursor-native awareness file (e.g. ~/.cursor/rules/ or AGENTS.md).

The atomic_write + create_dir_all change and its tests are genuinely good and worth keeping regardless. My only ask is that the Cursor routing be fixed so we don't install Claude Code for Cursor users. Happy to help.

@mvanhorn

Copy link
Copy Markdown
Contributor Author

Appreciate it @pszymkowiak — thanks for the thorough review.

@edurenye

Copy link
Copy Markdown

I think there is already another PR to fix this: #3000

@mvanhorn

Copy link
Copy Markdown
Contributor Author

Good catch, thanks. #3000 does cover the same failure (the 'Failed to create temp file in ~/.claude' error) and goes further by keeping cursor installs from touching ~/.claude at all. Closing this one in favor of #3000.

@mvanhorn mvanhorn closed this Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wont install for Cursor - trys to install Claude v 0.43.0

3 participants