Skip to content

docs(install): recommend the native Claude Code installer, warn off sudo-npm (#476) - #552

Merged
BaseInfinity merged 1 commit into
mainfrom
fix/476-native-install-recommendation
Aug 10, 2026
Merged

docs(install): recommend the native Claude Code installer, warn off sudo-npm (#476)#552
BaseInfinity merged 1 commit into
mainfrom
fix/476-native-install-recommendation

Conversation

@BaseInfinity

Copy link
Copy Markdown
Owner

Closes #476.

What

The wizard documented how to install itself and never how to install Claude Code, the CLI it runs on. Adds a Prerequisites block naming the native installer as the recommended path, one README sentence, and which -a claude as the conflict check.

The footgun this steers off

Observed on a real machine (#476): sudo npm install -g @anthropic-ai/claude-code left the global module directory root-owned. From there claude update refused with "Insufficient permissions to install update"; npm uninstall -g failed with EACCES, because a normal user cannot rename a root-owned directory; and switching to the native install left two claude binaries on PATH, resolved by PATH order.

which -a claude, not claude doctor

Review ran claude doctor 2.1.221 against a decoy binary placed earlier on PATH. It reported no conflict — precisely the PATH-shadowing case the prose describes. The remediation I first wrote would have masked the exact failure it existed to catch. The official docs' own procedure is which -a claude; doctor stays for install health with its blind spot stated.

Claims scoped to what is actually documented

Every factual claim was checked against Anthropic's setup docs by both reviewers:

  • sudo can leave the directory root-owned, not does — the docs say "can lead to permission issues"
  • the compounding failures are attributed as observed on one machine, not asserted as guaranteed
  • a non-sudo npm install stops auto-updating "with only a one-time notice at startup", not silently — the docs state a notice is shown

The test

test_wizard_prereqs_recommend_native_claude_install is scoped to the ## Prerequisites section, not the file. Asserting a string appears somewhere in 4,900 lines is the #493 failure mode, and this doc already names the installer in an unrelated aside about version pinning.

It asserts three things, each RED-proven: the install command is present; it is described as recommended; and no negation reaches it. That third one exists because an earlier version asserted only the URL — flipping the prose to "Do not use the native installer" while keeping the URL still passed. The guard proved a string, not a stance.

What was dropped, and why

A companion guard asserting no doc instructs sudo-npm is parked in #551. It cannot be "the string must not appear", since the warning has to quote the command it warns about, so it had to tell a warning from an instruction. Six rounds, two reviewers, three rewrites of the rule — each broken by a sentence nobody had thought of, ending with the rule converging but its needle not converging: sudo -E npm, then sudo -u root npm, and as root, run npm install -g names the same footgun with no sudo token at all.

Dropped under the PROCESS BUDGET rule from #531 — a test may not cost more review rounds than the change it guards, and this issue asked for ~20 documentation lines. Both reviewers agree the documentation ships without it: GPT-5.6 chose the deletion explicitly and certified conditional on it.

Two findings from that work outlived the guard and are recorded in #551 and #550:

  1. The guard was once completely deadsudo[[:space:]]+npm handed to a Python regex, where [[:space:]] is the character set [ : s p a c e and matches no space. It matched nothing, passed vacuously on every input, and the suite was fully green.
  2. A local suite harness silently ran 30 of 65 suites and reported success, because a test script consumes stdin and ate the rest of a while read list (Local 'all suites green' claims are unreliable: a test script eats stdin in a while-read loop #550).

A check that cannot fail is worse than no check, and the only thing that reliably found these was mutating the shipped artifact and watching it go red.

Verification

Review

  • GPT-5.6 Sol high — 6 rounds. Findings: inverted-recommendation acceptance, semantic bypasses, prose overstatement, a false comment about npm not shipping README (npm pack --dry-run proves it does), and two guard bypasses. CERTIFIED conditional on dropping the parked guard.
  • Fable xhigh — 4 rounds. Findings: the claude doctor blind spot, first-mention-per-line blindness, a comment overclaiming soundness, needle evasion. CLEAR, zero unresolved.

…udo-npm (#476)

The wizard documented how to install ITSELF and never how to install Claude
Code, the CLI it runs on. A real machine hit the footgun the official setup
docs warn about: `sudo npm install -g @anthropic-ai/claude-code` can leave the
global module directory root-owned, and from there `claude update` refused with
"Insufficient permissions to install update", `npm uninstall -g` failed with
EACCES, and switching to the native install left two `claude` binaries on PATH
resolved by PATH order.

Adds a Prerequisites block naming the native installer as the recommended path
and one README sentence, plus `which -a claude` as the conflict check.

`which -a claude`, not `claude doctor`: review ran doctor against a decoy binary
placed earlier on PATH and it reported no conflict — precisely the PATH-shadowing
case the prose describes. The docs' own procedure is `which -a`. Doctor stays for
install health, with its blind spot stated.

Claims are scoped to what the official docs actually say. Sudo "can leave" the
directory root-owned rather than does; the compounding failures are attributed as
observed on one machine; a non-sudo npm install stops auto-updating "with only a
one-time notice at startup" rather than silently.

test_wizard_prereqs_recommend_native_claude_install is scoped to the
Prerequisites section rather than the whole file, because asserting a string
appears somewhere in 4,900 lines is the #493 failure mode. It requires the
command, the recommendation, and the absence of a negation on it — an earlier
version asserted only the URL and passed when the prose was flipped to "Do not
use the native installer".

A companion guard asserting no doc INSTRUCTS sudo-npm is parked in #551. It cost
six review rounds: the rule converged, but its needle cannot — "as root, run npm
install -g" names the same footgun with no sudo token in it. Dropped under the
PROCESS BUDGET rule from #531, with both reviewers agreeing the documentation
ships without it.
@BaseInfinity

Copy link
Copy Markdown
Owner Author

Cross-model review record

.reviews/ is gitignored, so this comment is the durable record.

GPT-5.6 Sol high — 7 rounds. Findings across the dialogue: the Prerequisites test accepted an inverted recommendation (URL present, prose flipped to "Do not use the native installer" — still green); two semantic bypasses of the sudo guard; prose overstating what Anthropic documents; a false comment claiming npm does not ship README (npm pack --dry-run proves it does); and two further guard bypasses. On being asked for a terminal decision it chose to drop the guard — "the semantic space is unbounded, and the repo's positive-anchor test is sufficient regression coverage for the requested documentation stance" — and certified conditional on that deletion. Rebound to the PR head after commit:

No findings. Exact three-file diff; deleted guard, helper, and negbind.py are absent. One commit; branch and worktree clean; PR head matches. Both required mutations went RED; restored baseline is 130/0. Non-E2E suites: 65/65. ShellCheck unchanged, zero findings in the added block. Permanent claims verified against Anthropic's setup and troubleshooting docs, live claude doctor 2.1.221 decoy testing, npm pack --dry-run, issue #476, and the recorded reviewer clearances.

CERTIFIED, confidence 99, bound to 2094700.

Fable xhigh — 4 rounds, CLEAR, zero unresolved. Its findings drove most of the prose:

  • claude doctor does not detect the failure the doc told readers to use it for. It ran doctor 2.1.221 with a decoy claude earlier on PATH and got a clean report — precisely the PATH-shadowing case the prose describes. The remediation as first written masked the exact failure it existed to catch. which -a claude is the docs' own procedure and is what shipped.
  • "silently stops auto-updating" overstated; the docs state a one-time startup notice is shown.
  • A comment overclaiming that a guard was sound.

Fable's clearance was issued against the superset diff that still carried the sudo guard. The shipped diff is a strict subset of it — the guard removed — and GPT-5.6 chose and certified that removal explicitly, so no leg of the evidence covers less than what shipped.

On the dropped guard

Parked in #551 with its 27-case corpus. Both reviewers converged on dropping it: Fable established that needle coverage is unbounded in principle (as root, run npm install -g names the same footgun with no sudo token), and GPT-5.6 chose deletion when asked to decide. It was dropped under the PROCESS BUDGET rule shipped in #531 — a test may not cost more review rounds than the change it guards.

Recorded plainly because it is the useful part: this PR's review went six rounds on a ~20-line documentation change, which is the circling behaviour milestone v1.97.0 exists to eliminate. The rule that ends it had already merged and was not applied. Rounds 1–4 bought real defects — a guard that matched nothing and passed vacuously, a false claude doctor claim, a false npm-README claim. Rounds 5–6 bought spellings of sudo. The budget should have cut between those.

@BaseInfinity

Copy link
Copy Markdown
Owner Author

Cross-model clearance — GPT-5.6 Sol high, 7 rounds

Rebound to the PR head after commit. It verified the three-file diff, confirmed the dropped guard and helper are absent, re-ran both RED mutations on the surviving test, and fact-checked the permanent commit-message and PR-body claims against Anthropic's setup and troubleshooting docs, live claude doctor 2.1.221 decoy testing, and npm pack --dry-run.

{"reviewer":"gpt-5.6-sol","verdict":"YES","confidence":99,"sha":"209470042c5f3339588d9031e5906a66d0c33be7"}

@BaseInfinity

Copy link
Copy Markdown
Owner Author

Cross-model clearance — Fable xhigh, 5 rounds

Reviewed the diff that actually ships, not the superset it cleared earlier — the guard was dropped after its round 4, so this is a different artifact.

Asked specifically whether the surviving test's third assertion, now a single grep where a module used to be, is a weaker check wearing the old one's clothes. It compared the two directly on every divergence it could construct:

The grep is identical-or-more-paranoid everywhere I probed, and it closes the only attack ever made against this test. On litotes ("Don't forget to use the native installer") the grep goes RED where the old rule was green. On the comma-smuggled inversion the grep is false-green — and I verified the dropped negbind rule was false-green on the same sentence. Shared hole, adversarial class, both disclosed.

All three assertions mutation-proven independently. Docs verified by blob identity (4b32df3, 855f7a8) against the tree whose every prose fact it had already checked against Anthropic's setup and troubleshooting docs. CI validate confirmed via the GitHub API on this exact head SHA rather than on assertion.

On the drop itself: "I endorse it. It is my own round-3 position carried to its conclusion — needle-widening was tripwire extension, never soundness, and the spelling surface is unbounded."

{"reviewer":"fable","verdict":"YES","confidence":97,"sha":"209470042c5f3339588d9031e5906a66d0c33be7"}

@BaseInfinity

Copy link
Copy Markdown
Owner Author

CROSS-MODEL-CLEARANCE

Reviewer: GPT-5.6 Sol high, 7 rounds. Rebound to the PR head after commit; verified the three-file diff, confirmed the dropped guard and helper are absent, re-ran both RED mutations on the surviving test, and fact-checked the permanent commit-message and PR-body claims against Anthropic's setup and troubleshooting docs, live claude doctor 2.1.221 decoy testing, and npm pack --dry-run.

{"reviewer":"gpt-5.6-sol","verdict":"YES","confidence":99,"sha":"209470042c5f3339588d9031e5906a66d0c33be7"}

@BaseInfinity

Copy link
Copy Markdown
Owner Author

CROSS-MODEL-CLEARANCE

Reviewer: Fable xhigh, 5 rounds. Reviewed the diff that actually ships rather than the superset it cleared earlier. Compared the surviving test's grep against the machinery it replaced and found it identical-or-more-paranoid on every divergence probed; all three assertions mutation-proven independently; docs verified by blob identity against the tree whose prose it had already fact-checked; CI validate confirmed via the GitHub API on this head SHA.

{"reviewer":"fable","verdict":"YES","confidence":97,"sha":"209470042c5f3339588d9031e5906a66d0c33be7"}

@BaseInfinity
BaseInfinity merged commit 55a06cc into main Aug 10, 2026
4 checks passed
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.

Recommend native install for Claude Code CLI (avoid sudo-npm footgun)

1 participant