Section 2Setup
Section 1 argued that the harness — not the model — decides your results; here you build its first pieces. This is a READ-DO checklist: read each item, do it, move on. Budget about an hour from a blank machine — less if Node and Git are already on it. At the end you'll have a working agent, a real project for it to work on (with a test that passes), the skills that teach it this guide's workflow, and three layers of guardrail that prove rules can be enforced rather than merely requested. Then you'll run your first agent and see it work.
Everything here happens in the terminal. If you've never used one, that's fine — every command below is copy-paste, each step ends with a "you'll know it worked" check, and none of the specific commands in this section can damage anything. That last promise is about these particular commands, not about agents in general — an agent can run destructive commands, which is exactly why later sections build guardrails. You'll install the first one before this chapter ends.
The terminal is a program where you operate your computer by typing commands instead of clicking. On a Mac it's the pre-installed app called Terminal; on Windows, PowerShell; on Linux, any terminal app. You type a command, press Enter, and the computer prints its answer as text. Two things nobody tells beginners: nothing happens until you press Enter, and no news is usually good news — many commands print nothing when they succeed.
Before you start (prerequisites)
Three things must exist before the agent can run — a runtime, version control, and an account — plus a folder for it to work in. They get the same treatment as everything else in this chapter: do the step, run the check.
Install Node.js
Node.js is the runtime your project's tooling runs on — the package manager, the build tool, the test runner you install in later steps. Think of it as the motor many developer tools share; you install it once and forget it. Installing it also gives you npm (a package manager, used below). Go to nodejs.org and click the big LTS download button — the "long-term support" installer for your operating system. Run it; the wizard's default answers are all fine.
In your terminal:
node --version
v20 or higher (something like v22.11.0).
If it says command not found (or not recognized): close the terminal window and open a fresh one, then try again. Newly installed commands often only appear in new terminal sessions — remember this reassurance, it applies to every install in this chapter.
Install Git
Git is the version-control tool that saves snapshots ("commits") of your code and lets agents work on separate copies. It's also your safety net: because every change is recorded, anything an agent does can be inspected and undone. The whole workflow assumes a git project. On Windows, download the Git for Windows installer from git-scm.com — the defaults are fine, and it also installs Git Bash, which a later step relies on. On a Mac, run xcode-select --install in the terminal and accept Apple's dialog, or use the installer from the same page.
In your terminal:
git --version
Create a Claude account
Claude Code signs in to Anthropic's service, which needs a paid plan or API credits (you pay per token — roughly, per chunk of text the model reads and writes). Create an account at claude.com. Expect a real cost: as of mid-2026, Claude Pro at roughly $20/month is the typical hobbyist tier, Claude Max comes in two tiers (roughly $100/month and roughly $200/month) for heavy or multi-agent use, and pay-per-token API credits are the alternative. Prices change — check the current pricing page before you pick. Pro is enough for everything in this guide.
Make your first project folder
Everything an agent does happens inside a project folder — one folder per project, with git recording every change inside it. The rest of this guide keeps saying "go to your project folder", so make it exist now:
In your terminal:
mkdir my-first-project
cd my-first-project
git init
cd ("change directory") moves your terminal into that folder — every command you type afterwards applies there. You'll type it every time you come back to the project; a handy trick is to type cd (with a trailing space) and drag the folder from Finder or Explorer into the terminal window — its location gets pasted for you.
git status answers "On branch main" (or master) and "No commits yet" — an empty, git-tracked project, which is exactly what the next steps assume.
Install Claude Code
Claude Code is the harness — the terminal app that runs the agent. The recommended way to install it is the native installer: one line that downloads a self-contained program and puts it on your command line. It installs globally — once for your whole computer, not into one project, which is what you want for tools you use everywhere.
In your terminal (Mac and Linux):
curl -fsSL https://claude.ai/install.sh | bash
claude # first run walks you through login
Windows (PowerShell):
irm https://claude.ai/install.ps1 | iex
The native install carries its own runtime, so Claude Code itself doesn't depend on the Node.js from Step 1 — but your project still will, because pnpm, the build tool and the test runner all run on Node. Keep it installed. (The older route, npm install -g @anthropic-ai/claude-code, still works if you'd rather use it.)
The first claude run opens your browser so you can sign in to your account; after that, the terminal and the agent are connected. From then on, starting an agent is: open terminal, go to your project folder (cd my-first-project), type claude.
You are now juggling two different prompts, and mixing them up is the classic beginner tangle. The terminal prompt — a line ending in something like $ or > — is where commands like npm and git go. The Claude Code prompt — the bordered chat box that appears after you type claude — is where you talk to the agent in plain English and use slash-commands like /grill-me. Paste a terminal command into the chat box and the agent may run it — or just chat about it; paste /grill-me into PowerShell and you get an error. Every code block in this chapter is labelled with where it belongs.
claude in any folder opens the chat prompt and shows your working directory.
If the terminal says command not found: claude, close the terminal window and open a fresh one — newly installed commands often only appear in new sessions.
How to read a command. npm install -g pnpm (the next step) is three parts: the tool being asked (npm), what to do (install, with -g for "globally"), and the thing to act on (the package name). Most commands in this guide follow that pattern — tool, action, target. You never need to memorise them; you copy, paste, and read the answer.
Install pnpm
Use pnpm as your project's package manager — the tool that fetches and installs the code libraries (dependencies) your project builds on. It's fast and strict: it refuses to let your project silently use a library nobody declared, a whole class of "works on my machine" bugs that agents are especially prone to introduce. This guide's rules assume it.
In your terminal:
npm install -g pnpm
pnpm --version
pnpm --version prints a version number.
Using npm to install these global tools is fine — the "never npm" rule you'll set below is only about commands inside a project. Two package managers in one project create conflicting bookkeeping; that's the actual rule.
Install the skills
Matt Pocock's skills are the reusable instructions that teach the agent each part of this workflow — grilling, planning, TDD, review. Think of each as a recipe card the agent pulls out when you ask for that move by name, so you don't re-explain the method every session. Install them once; they work in every project. Follow the current command in the repo's README (at time of writing):
In your terminal (not in the Claude Code chat box):
npx @mattpocock/skills install
npx is npm's "run once without installing" command — it fetches the installer, runs it, and leaves nothing behind but the skills themselves.
/ inside Claude Code lists skills like grill-me, to-prd and tdd.
Scaffold a real project — with the agent
Your folder is still empty, and an empty folder can't be type-checked or tested. Every later section assumes a working Node project: Section 5 writes tests in it, Section 6 reads the diff of changes to it, Section 7's CI runs its checks. So build the skeleton now. It's four things — a package.json (the file that names your project and lists its dependencies and commands), TypeScript in strict mode, Vite to build and serve it, and Vitest to run tests — which is the same stack Section 13 recommends for every new project.
You could type a dozen setup commands. Don't: this is a guide about directing agents, and scaffolding is exactly the well-trodden, verifiable work agents are good at. Start the agent in your project folder (claude), and give it this. Notice the shape of the prompt — an exact stack, an exact definition of done, and an instruction to show you the proof. That shape is the whole skill, and Section 3 will sharpen it.
Say this inside Claude Code (the chat box), not at the terminal prompt:
Scaffold a minimal web app in this folder. It is an empty git
repo. Use exactly this stack and nothing more:
- Vite, vanilla-ts template
- TypeScript in strict mode, with noUncheckedIndexedAccess on
- Vitest for tests
- one small source function with one test that passes
Install dependencies with pnpm (never npm). Then run
`pnpm vitest run` and `pnpm tsc --noEmit` and show me the
real output of both.
Then check it yourself, because "the agent said it worked" is not evidence — the habit Section 1 called evidence over claims starts here:
In your terminal, from the project folder:
pnpm vitest run
pnpm tsc --noEmit
pnpm dev
pnpm vitest run ends with 1 passed, pnpm tsc --noEmit prints nothing at all (silence is success — no news is good news), and pnpm dev prints a http://localhost:5173 address that opens a real page in your browser. Press Ctrl+C in the terminal to stop the dev server when you've seen it.
Save the result, so there's something to go back to:
In your terminal:
git add -A
git commit -m "Scaffold Vite + TypeScript + Vitest"
That first commit matters beyond tidiness: it's the point every later rollback can return to, and the production setup page expects a repository with at least one commit in it.
If the agent's scaffold doesn't pass those checks, don't fix it by hand — paste the failing output back into the chat and say "this failed, fix it and show me the output again." Handing an agent its own error message is the single most useful move in this guide, and it's the whole of Section 5's inner loop in one sentence.
Write a lean AGENTS.md
AGENTS.md is standing instructions for coding agents — a "README for agents": build/test commands, house rules, environment quirks. It's the open, cross-tool convention that most agents read. Claude Code itself natively reads a different file, CLAUDE.md — so the setup that makes every tool happy is a pair: put your rules in AGENTS.md, and add a CLAUDE.md whose entire content is the single line @AGENTS.md. That line is an import — Claude Code follows it and pulls the shared file in, every other tool reads AGENTS.md directly, and the two can never drift apart. Keep the file tiny: the model has a limited instruction budget, so record only what it can't discover on its own. And resist Claude Code's /init — a slash command you type inside the chat, which writes a CLAUDE.md for you by surveying the project. It sounds helpful and produces a bloated file that goes stale within a week. Two lines you wrote beat forty the agent guessed.
Both rules below are true of your project as of the previous step — pnpm is installed, and pnpm tsc --noEmit is a command that actually runs. Never write a rule into this file that names a tool the project doesn't have; an instruction the agent can't obey teaches it that this file is approximate.
File contents — AGENTS.md (in your project's top folder):
- Use pnpm, never npm.
- Type-check with `pnpm tsc --noEmit` before claiming a task is done.
File contents — CLAUDE.md (one line, nothing else):
@AGENTS.md
You haven't needed a code editor so far, and you don't need one now: the easiest way to create both files is to ask Claude Code itself — inside the chat, say "create AGENTS.md and CLAUDE.md in the project root with exactly these contents" and paste the two blocks above. This is how you'll create every configuration file in the rest of this chapter, so it's worth doing once deliberately.
ls in the project folder shows both AGENTS.md and CLAUDE.md — and when, in a fresh Claude Code session, asking "what package manager does this project use, and how do you know?" gets an answer that cites the file rather than a guess.
Set permissions — the first guardrail
By default Claude Code asks before it does anything consequential, which is safe and quickly exhausting: click "yes" fifty times in an afternoon and you stop reading the prompts, which is worse than not being asked. The fix is not to loosen everything — it's to decide once, in writing, what runs freely, what must always ask, and what is refused outright. That's Claude Code's permissions system, and in 2026 it is your first line of defence.
Three lists, plus a default. allow runs silently. ask always prompts, even if something else would have allowed it. deny refuses outright and cannot be talked around — nothing the model says overrides it. Everything unlisted falls to defaultMode. You can inspect and edit the current rules any time by typing /permissions inside the chat; the file below is the same thing, written down and committed so it applies to everyone on the project.
Ask Claude Code to create this, exactly as you did with AGENTS.md:
File contents — .claude/settings.json:
{
"permissions": {
"allow": [
"Bash(pnpm vitest run)",
"Bash(pnpm tsc --noEmit)",
"Bash(git status)",
"Bash(git diff *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl *)"
],
"defaultMode": "acceptEdits"
}
}
Read the deny list twice, because it's the half that matters. Your credentials will live in .env (the production setup page puts them there), and an agent has no business reading them: a secret that enters the conversation is a secret you must rotate. defaultMode: "acceptEdits" says file edits go through without prompting — safe precisely because git records every one of them, and Section 6 reviews the diff before anything merges.
Permission rules are checked before a tool runs — the file reader, the editor, the web fetcher, the Bash tool itself. What they cannot do is follow a shell command inside. "Read(./.env)" stops Claude's Read tool cold and does nothing about an agent running cat .env, because the rule sees one approved Bash call, not what the shell does next — and nothing about the programs that command then starts. This is not a bug you can configure away; it's the shape of the thing. It's also the entire reason the next two layers exist: the sandbox (Step 11) is enforced by the operating system and does reach inside shell commands and their child processes, and the hook (Step 12) inspects the command text before it runs. Permissions, sandbox, hooks — three layers, because each has a hole the others cover.
/permissions in the chat lists your rules — and asking the agent "read the .env file" (create an empty one first with touch .env) is refused, rather than prompting you.
Turn on the sandbox
A sandbox is a fence the operating system holds, not the model — inside it, a command physically cannot write outside your project or reach a host you didn't list, however confidently the agent tries. People often assume this means Docker and a day of work. It doesn't any more: Claude Code ships a sandbox built in on macOS, Linux and WSL2, and turning it on is a few lines in the same settings file.
It pays for itself twice. Once in safety, and once in quiet: because commands inside the fence can't do damage, Claude Code has an auto-allow mode that stops asking permission for them. The stream of prompts you were about to start rubber-stamping largely disappears, and the ones that survive are the ones worth reading — which is the only way a permission prompt ever does its job.
The fastest way in is the panel: type /sandbox in the chat, open the Mode tab, and choose auto-allow. That writes the setting for you. To make it the standing policy for the project, ask the agent to merge this into .claude/settings.json next to the "permissions" block:
File contents — the sandbox block of .claude/settings.json:
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": [
"registry.npmjs.org",
"*.github.com"
]
},
"filesystem": {
"denyRead": ["./.env", "./secrets/**"]
}
}
}
Two lines are doing the work. allowedDomains means the agent's commands can reach your package registry and GitHub — and nothing else. That single restriction removes a whole family of bad days: a compromised dependency phoning home, or an agent following an instruction hidden in a web page to send your files somewhere (Section 9 names that attack). And filesystem.denyRead is the piece that closes the hole in the warning above: this is what stops cat .env, because the operating system refuses the read no matter which program asks. Deny the same paths in both places — permissions for Claude's own tools, sandbox for everything a shell command spawns.
Two escape hatches you'll meet eventually: some commands genuinely need to be outside the fence — Docker is the usual one — and go on an excludedCommands list ("docker *"), while allowUnsandboxedCommands governs whether the agent may ask to step out at all. Add them when something actually breaks, not in advance. Platform note: this works on macOS, on Linux (which needs the bubblewrap and socat packages), and on Windows through WSL2 — but not on Windows natively, where the permissions and hook layers still apply and Section 11's container route is the fallback.
/sandbox reports the sandbox as active, and — after restarting Claude Code — asking the agent to "read .env using the cat command" fails with a permission error from the system rather than printing the file.
Three settings files, and which one wins. You just wrote .claude/settings.json — project settings, committed to git, shared with everyone who works on the project. There are two others. ~/.claude/settings.json (the ~ means your home folder) is your settings, applied to every project on your machine — Section 13 calls this Layer 1 and builds it into the thing you carry between projects. .claude/settings.local.json sits in the project but is gitignored: your personal tweaks to this project, not imposed on teammates. When two of them disagree, the more specific wins: local beats project, project beats user. Rule of thumb — a rule the whole project needs goes in the committed file; a preference only you want goes in the local one.
Enforce one rule with a hook
Permissions and the sandbox bound what the agent can do. A hook is the third layer, and the only one that can judge a command by what it actually says. Rules the model "should" follow in prose, it will sometimes ignore — not out of defiance, but because a model follows instructions statistically, not mechanically. A hook is a script that fires automatically and blocks the wrong action every time. It isn't smarter than the model; it's dumber, and that's the point: it cannot be argued with, and it never has an off day. This one rejects npm inside the project. Before each shell command, Claude Code hands the script a small JSON description of the call; the script fishes out the command (using Node — already installed, no new tools), and if it's an npm install-family command, it prints the reason and exits with code 2, the exit code that means "block this and tell the agent why".
Two files make it real, and — as with AGENTS.md — the agent writes them for you. Paste this into the chat first, then paste the two blocks below it when it asks:
Say this inside Claude Code:
Create the folder .claude/hooks, then create the file
.claude/hooks/pre-bash.sh with exactly the contents I paste
next, and make it executable. Then merge the "hooks" block I
paste after that into the existing .claude/settings.json,
keeping the "permissions" and "sandbox" blocks intact.
File contents — .claude/hooks/pre-bash.sh:
#!/bin/bash
# Blocks npm inside this project — the rule is "pnpm, never npm".
cmd=$(node -e 'const d=require("fs").readFileSync(0,"utf8");try{process.stdout.write(JSON.parse(d).tool_input.command||"")}catch(e){}')
if echo "$cmd" | grep -qE '\bnpm +(install|i|ci|add|exec)\b'; then
echo "Blocked by hook: this project uses pnpm, never npm. Re-run the command with pnpm." >&2
exit 2 # exit 2 blocks the tool call; Claude reads the message above
fi
exit 0
Registering it tells Claude Code to actually fire the script before every shell command:
File contents — the hooks block of .claude/settings.json (merged in beside permissions and sandbox):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pre-bash.sh"
}
]
}
]
}
}
"Make it executable" in the prompt above is the agent running chmod +x .claude/hooks/pre-bash.sh for you — on Mac and Linux a file needs that permission before the system will execute it, and a hook that isn't executable simply never fires, silently. Check it with ls -l .claude/hooks/: you want an x in the permissions column. (Windows has no such permission; there the script runs in Git Bash, which Claude Code picks up automatically and which the Git for Windows installer from Step 2 already put on your machine — no Git Bash? Use WSL.)
Then restart Claude Code — type /exit, then claude again. Hook and settings configuration is read at startup, so a change you don't restart for is a change that isn't running. This catches everyone once.
pnpm on its own. More hook patterns: the Claude Code hooks guide.
One sibling worth knowing about now, because it's arguably the more useful of the two. PreToolUse fires before a tool runs and can block it. PostToolUse fires after, and its natural job is cleaning up behind every edit: same shape, but "matcher": "Write|Edit" and a script that formats the file the agent just touched and type-checks it. The agent then sees the type error immediately, in the same turn, instead of you finding it twenty minutes later. One caveat that trips people up: exit code 2 in a PostToolUse hook does not undo anything — the tool has already run — it just puts your message in front of the model. Blocking is PreToolUse's job; reacting is PostToolUse's.
Once you've seen the hook fire, delete the "Use pnpm, never npm" line from AGENTS.md — it was scaffolding. Section 12's doctrine is that every line in that file must earn its place in the instruction budget, and a rule a hook already guarantees earns nothing. This tiny hook is a preview of the whole discipline: Section 1 said to build machinery that doesn't rely on trust — this is the first piece of that machinery, and Sections 7, 9 and 12 build the bigger ones the same way.
Where did .claude go? Files and folders whose names start with a dot are hidden by default — they hold configuration, and file browsers tuck them away. Your file manager can show them (on a Mac, press Cmd+Shift+. in Finder), the terminal lists them with ls -a, and the agent sees them just fine. Hidden ≠ gone.
Learn two controls: plan mode and rewind
Everything so far was configuration. These two are keystrokes, they take two minutes to learn, and between them they cover the beginner's two worst moments — the agent charged off and built the wrong thing, and the agent broke something and I don't know what.
Plan mode is the brake. In it, the agent may read and think but may not edit a single file: it comes back with a plan you approve or send back. For anything you haven't done before, this is the right way to start — a wrong approach is obvious in five bullet points and nearly invisible in a finished diff. Enter it by pressing Shift+Tab inside the chat, which cycles through the modes in order: default → accept edits → plan. The mode is shown above the prompt, so you can always see which one you're in. To start a whole session that way, launch with claude --permission-mode plan. Section 5 makes it the standard opening move for any change worth thinking about, and the rescue page opens an unfamiliar codebase with it.
Rewind is the undo. Claude Code quietly snapshots your files before each change it makes, so a session that has gone sideways doesn't need heroics: press Esc twice (or type /rewind), pick a point, and choose what to restore — the code, the conversation, or both. Restoring only the conversation is the underrated one: it rewinds what the agent believes while keeping the work, which is how you back out of a misunderstanding without losing the good part. Note the honest limit: rewind reliably covers files the agent edited with its own tools, and is not a substitute for git when a shell command moved things around. Commit at every point you'd hate to lose — rewind is the small undo, git is the real one.
Start claude in your project folder and — inside the Claude Code chat, not the terminal prompt — type /grill-me with a one-line idea for what the app you just scaffolded should become ("a booking page for a small hair salon"). The agent will start interviewing you. That interview is agentic coding — you've already started. And that grilling, run properly until every fuzzy decision is nailed down, is exactly where Section 3 picks up.
Most of the loop assumes your project lives on GitHub (or GitLab) with CI running your checks on every proposed change. Wiring that up is its own hour and has its own page: Setup, part two: production infrastructure. You need it sooner than you might think: Section 4 puts your tickets on a real board in that repo, and Section 6 reviews every change on its pull-request page with a green CI check next to it. Sections 3 and 5 work fine without it. So: do it right after this chapter if you're on a roll, and at the latest before Section 4.
If something doesn't work
Setup problems are almost never subtle — the fix is usually "restart and re-read." The two classics:
Troubleshooting: the skills don't show up after install
Restart Claude Code so it re-reads the skills folder. Confirm the skills landed in your Claude config directory (usually ~/.claude/skills/). If the install command has changed, the repo README is the source of truth — the ecosystem moves fast.
Troubleshooting: command not found after an install
The terminal builds its list of known commands when it starts, so a tool installed a minute ago may not be on it yet. Close the terminal window, open a new one, try again. If it persists, re-run the install command and read its output — the error message usually names the problem directly, and pasting it into the agent (or any chatbot) gets you an explanation in plain language.
Quick check: three days in, the agent runs npm install anyway — even though AGENTS.md says "Use pnpm, never npm." A colleague suggests repeating the rule in capital letters. What do you do instead?
Skip the capital letters and reach for machinery: make sure the Step 12 hook is registered and firing (or build it now), watch it block npm once, then delete the prose line. Prose is a request the model honours most of the time; a hook is a guarantee that holds every time. Louder prose buys you nothing — enforcement does, and that difference is the core idea of this whole guide.