The complete guide to Claude Code. Opus 4.7, Sonnet 4.6, Haiku 4.5. 1M token context window. 27 hook events. 43 production-tested chapters across 6 topical Parts (Foundation, Workflow, Extension, Context Engineering, Advanced, Reference). Three install tiers. CC 2.1.121+ compatible.
Most Claude Code setup failures fall into a dozen buckets, and almost all of them have a diagnostic that takes under a minute. This chapter is organized symptom-first – find your symptom, try the fix.
Purpose: Unblock common setup issues fast Difficulty: Beginner When to use: The install or first session isn’t behaving as expected
claude command not foundSymptom: claude --version returns “command not found” or “no such file.”
Diagnosis:
which claude
echo $PATH
Fix:
claude installed but not on PATH: add the install dir to PATH in ~/.bashrc or ~/.zshrc, then source ~/.bashrc.claude never installed: follow claude.com/claude-code to install the CLI itself. This guide’s installer adds best practices on top of Claude Code; it does not install Claude Code.claude inside WSL, not on Windows. Windows-installed binaries won’t show up in WSL’s PATH by default.Symptom: claude starts, opens a browser to authenticate, but login never completes or returns an error.
Common causes and fixes:
anthropic.com and related domains. Check with curl https://api.anthropic.com/v1/messages -I – if that fails, it’s network.rm -rf ~/.claude/credentials/
claude # will re-prompt for login
claude --bare with ANTHROPIC_API_KEY set instead of OAuth. Useful for CI / SSH sessions.claude in Windows Terminal with WSL tab (WSLg handles the callback cleanly) or fall back to ANTHROPIC_API_KEY.Symptom: A hook in .claude/hooks/*.sh should fire on SessionStart / PreToolUse / etc., but nothing happens. No errors either.
Check 1 – executable bit:
ls -l .claude/hooks/
# Scripts need +x
chmod +x .claude/hooks/*.sh
Check 2 – registered in settings.json:
Hooks are not auto-discovered. They must be registered in settings.json under the right event:
{
"hooks": {
"SessionStart": [
{ "command": "bash ${CLAUDE_PROJECT_DIR}/.claude/hooks/memory-context-loader.sh" }
]
}
}
Typos in the event name (e.g. "session-start" instead of "SessionStart") fail silently. Use exact event names from Part VI/03 — Hook Event Catalog.
Check 3 – stdin pattern, not env vars:
The legacy env-var hook API ($CLAUDE_HOOK_INPUT, $CLAUDE_TOOL_INPUT, $CLAUDE_HOOK_EVENT) is dead. Hooks now receive all data via stdin JSON. If your script reads from env vars, it reads empty strings.
#!/bin/bash
# CORRECT
INPUT=$(timeout 2 cat 2>/dev/null || true)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
Check 4 – portable paths:
Use $CLAUDE_PROJECT_DIR (Claude Code sets this per-session) rather than hard-coded paths. Hard-coded paths break the moment the repo is cloned to a different location.
Check 5 – hook logs:
ls -la ~/.claude/logs/
# Or project-scoped:
ls -la .claude/logs/
Most installed hooks log to .claude/logs/<hookname>.log. Empty or missing log = hook never fired.
Symptom: Added an MCP server to settings.json under mcpServers, but claude mcp list doesn’t show it, and the tools aren’t available.
Cause: In recent Claude Code versions, MCP servers declared in settings.json’s mcpServers block are silently ignored. MCP registration must go through the claude mcp add CLI, which writes to ~/.claude.json.
Fix:
# Remove the mcpServers block from settings.json
# Then register via CLI:
claude mcp add github -- npx -y @modelcontextprotocol/server-github
# Or with env:
claude mcp add github -e GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx -- npx -y @modelcontextprotocol/server-github
# Verify:
claude mcp list
See Part VI/05 — MCP Server Catalog for per-server recipes.
Symptom: Skill exists in ~/.claude/skills/myskill/SKILL.md and /skills shows it, but Claude never invokes it automatically when the trigger situation arises.
Cause 1 – missing trigger clause in description:
Claude auto-invokes skills based on the description field in the skill’s frontmatter. Without an explicit trigger clause (“Use when…”), Claude can’t auto-match.
Bad:
---
name: myskill
description: Does a thing with files.
---
Good:
---
name: myskill
description: Process CSV files into Parquet. Use when user asks to convert data files, reduce CSV size, or prepare data for analytics.
---
Cause 2 – description too short / no keywords:
Description field has a 1536-char limit (was 250 pre-2.1.105). Use the space. Include the keywords Claude will encounter.
Cause 3 – disable-model-invocation: true:
If the frontmatter has disable-model-invocation: true, Claude can’t auto-invoke it – only the user can. This is intentional for side-effect skills (deploys, commits) but often accidental.
Cause 4 – still not triggering:
Check with /skills that the skill is loaded at all. If it’s not, the skill directory name may have the deprecated -skill suffix (use bare names like myskill/, not myskill-skill/).
settings.json silently ignoredSymptom: Edited settings.json, but changes don’t take effect. No errors.
Cause 1 – JSON syntax error:
jq empty .claude/settings.json
# No output = valid JSON
# Error = your problem
Pre-2.1.99 versions would nuke the entire settings file on unrecognized event names. 2.1.99+ is more resilient (unknown keys ignored, rest still loads) – but a JSON syntax error still kills the whole file.
Cause 2 – typo in hook event name:
"hooks": {
"SessionStarts": [ ... ] // BAD: should be "SessionStart"
}
Unknown event names are silently dropped. Always cross-check against the authoritative list in Part VI/03 — Hook Event Catalog.
Cause 3 – scope confusion:
settings.json cascades: ~/.claude/settings.json (global) → <project>/.claude/settings.json (project) → <project>/.claude/settings.local.json (local). Later overrides earlier. If your “setting isn’t working,” check whether a more specific scope is overriding it.
jq not installedSymptom: Installer fails with jq: command not found or similar.
Fix:
# Debian/Ubuntu/WSL2
sudo apt install jq
# macOS
brew install jq
# Arch
sudo pacman -S jq
# Verify
jq --version
The installer uses jq to read manifest.json; it’s a hard dependency.
Symptom: On WSL2, the Chrome MCP server (mcp__claude-in-chrome__*) disconnects mid-session or fails to connect at all.
Cause: Chrome MCP requires a running Chrome with the extension, and the WSL2 ↔ Windows Chrome bridge is unreliable (network isolation, handshake timing).
Fix: use Playwright MCP instead. Playwright runs fully inside WSL and doesn’t need the browser bridge.
claude mcp add playwright -- npx -y @playwright/mcp
The playwright-mcp skill (installed with Recommended tier) wraps common flows (navigate, screenshot, form fill, extract). See Part VI/05 — MCP Server Catalog for setup.
.claude/commands/Symptom: Created .claude/commands/mycommand.md expecting Claude Code to recognize a new slash command, but nothing happens.
Cause: Commands were merged into skills in Claude Code 2.1.88. The commands/ directory is deprecated – new slash commands are authored as skills.
Fix: migrate to skill format.
# Old (don't author this format any more):
# .claude/commands/mycommand.md
# New:
mkdir -p .claude/skills/mycommand
# Move content into .claude/skills/mycommand/SKILL.md
# Add frontmatter with `name` and `description` containing a trigger clause
See the skill-creator plugin or Part III/01 — Skills (when available) for the full authoring guide.
Escalation path:
/doctor/doctor
The doctor skill (Recommended tier) runs a self-diagnostic: checks Claude Code version, config parse, MCP health, hook registration, permissions. If it finds something, it’ll tell you what. Since 2.1.105 the doctor can auto-fix many common issues (press f).
ls -la ~/.claude/logs/ # Claude Code's own logs
ls -la .claude/logs/ # project-scoped hook logs
Look for the most recent file with content. Hook failures often leave a single-line error in their log file that points right at the problem.
# What does Claude Code think is loaded?
# Inside a Claude Code session:
/context # shows context composition
/skills # lists loaded skills
/cost # session cost breakdown
claude mcp list # lists registered MCP servers
Most failure modes encountered by prior sessions are documented. Inside Claude Code:
Search my ~/.claude/rules/ for the error I'm seeing.
Or grep the Basic Memory knowledge graph (Recommended tier with Basic Memory MCP):
Search memory for "hook not firing"
If nothing resolves, the guide’s GitHub issues are the last stop:
github.com/ytrofr/claude-code-guide/issues
Include:
claude --versionsettings.json (sanitized)Keep these handy.
# Claude Code version
claude --version
# What settings are in effect
jq . ~/.claude/settings.json
jq . .claude/settings.json 2>/dev/null
# What MCP servers are registered
claude mcp list
# What hooks are registered
jq '.hooks' .claude/settings.json 2>/dev/null
jq '.hooks' ~/.claude/settings.json
# What rules are installed
ls ~/.claude/rules/
ls .claude/rules/
# What skills are installed
ls ~/.claude/skills/
ls .claude/skills/
# Marker file for this installer
cat .claude-best-practices-installed 2>/dev/null
# jq is present
jq --version
# Node is recent
node --version # should be v18+