docs(install): recommend the native Claude Code installer, warn off sudo-npm (#476) - #552
Conversation
…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.
Cross-model review record
GPT-5.6 Sol
CERTIFIED, confidence 99, bound to Fable
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 guardParked in #551 with its 27-case corpus. Both reviewers converged on dropping it: Fable established that needle coverage is unbounded in principle ( 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 |
Cross-model clearance — GPT-5.6 Sol
|
Cross-model clearance — Fable
|
|
CROSS-MODEL-CLEARANCE Reviewer: GPT-5.6 Sol {"reviewer":"gpt-5.6-sol","verdict":"YES","confidence":99,"sha":"209470042c5f3339588d9031e5906a66d0c33be7"} |
|
CROSS-MODEL-CLEARANCE Reviewer: Fable {"reviewer":"fable","verdict":"YES","confidence":97,"sha":"209470042c5f3339588d9031e5906a66d0c33be7"} |
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 claudeas the conflict check.The footgun this steers off
Observed on a real machine (#476):
sudo npm install -g @anthropic-ai/claude-codeleft the global module directory root-owned. From thereclaude updaterefused with "Insufficient permissions to install update";npm uninstall -gfailed withEACCES, because a normal user cannot rename a root-owned directory; and switching to the native install left twoclaudebinaries onPATH, resolved byPATHorder.which -a claude, notclaude doctorReview ran
claude doctor2.1.221 against a decoy binary placed earlier onPATH. 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 iswhich -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:
The test
test_wizard_prereqs_recommend_native_claude_installis scoped to the## Prerequisitessection, 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, thensudo -u root npm, andas root, run npm install -gnames the same footgun with nosudotoken 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:
sudo[[:space:]]+npmhanded to a Python regex, where[[:space:]]is the character set[ : s p a c eand matches no space. It matched nothing, passed vacuously on every input, and the suite was fully green.while readlist (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
high— 6 rounds. Findings: inverted-recommendation acceptance, semantic bypasses, prose overstatement, a false comment about npm not shipping README (npm pack --dry-runproves it does), and two guard bypasses. CERTIFIED conditional on dropping the parked guard.xhigh— 4 rounds. Findings: theclaude doctorblind spot, first-mention-per-line blindness, a comment overclaiming soundness, needle evasion. CLEAR, zero unresolved.