Skip to content

Moving Claude Code from npm to the Native Installer

As of 2026-09-16, Anthropic's Claude Code setup docs list three install methods: Native Install (Recommended), Homebrew and WinGet. npm sits under "Advanced installation options." Note that an npm global install that happens to live under Homebrew's Node (/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code) is not the Homebrew install. The Homebrew install is the claude-code cask.

The switch itself is one command. What bites is everything else on the machine that launches claude. Long-running helpers, like plugin daemons and editor integrations, keep using the old binary, or look for it where it no longer exists.

What prompted this at MajorsHouse: on MajorM5Pro the npm auto-updater reinstalled the version that was already installed six times in one afternoon, while showing "update waiting" with nothing newer published. The root cause of that loop was not confirmed. It is recorded here only as the reason for the move, not as a diagnosis.

Before you start

1. Confirm what you are actually running:

which -a claude
ls -l "$(which claude)"      # npm installs resolve into .../node_modules/@anthropic-ai/claude-code/...

2. Check PATH order. The native installer puts its launcher in ~/.local/bin, which must come before /opt/homebrew/bin or the old binary keeps winning:

echo "$PATH" | tr ':' '\n' | grep -nE 'homebrew/bin|\.local/bin'

3. Find everything that launches claude. Grep for the package path as well as the launcher. A monitoring script that reads the version straight from .../claude-code/bin/claude.exe won't match a search for /opt/homebrew/bin/claude. We missed one that way the first time.

grep -rlsE '/opt/homebrew/bin/claude|node_modules/@anthropic-ai/claude-code|claude\.exe' \
  ~/Library/LaunchAgents ~/.claude/settings*.json ~/.claude.json \
  ~/.zshrc ~/.zprofile ~/.bashrc ~/.bash_profile ~/.local/bin 2>/dev/null

4. List what is running it right now, and what launched it. Anything long-lived here will need a restart after the switch:

ps -eo pid,ppid,lstart,command | grep -E 'bin/claude|claude --' | grep -v grep
ps -o command= -p <ppid>     # e.g. a bun claude-mem worker, or "Obsidian Helper (Renderer)"

1. Install native alongside npm

Download the script and read it before running it. It fetches the binary from downloads.claude.ai, verifies its SHA-256 against the release manifest, then runs claude install:

curl -fsSL -o install.sh https://claude.ai/install.sh
less install.sh
bash install.sh

Verify:

which -a claude          # should now list only ~/.local/bin/claude (see step 2)
claude --version
claude doctor            # expect: Running: native (...), Config install method: native, No installation issues found

2. The installer removes the npm package for you

You don't need a separate uninstall. The claude install step itself runs npm uninstall --global @anthropic-ai/claude-code, and it shows up as its own entry in ~/.npm/_logs/. A manual npm uninstall -g afterward just reports nothing to do. Confirm it's gone:

ls -l /opt/homebrew/bin/claude                               # No such file or directory
npm ls -g --depth=0 | grep claude-code                       # no output

3. Repoint the things that launch claude

claude-mem

The worker reads CLAUDE_CODE_PATH from ~/.claude-mem/settings.json. Blank means auto-detect, and a worker started before the migration keeps using the path it already found. Set the path explicitly, then restart the worker with its own command:

cp -p ~/.claude-mem/settings.json ~/.claude-mem/settings.json.bak
# set "CLAUDE_CODE_PATH": "/Users/<you>/.local/bin/claude"   (absolute path)
cd ~/.claude/plugins/cache/thedotmack/claude-mem/<version>
bun scripts/worker-service.cjs restart
grep 'Using configured CLAUDE_CODE_PATH' ~/.claude-mem/logs/claude-mem-$(date +%F).log | tail -1

The log line should name ~/.local/bin/claude and its version. ~/.local/bin/claude is a launcher symlink that native updates keep current, so pinning it doesn't pin a version.

Obsidian Copilot (Claude agent backend)

The plugin has no path setting. It looks for the binary in its own override, PATH, the standard system directories and home-relative locations, so it finds ~/.local/bin/claude without help. But its running session keeps the old binary until Obsidian restarts. Restart Obsidian, then confirm:

for p in $(pgrep -f 'Obsidian Helper'); do pgrep -P "$p" -fl claude; done

Anything else step 3 of "Before you start" found

Scripts that read the npm binary for version logging fail quietly. They print unknown, never an error. Point them at ~/.local/bin/claude --version.

4. Restart sessions that started before the switch

The npm binary was deleted, but processes already running from it keep running it. Restart those terminal sessions onto the native binary.

On macOS the login credential stays in the login keychain. The install method does not change where it is stored, so moving to native is not a fix for keychain password prompts (see Related). Our restart onto native raised no prompt.

5. If plugin MCP servers don't come back after the restart

The first new session reported its plugin MCP servers as Skipping connection (recent failure cached …), and no connect attempt appeared in their logs. The previous session's shutdown had needed a SIGKILL for one of them, which is the likely source of that cached failure. Both servers were healthy when probed directly.

  • Run /mcp and reconnect. That fixed it immediately.
  • Otherwise the harness retries by itself after about 15 minutes.

Auto-updates

Native installs update in the background by default, and claude doctor shows the release channel. To turn background checks off, set DISABLE_AUTOUPDATER. Per Anthropic's docs, claude update still works with it set; DISABLE_UPDATES blocks every update path.

Rollback

rm ~/.local/bin/claude && rm -rf ~/.local/share/claude
npm install -g @anthropic-ai/claude-code
# restore ~/.claude-mem/settings.json from the backup (or blank CLAUDE_CODE_PATH), then:
bun ~/.claude/plugins/cache/thedotmack/claude-mem/<version>/scripts/worker-service.cjs restart
# restart Obsidian and any terminal sessions