Claude Code Fundamentals
Claude Code is a command-line tool from Anthropic that reads your codebase, edits files, runs shell commands, and iterates on its own until a task is done. It is easy to mistake it for a fancier autocomplete — type a comment, get a function — but that mental model will actively mislead you. Autocomplete predicts the next few tokens from the file you're looking at. Claude Code runs a loop: it decides what to do, does it with a real tool (a file read, a shell command, a search), looks at the actual result, and decides what to do next. It keeps looping until the task is done or it needs you.
This distinction is the spine of everything in this subject. Once you understand the loop, the built-in tools, and the permission system that governs what the loop is allowed to do without asking you, the rest of Claude Code's behavior — why it re-reads a file after editing it, why it runs your test suite unprompted, why it sometimes stops to ask for approval — stops looking mysterious and starts looking mechanical.
Autocomplete vs. an Agent
| Inline autocomplete (e.g. classic Copilot-style completion) | Claude Code (agentic) | |
|---|---|---|
| Input | The current file, cursor position | Your natural-language request, plus whatever it chooses to read |
| Action | Predicts next tokens | Chooses and executes tools: read, search, edit, run commands |
| Feedback | None — it doesn't see if the code runs | Sees command output, test results, error messages, and reacts to them |
| Scope | One file, one cursor position | Any number of files, plus your terminal, plus git |
| When it stops | After emitting a suggestion | After the task is verified as done, or when it needs your input |
The key difference is the feedback loop. An autocomplete engine has no way of knowing whether the code it just suggested compiles, passes tests, or even matches the rest of the file it's editing beyond local pattern-matching. Claude Code, by contrast, can run pytest, see a failure, read the traceback, find the offending function, fix it, and re-run the tests — all without you doing anything in between. That loop, repeated as many times as needed, is what "agentic" means in practice.
Installing and Starting a Session
Claude Code runs from your terminal (it's also available as a VS Code extension, a desktop app, and a web interface, but the terminal CLI is the reference experience and what this subject focuses on).
Install (macOS, Linux, WSL):
curl -fsSL https://claude.ai/install.sh | bash
Windows has PowerShell and CMD equivalents, and Homebrew (brew install --cask claude-code) and WinGet installs are also available. Confirm the install with:
claude --version
Start a session by running claude inside a project directory:
cd your-project
claude
On first use you'll be prompted to log in (or, if you've set an ANTHROPIC_API_KEY environment variable, to approve using that key instead). Once authenticated, you're dropped into an interactive prompt scoped to that directory — Claude Code reads project files as needed rather than requiring you to manually attach them.
From here you type requests in plain English:
what does this project do?
there's a bug where users can submit empty forms — fix it
You don't pre-select files or paste code. Claude Code figures out what's relevant by exploring — which is exactly the loop we cover next.
Surfaces at a Glance
Everything in this subject — the loop, the built-in tools, the permission modes — is identical no matter where you run Claude Code. What changes across surfaces is only where the code executes and how you see and interact with it, not the underlying mechanics:
| Surface | What it is |
|---|---|
| Terminal (CLI) | The reference experience — everything in this subject is written against it |
| VS Code / JetBrains extensions | The same agentic loop inside your editor, with inline diff review |
| Desktop app | A standalone app for managing multiple sessions, including background tasks |
| claude.ai/code (web) & mobile | Cloud-hosted sessions you can start from a browser or phone, useful when you don't have your laptop |
| Remote Control | Drive a session that's running (and keeping its files) on your own machine, from a browser |
| Slack | Kick off and follow Claude Code work from inside a conversation |
| CI/CD (e.g. GitHub Actions) | Non-interactive runs triggered by your pipeline instead of a human typing prompts |
This subject sticks to the terminal because it's where the gather → act → verify mechanics are easiest to observe directly, one tool call at a time. A full comparison of every surface — including a decision table for which one to reach for — lives in claude-code-platforms-and-interfaces.
The Agentic Loop
Every task Claude Code performs runs through three phases that repeat until the task is complete:
┌─────────────────────────────────────────────────────┐
│ │
▼ │
┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ GATHER │───────▶│ TAKE │───────▶│ VERIFY │───────┘
│ CONTEXT │ │ ACTION │ │ RESULTS │
└───────────┘ └───────────┘ └───────────┘
search, read edit, run run tests,
files, grep commands re-read output
│
▼
done? ──▶ report to you
not done? ──▶ loop again
- Gather context: Claude decides it needs to know something — what a function does, where a symbol is used, what the test output says — and calls a read-only tool (file read, search) to find out.
- Take action: armed with that context, it calls a tool that changes state — editing a file, running a build, staging a git commit.
- Verify results: it looks at what actually happened — did the edit apply cleanly, did the test pass, did the command exit 0 — and decides whether the task is done or whether it needs another pass.
These phases aren't rigid steps executed once each — they interleave. A single bug fix might gather context, take a small action, verify, discover something new, gather more context, and take another action, several times over. Each tool call's result feeds back into what the model decides to do next. This is the mechanical definition of "agentic": the next action is a function of the last observation, not a fixed script.
You are not locked out of this loop. You can interrupt at any point — stop Claude mid-task, redirect it ("actually, the bug is in the session handling, not the login form"), or add context it's missing. Claude Code is built to be steered mid-flight, not just launched and left alone.
A subtlety worth internalizing: sessions don't share memory by default
Each new session starts with a fresh context window — it does not remember yesterday's conversation. What does persist across sessions is whatever you write into a CLAUDE.md file in your project root (read at the start of every session) and "auto memory" that Claude saves on its own as it learns things about your project. If you want Claude to consistently know something ("we use pnpm, not npm" / "never touch the legacy/ folder"), put it in CLAUDE.md — don't rely on having mentioned it three sessions ago.
The Built-in Tools
The loop is only as capable as the tools available to it. Claude Code ships with a set of built-in tools that fall into a few functional categories. The five you'll see doing the real work in almost every task:
| Tool | Category | What it does | Typical use |
|---|---|---|---|
| Read | File operations | Reads a file's contents (with line numbers) | Understanding a function before changing it |
| Edit | File operations | Makes a targeted, exact string replacement in an existing file | Fixing a bug, changing a config value |
| Write | File operations | Creates a new file, or fully overwrites an existing one | Scaffolding a new module |
| Bash | Execution | Runs a shell command in your environment | Running tests, installing deps, git operations |
| Grep | Search | Searches file contents for a pattern (regex, powered by ripgrep) | "Where is validateEmail called?" |
| Glob | Search | Finds files by name pattern (**/*.test.ts) |
"Which files are test files?" |
Two mechanical details worth knowing because they explain behavior you'll otherwise find confusing:
- Edit requires a prior Read. Claude Code generally won't blindly edit a file it hasn't looked at in the current conversation — it reads first (or the read requirement is satisfied by having viewed the file another way), so the edit is grounded in the file's actual current contents rather than a guess. This is why you'll often see Claude read a file immediately before editing it, even if it just wrote that file a moment ago.
- Edit is exact-string replacement, not a diff or regex. It replaces one exact snippet of text with another. If the snippet it's trying to match doesn't appear verbatim (whitespace included) or appears more than once without disambiguating context, the edit fails and Claude has to try again with a more precise match. This is a deliberate safety property: Claude cannot silently "sort of" apply a change — the old text has to genuinely be there.
Beyond these core five, Claude Code has tools for fetching web pages and running web searches (useful for looking up library documentation or error messages), and for spawning subagents — sub-conversations with their own separate context window that go off, do a scoped task, and report back a summary without cluttering the main conversation. You don't need to invoke any of this yourself; the model chooses which tool to reach for based on what the task needs.
Worked example: what "fix the failing tests" triggers
Given a prompt like "fix the failing tests," a plausible tool sequence looks like:
1. Bash → run the test suite, see which tests fail
2. Read → open the source file the failing test exercises
3. Grep → search for other places that call the broken function
4. Edit → apply a fix to the source file
5. Bash → re-run the test suite
6. (loop back to 2–5 if still failing)
7. report → summarize what was wrong and what changed
Nothing here is scripted in advance — this is simply the sequence that emerges from the loop: each tool's result (which tests failed, what the code looks like, whether the fix worked) determines the next tool call.
Permission Modes: the Safety/Autonomy Tradeoff
Giving a model the ability to run arbitrary shell commands and edit arbitrary files is powerful and also genuinely risky — a misunderstood instruction or a bad inference can delete the wrong file or run a destructive command. Claude Code's answer to this is permission modes: a setting that controls how much Claude can do without stopping to ask you first. You cycle through modes during a session (in the terminal, with Shift+Tab), and you can also set a default for a whole project.
| Mode | What runs without asking | When to use it |
|---|---|---|
Auto (auto) |
Everything — reads, edits, and shell commands — reviewed in the background by a separate classifier model instead of prompting you | The default starting mode on Pro, Max, and Team plans; hands-off work where you trust the general direction |
Manual (default) |
Reads only — Claude asks before every file edit and shell command | Reviewing every action yourself; sensitive or unfamiliar codebases; the default on Enterprise plans and Console API keys |
Accept edits (acceptEdits) |
Reads, file edits, and common filesystem commands (mkdir, mv, cp, etc.) inside your project |
Iterating quickly on code you'll review afterward with git diff |
Plan (plan) |
Reads and exploration only — Claude researches and proposes a plan but makes no edits until you approve it | Understanding a large or unfamiliar change before committing to it |
| Bypass permissions | Everything, with no prompts and no safety checks at all | Isolated containers/VMs only — never your primary machine |
A note on Auto mode, since it's what most new sessions actually start in today: instead of asking you before an action, a separate model (the classifier) reviews each action in the background and blocks a defined set of risky categories — force-pushes, production deploys and migrations, curl | bash-style remote code execution, mass deletions, and similar — while letting routine local work (reading, editing files in your project, installing declared dependencies) proceed without interrupting you. It's easy to assume Manual is still "the normal mode" because it's the most cautious one, but on Pro, Max, and Team plans, Auto is now the built-in starting mode for terminal and VS Code sessions; Manual remains the default on Enterprise plans and for Console API keys. Either way, the underlying idea is the same as every mode in this table: someone or something checks actions that leave your local sandbox before they run. You're not "turning off safety" by staying in Auto — you're trading a human checkpoint for a model checkpoint. The classifier's exact rules, and how an organization tunes them, are their own topic — covered in depth in settings-permissions-and-hooks.
Why this tradeoff exists
The dimension that actually matters here is reversibility. File edits inside your working directory are cheap to review and cheap to undo — Claude Code snapshots files before editing them specifically so you can revert. A git push --force, a production database migration, or a curl | bash that executes an arbitrary remote script are a different category: hard or impossible to undo, and their blast radius reaches outside your local sandbox. This is why every mode described above — even the most permissive ones — treats a category of destructive or externally-visible actions specially and still prompts (or routes through the classifier) for those, rather than ever making them silently automatic.
Practical default: start new or unfamiliar work in Manual or Plan mode so you can watch what Claude decides to do before trusting it, and switch to Accept Edits once you've built confidence that its plan of attack is sound. Reserve Bypass Permissions for a disposable container where nothing Claude could do would touch anything you care about.
Checkpoints: Undoing What the Loop Did
Permission modes control whether an action happens at all. Checkpoints are the complementary safety net for the actions that do happen: before Claude edits a file, Claude Code snapshots the file's current contents. If an edit turns out to be wrong, you don't have to manually reconstruct what it looked like before.
Press Esc twice with an empty prompt, or run /rewind, to open the rewind menu. It lists every prompt you sent this session; pick a point and choose:
- Restore code and conversation — revert both to that point
- Restore conversation — rewind the conversation, keep the current code
- Restore code — revert file changes, keep the conversation
- Summarize from/up to here — compress part of the conversation to free up context, without touching anything on disk
Checkpoints vs. git
It's tempting to treat /rewind as a universal "undo" and stop thinking about it — but it has real limits worth knowing before you rely on it:
- It only tracks Claude's own file-editing tools (Edit/Write). If Claude ran a Bash command that changed files —
rm file.txt,mv old.txt new.txt,cp source.txt dest.txt— those changes are invisible to checkpointing./rewindcannot undo them; that's agit checkout/git revertjob. - Subagent edits usually aren't restored either. A subagent generally edits files outside your session's checkpoint tracking, so reverting its changes is, again, a git job.
- It has no idea about anything outside your filesystem. A database migration, an API call, a production deploy — checkpoints cover local file state only. This is exactly why permission modes still gate those actions separately, as covered above: checkpointing can't be the safety net for something it can't see.
- It's session-scoped recovery, not permanent history. Checkpoints exist for quick, in-session (or resumed-session) recovery — they are explicitly not a replacement for version control.
The practical rule: checkpoints are a fast, low-friction undo for "that last edit (or few) was wrong" during an active session. Git is still what you rely on for anything durable, anything outside file edits, or anything you want recoverable weeks later. Committing your work at sensible points is not optional just because /rewind exists.
Two More Dials: Output Styles and Fast Mode
Two other session-level settings are worth knowing the shape of, even though the full treatment belongs elsewhere:
Output styles change how Claude communicates — tone, role, response format — by modifying the system prompt. They don't change what Claude knows about your project (that's CLAUDE.md's job) or the mechanics of the agentic loop itself; a session in the "Explanatory" output style still gathers context, takes action, and verifies results exactly as described above, it just narrates more of its reasoning while doing so. Built-in styles include Default (the ordinary software-engineering behavior used throughout this subject), Explanatory, Learning, and Proactive. Set one with /config → Output style, or by setting the outputStyle field directly in a settings file. Custom styles, and the full comparison against CLAUDE.md, skills, and --append-system-prompt, are covered in claude-code-platforms-and-interfaces.
Fast mode (/fast) is a research-preview toggle that makes Opus respond faster in exchange for a higher per-token price. It is not a switch to a smaller or cheaper model — you get the same Opus model and quality, just lower latency, which makes it a fit for live debugging or rapid iteration and a poor fit for cost-sensitive batch work. Toggling it doesn't change anything about the loop or the tools available; it only changes how quickly responses come back. The cost tradeoffs and when they're worth it are covered in claude-code-models-cost-and-context.
Where Configuration Lives
Claude Code's settings — including permission rules — live in a settings.json file, and which one applies depends on scope:
| Scope | Location | Applies to | Typically committed to git? |
|---|---|---|---|
| User | ~/.claude/settings.json |
You, across every project | No |
| Project | .claude/settings.json |
Everyone who checks out this repo | Yes |
| Local | .claude/settings.local.json |
You, in this repo only | No (gitignored) |
| Managed | Deployed by an organization | Everyone in the org, cannot be overridden | Yes (IT-managed) |
Project-level settings are the important one for a team: because .claude/settings.json is checked into version control, it's how a team agrees on shared rules — "everyone's Claude Code instance is allowed to run npm test without asking" — rather than each engineer configuring their own machine by hand.
The permission rule format
Inside settings.json, a permissions block declares rules that pre-approve or block specific actions, independent of whichever mode is active:
{
"permissions": {
"allow": [
"Bash(npm run test *)",
"Bash(npm run lint)"
],
"deny": [
"Bash(curl *)",
"Read(./.env)",
"Read(./secrets/**)"
]
}
}
allowrules mean Claude executes that exact action without prompting, in any mode.denyrules block an action outright — Claude cannot perform it, period, and deny always wins over an allow rule if both could match.- An implicit
askbehavior (prompt every time) is the fallback for anything not explicitly allowed or denied.
Notice the shape: rules are scoped to a specific command pattern (Bash(npm run test *)) or a specific path pattern (Read(./secrets/**)), not a blanket "allow everything" toggle. This is the same reversibility principle from the permission-modes section, applied at a finer grain: you can tell Claude Code "you may always run the test suite" without also saying "you may always run any shell command," and you can block reads of your .env file even in a mode that would otherwise auto-approve file operations.
Worked Mental Model: Fixing a Bug, Turn by Turn
Let's put the loop, the tools, and permissions together with a concrete walkthrough. Suppose you type:
"Users can submit the signup form with an empty email field — fix it."
Here is a plausible, mechanistically accurate trace of what happens next, assuming Manual mode (so each state-changing step prompts for approval):
Turn 1 — GATHER CONTEXT
Tool: Grep pattern="signup" → finds src/forms/signup.ts, src/api/users.ts
Tool: Read src/forms/signup.ts → sees the form component and its submit handler
Model's reasoning: "the submit handler doesn't check for an empty email
before calling the API — the validation is missing, not broken."
Turn 2 — GATHER MORE CONTEXT
Tool: Grep pattern="validate" → finds src/forms/validators.ts already
has a validateEmail() helper used elsewhere, but signup.ts never imports it.
Model's reasoning: "reuse the existing validator instead of writing a new one."
Turn 3 — TAKE ACTION
Tool: Edit src/forms/signup.ts → imports validateEmail, calls it before
the API request, blocks submission and shows an error if it fails.
[Permission prompt: approve this edit? → you approve]
Turn 4 — VERIFY
Tool: Bash npm test -- signup → one new-looking assertion fails:
the existing test suite has no test for the empty-email case.
Model's reasoning: "the fix is applied but unverified — add a regression test."
Turn 5 — TAKE ACTION
Tool: Edit src/forms/signup.test.ts → adds a test case for empty email.
[Permission prompt: approve? → you approve]
Turn 6 — VERIFY
Tool: Bash npm test -- signup → all tests pass.
Turn 7 — REPORT
Claude summarizes: what was broken, what changed, which files, and that
tests now pass. No further tool calls — task considered complete.
Notice what makes this "agentic" rather than a single autocomplete-style suggestion: turn 4 discovered a gap (no regression test existed) that wasn't part of your original request, and the loop adapted — it added a step you didn't ask for because verification revealed it was needed. That adaptive branching, driven by real command output rather than a fixed script, is the entire point of the loop.
Also notice where the human sits in this trace: you weren't asked to approve the reads or the searches (Manual mode auto-approves those; they're read-only, so they carry no risk), but you were asked before both edits — you're the checkpoint on anything that changes files. That's the permission system from the previous section, operating exactly as designed.
Common Beginner Mistakes
Treating it like autocomplete and micromanaging file-by-file. If you find yourself opening the file first, deciding exactly which lines to change, and then dictating the edit almost like you'd write a diff yourself, you're not using the agentic loop — you're using Claude Code as an expensive typist. Give it the outcome you want and the relevant symptom or context, and let context-gathering do its job:
- Weak: "In
signup.tsline 42, add anifstatement checkingemail.length > 0before line 45." - Strong: "Users can submit the signup form with an empty email — find and fix it, and add a test."
Not reviewing diffs before they land. Accept Edits mode (and auto mode) exist to reduce prompt fatigue, not to remove your judgment from the loop. The verification step in the agentic loop checks that tests pass and commands succeed — it does not check that the change is the one you actually wanted, or that it's stylistically consistent with the rest of your codebase. Get in the habit of running git diff (or asking Claude to summarize what changed) before you consider a task genuinely done, especially in a mode that doesn't prompt per edit.
Granting overly broad permissions out of prompt fatigue. It's tempting to write "allow": ["Bash(*)"] the first time approval prompts feel repetitive. This defeats the entire reversibility argument from the permissions section: a blanket Bash allow doesn't distinguish between npm test and rm -rf. Prefer narrow, specific allow rules (Bash(npm run test *)) that name exactly the trusted commands, and let genuinely novel or destructive actions still prompt.
Forgetting that sessions don't carry memory forward. If you explained an important constraint in a session three days ago and it's not in CLAUDE.md, a fresh session has no idea about it. Persistent instructions belong in CLAUDE.md, not in your memory of "but I told it that already."
Assuming a stopped-and-asked prompt means something is broken. A permission prompt is the system working correctly, not an error. If Claude keeps needing to ask for the same category of action you've decided to trust, that's a signal to add a narrow allow rule to settings.json — not to switch to a mode that stops asking about everything.
Summary
| Concept | Core idea |
|---|---|
| Agentic vs. autocomplete | Claude Code acts, observes real results, and decides its next step — autocomplete just predicts tokens |
| The agentic loop | Gather context → take action → verify results → repeat until done or blocked |
| Read / Grep / Glob | Read-only tools for understanding code; low risk, rarely need approval |
| Edit / Write / Bash | State-changing tools; Edit requires an exact string match and a prior read |
| Permission modes | Auto (default on Pro/Max/Team; classifier reviews in the background) · Manual (ask every time) · Accept Edits (auto-approve local edits) · Plan (research only, no edits) · Bypass (no checks at all, containers only) |
| Why modes exist | Reversibility: local file edits are cheap to undo; commands with external side effects are not, and stay gated even in permissive modes |
Checkpoints (/rewind) |
Undoes file edits made by Claude's own Edit/Write tools, per prompt; doesn't cover Bash-modified files, most subagent edits, or anything outside your filesystem; not a replacement for git |
| Output styles & fast mode | Two more session-level dials — output style changes tone/role/format via the system prompt; fast mode trades cost for lower Opus latency; neither changes the loop itself |
settings.json scopes |
User (you, everywhere) → Project (team, committed) → Local (you, this repo) → Managed (org-wide, non-overridable) |
| Permission rules | allow / deny / (implicit) ask, scoped to specific command or path patterns — not blanket toggles |
CLAUDE.md and memory |
Persistent instructions across sessions live here; conversation history itself does not carry over |
| Beginner failure mode | Dictating line-by-line edits instead of describing outcomes; not reviewing diffs; overly broad allow rules |
The through-line across all of this is the same idea seen from different angles: Claude Code is powerful because it closes the loop between deciding, acting, and checking the result — and every other design choice, from how Edit works to how permission modes are structured, exists to keep that loop honest and reversible while it runs.