Your machine

This page gets you a working terminal with the right tools in it — about 20 minutes on macOS or Linux, 30–45 on Windows.

Nothing here touches your project or costs money — it's groundwork, and once it's done you never do it again. Most of the Windows time is a reboot and a download bar.

If you already have a terminal you're comfortable in, skip to the tools and run the check-everything script.


What a terminal actually is#

A terminal is a window where you type the name of a program and it runs. That's the whole idea. Your desktop shows you programs as icons you click; the terminal shows you programs as words you type. The same computer, the same files, a different door in.

Inside that window is a prompt — a bit of text sitting at the left waiting for you, usually ending in $ or % or >. It often tells you who you are and which folder you're in, like you@laptop ~/projects $. You type a command after it, press Enter, and the computer does the thing. When it's finished, the prompt comes back, which is how you know it's done.

This guide uses a terminal for a reason that isn't stubbornness: the things you are about to do — buying a domain, pushing code, deploying a site — all have web dashboards, and those dashboards get redesigned every few months. A command is stable, copy-pasteable, and repeatable. It also means that when something breaks at 11pm, you can paste the exact command and the exact error into Claude Code and get a real answer, instead of describing a button you clicked.

Five things that catch people out#

Two commands worth knowing before anything else: pwd prints the folder you're currently in ("print working directory"), and cd some-folder moves you into one. cd .. goes back up one level. If you're ever lost, pwd tells you where you are.


Windows#

This section is long, and deliberately so. A shell is the program running inside the terminal window that reads what you type and decides what it means — different shells understand slightly different languages. This guide is written in bash, the shell macOS and Linux use, and Windows does not have bash out of the box. That gap is where most Windows readers give up, so here is the whole thing.

PowerShell and Command Prompt are not bash#

Windows gives you two terminals already: Command Prompt (cmd, the older one) and PowerShell (the modern one). Both are real, capable shells. Neither of them speaks bash, and the difference is not cosmetic — commands from this guide will fail in them, sometimes loudly and sometimes silently, which is worse.

Four concrete examples, because "it's different" isn't useful:

Thing this guide does bash PowerShell
Write a file inline:
cat > f.json <<EOFEOF
Creates the file The '<' operator is reserved for future use — heredocs don't exist
Literal text: '{"Name":"a"}' Passed through exactly Single quotes are literal in PowerShell too, but PowerShell then re-parses the argument when handing it to a native .exe, and JSON comes out mangled
A variable: $BUCKET and export BUCKET=x Sets and reads a variable $BUCKET is a PowerShell variable with different rules; export doesn't exist (it's $env:BUCKET = "x")
Continue a long command on the next line with a trailing \ Joins the lines The \ is treated as text; PowerShell uses a backtick ` instead. The command runs half-finished

A heredoc — the cat > file <<EOF pattern — is how this guide writes config files and AWS policy documents. Track B uses it repeatedly. If your shell can't do heredocs, large parts of Track B simply won't work as written.

So you need a bash. There are two routes.

WSL stands for Windows Subsystem for Linux: a real Ubuntu Linux running inside Windows, sharing your files and your network, with no dual-boot and no virtual machine to manage. You open it like any other app. Every command in this guide then works exactly as written, because you are genuinely on Linux.

It works on Windows 11 and on Windows 10 version 2004 or later. Windows Home is fine — you do not need Pro, despite what older articles say.

On a work laptop? WSL needs hardware virtualisation, which some corporate IT policies switch off and lock. If the steps below fail with a policy error, don't fight it — use Git Bash and Track A, which between them need very little terminal.

Step 1 — Open PowerShell as Administrator

Installing WSL changes Windows features, so it needs administrator rights.

  1. Press the Windows key, or click Start.
  2. Type powershell.
  3. In the results, right-click "Windows PowerShell" and choose Run as administrator. (On the newer Start menu, "Run as administrator" also appears in the panel on the right.)
  4. A User Account Control box appears asking "Do you want to allow this app to make changes to your device?" — click Yes.

You'll know it worked because the window's title bar starts with Administrator:. If it doesn't, you're in a normal PowerShell and step 2 will fail with an access-denied error.

On Windows 11 there's a shortcut: right-click the Start button itself and choose Terminal (Admin).

Step 2 — Install it

wsl --install

That single command turns on two Windows features, downloads the Linux kernel, and installs Ubuntu. It prints progress lines like Installing: Virtual Machine Platform, Installing: Windows Subsystem for Linux, Downloading: Ubuntu, and finishes with something close to:

The requested operation is successful. Changes will not be effective until the system is rebooted.

The download is a few hundred megabytes, so on a slow connection this takes a while and the progress percentage can appear to stall. Let it.

Step 3 — Reboot

Actually reboot. Not "close the lid" — a real restart, from Start → Power → Restart. WSL will not work until you do, and the error you get if you skip it looks unrelated and will waste your evening.

Step 4 — Set your Linux username and password

After the reboot, an Ubuntu window usually opens by itself and says Installing, this may take a few minutes.... If it doesn't appear, open Start and click Ubuntu.

Then it asks two things:

Enter new UNIX username:

Type a short, lowercase name with no spaces. It does not have to match your Windows username and it isn't shown to anyone. jon is fine.

New password:

The password shows nothing as you type. Not even asterisks. The cursor does not move. This is not a broken keyboard and the window has not frozen — Unix has hidden password input since the 1970s and it panics everyone the first time. Type your password, press Enter, type it again when it asks to confirm, press Enter.

Write this password down. It is not your Windows password, it is not your Microsoft account, and there's no "forgot password" link. You'll need it every time you run a command starting with sudo — which means "run this one command with administrator rights".

When it's done you get a prompt that looks like this, and you are on Linux:

jon@DESKTOP-4F2K1:~$

Step 5 — Confirm it's healthy

Back in PowerShell (a normal one is fine now):

wsl -l -v

Expected shape — the important column is VERSION, which should say 2:

  NAME      STATE           VERSION
* Ubuntu    Running         2

If it says 1, run wsl --set-version Ubuntu 2. Version 1 is the older implementation and some things behave differently.

Opening Ubuntu from now on

Three ways, all equivalent:

Where your files are

This is the bit that confuses everyone, so here it is plainly. You now effectively have two filesystems that can see each other.

Where Path inside Ubuntu Path in Windows Explorer
Your Linux home folder ~ (which is /home/jon) \\wsl.localhost\Ubuntu\home\jon (older builds: \\wsl$\Ubuntu\home\jon)
Your Windows C: drive /mnt/c C:\
Your Windows Desktop /mnt/c/Users/YourName/Desktop the Desktop

So if your project is currently sitting on your Windows desktop, you can reach it from Ubuntu:

cd "/mnt/c/Users/Your Name/Desktop/my-project"

Note the quotes — Windows usernames often contain a space, and without quotes bash reads that as two separate arguments and reports No such file or directory.

Strong advice: move your project into the Linux home folder.

bash cp -r "/mnt/c/Users/Your Name/Desktop/my-project" ~/ cd ~/my-project

Reading and writing files across the /mnt/c boundary goes through a translation layer, and it is slow — not "a bit slow", but ten times slower in a way you will feel. git status on a large repo takes seconds instead of being instant, and npm install can take minutes instead of moments. Keep the files on the Linux side and everything is fast. This is the single biggest quality-of-life difference in WSL.

To open your Linux folder in Windows Explorer, run this from inside Ubuntu:

explorer.exe .

The . means "this folder". You can drag files in and out of that window normally. If you use VS Code, install its WSL extension and then code . from the Ubuntu prompt opens the editor properly attached to Linux.

When wsl --install goes wrong

What you see What it means What to do
wsl : The term 'wsl' is not recognized... Windows is too old (pre-2004) Press Windows+R, type winver, press Enter. You need version 2004 / build 19041 or later. Run Windows Update, possibly twice
Invalid command line option: --install Windows 10, old enough to have wsl but not --install Update Windows. If you genuinely can't, use Microsoft's manual steps
Please enable the Virtual Machine Platform Windows feature and ensure virtualization is enabled in the BIOS, or error 0x80370102 Hardware virtualisation is switched off in your firmware See virtualisation below
WslRegisterDistribution failed with error: 0x800701bc The WSL2 Linux kernel is missing or out of date In admin PowerShell: wsl --update, then wsl --shutdown, then reopen Ubuntu
WslRegisterDistribution failed with error: 0x8007019e The WSL Windows feature never got enabled See enabling the features by hand below
WslRegisterDistribution failed with error: 0x80370114 Virtual Machine Platform is enabled but blocked — often Core Isolation / Memory Integrity, or another virtualisation product (VirtualBox, VMware) holding the hardware Turn off Memory Integrity in Windows Security → Device security → Core isolation, reboot, try again
It installs, then Ubuntu closes instantly with no message Almost always a failed first-run setup Run wsl --unregister Ubuntu then wsl --install -d Ubuntu to start clean. This deletes the Linux filesystem, which is empty at this point anyway
Everything fails and you're on a managed work laptop Group policy — rules your IT department pushes to the machine, which you can't override Stop here. Use Git Bash
Virtualisation disabled in the BIOS

WSL2 uses your CPU's virtualisation feature, and a surprising number of laptops ship with it switched off. First check whether it's actually off: open Task Manager (Ctrl+Shift+Esc) → PerformanceCPU, and look for Virtualization. If it says Disabled, that's your problem.

To turn it on you need your computer's firmware settings (the "BIOS" or "UEFI"), which is a menu that appears before Windows starts. The reliable way in:

  1. SettingsSystemRecoveryAdvanced startupRestart now.
  2. TroubleshootAdvanced optionsUEFI Firmware SettingsRestart.
  3. In the firmware menu, find the setting. It's called Intel VT-x, Intel Virtualization Technology, AMD-V, or SVM Mode, usually under Advanced, CPU Configuration, or Security. Set it to Enabled.
  4. Save and exit — usually F10.

Firmware menus differ per manufacturer and none of them are pretty. Searching for "enable virtualization" plus your laptop's exact model is genuinely the fastest route, and it is a normal, safe, reversible setting.

Enabling the features by hand

If the automatic install left the Windows features off, turn them on explicitly. In PowerShell as Administrator:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

Reboot, then:

wsl --update
wsl --install -d Ubuntu

Route 2 — Git Bash#

Git Bash is a small bash shell that comes bundled with Git for Windows. Install Git for Windows, accept the defaults, and you get a "Git Bash" entry in your Start menu that opens a genuine bash prompt with git, ls, cat, grep, curl, ssh, sed and friends already in it.

It's much lighter than WSL — a single installer, no reboot, no virtualisation — and it's the right answer if WSL is blocked or you want to get moving now.

What works: everything in Get it on GitHub, heredocs, single quotes, $VAR, backslash line continuations, and effectively all of Track A.

What doesn't:

That last point is why Track B is listed as "risky" below rather than "fine".

What works where#

Task PowerShell Git Bash WSL
Paste a bash command from this guide and have it run No Yes Yes
Heredocs (cat > file <<EOF) No Yes Yes
$VAR / export VAR=value No — different syntax Yes Yes
Backslash \ at end of line to continue No — uses a backtick Yes Yes
git, gh Yes Yes Yes
curl curl.exe yes; bare curl is an alias for a different tool in Windows PowerShell 5 Yes Yes
dig No — use nslookup No — use nslookup Yes
jq, zip Install separately Install separately sudo apt install
aws (AWS CLI) Yes Yes, with path-translation quirks Yes
sudo No — "Run as administrator" instead No Yes
Track A — Cloudflare end to end Mostly; it's dashboard-heavy Yes Yes
Track B — AWS end to end No Risky Yes

The recommendation, plainly: install WSL. It's twenty minutes and a reboot, and afterwards every instruction in this guide and in most of the internet's tutorials applies to you unchanged. Take Git Bash if WSL is blocked, or if you know you're doing Track A and want to start in the next five minutes.

Everything you install in Windows and everything you install in WSL are separate. Installing the AWS CLI in Windows does not put aws inside Ubuntu, and vice versa. If you take the WSL route, do all the installs in the next section from the Ubuntu prompt using the Linux instructions — not the Windows ones.


macOS#

macOS already has a terminal: Terminal.app, in Applications → Utilities. Press Cmd+Space, type terminal, press Enter. It opens on a shell called zsh, which is close enough to bash that everything in this guide works unchanged.

What it doesn't have is a way to install things. That's Homebrew.

Homebrew#

A package manager is a program whose job is installing other programs: it knows where each tool lives, downloads the right version for your machine, puts it somewhere your terminal can find it, and updates it later with one command. Without one you're hunting for download pages, and nothing knows what you've already got. Homebrew is the one macOS uses.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Two things will happen that surprise people:

  1. It asks for your Mac login password. Homebrew needs to create folders your normal user can't write to. Same rule as before — nothing appears as you type. Type it, press Enter.

  2. A dialog box appears offering to install the Xcode Command Line Tools. Click Install and accept the licence. This is Apple's set of developer tools — the compiler, plus git itself — and Homebrew needs it. It's a download of a gigabyte or two and takes several minutes on a good connection. If the dialog doesn't appear, run xcode-select --install yourself.

The bit people skip, and then brew isn't found#

When Homebrew finishes it prints a block headed ==> Next steps: with two or three commands in it. Run them. On Apple Silicon Macs, Homebrew installs to /opt/homebrew, which your shell does not look in by default, so if you skip this you'll open a fresh terminal tomorrow and get brew: command not found despite having installed it.

The commands look like this:

echo >> ~/.zprofile
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

That appends one line to your shell's startup file so every future terminal knows where Homebrew lives, then applies it to the current one.

On Intel Macs, Homebrew installs to /usr/local, which is already on the path, and there's nothing to do. Not sure which you have? Apple menu → About This Mac: "Chip: Apple M…" is Apple Silicon, "Processor: Intel…" is Intel. Or in the terminal, uname -m prints arm64 or x86_64.

Then install everything at once:

brew install git gh jq awscli

curl, dig and zip ship with macOS already.


Linux#

You already have a terminal and a package manager. The only question is which one, and that depends on your distribution — the particular flavour of Linux you installed, such as Ubuntu or Fedora:

Distribution Command
Ubuntu, Debian, Linux Mint, Pop!_OS, WSL's default Ubuntu sudo apt install …
Fedora, RHEL, CentOS, Rocky sudo dnf install …
Arch, Manjaro sudo pacman -S …
openSUSE sudo zypper install …

sudo means "run this one command as the administrator". It asks for your own login password the first time you use it in a session, and — you know this by now — shows nothing as you type.

On Debian, Ubuntu or WSL, get most of the way in one line:

sudo apt update
sudo apt install -y git curl jq zip unzip dnsutils

sudo apt update refreshes the catalogue of what's available; without it you can get "package not found" for something that plainly exists. -y answers yes to the "do you want to continue?" prompt.

Package names differ slightly per distribution:

Tool Debian / Ubuntu / WSL Fedora Arch
dig dnsutils (or bind9-dnsutils on newer releases) bind-utils bind
everything else the obvious name the obvious name the obvious name

gh and aws aren't in the default repositories in a usable version — they get their own instructions below.


The tools#

Nine things. Install them now rather than discovering each one missing halfway through a step at a point where you've lost your thread.

For each one: what it is, how to install it, and the command that proves it worked. Version numbers below are illustrative — yours will be higher and that's fine. What you're checking is that the command runs at all and prints something of roughly the right shape, rather than command not found. Any word here you don't recognise is in the glossary.

git — tracks your changes#

Git records every version of your project and is how your code gets to GitHub. Both tracks deploy from a GitHub repository, so nothing else in this guide happens without it.

# macOS — comes with the Xcode Command Line Tools; this gets a newer one
brew install git

# Debian / Ubuntu / WSL
sudo apt install -y git

# Windows without WSL — Git for Windows, which is also where Git Bash comes from
winget install Git.Git
git --version
git version 2.43.0

gh — GitHub from the command line#

GitHub's own tool. It creates repositories (a repository, or "repo", is one project's folder of code as GitHub stores it), sets permissions, and — most usefully — logs you in properly, so you never have to generate or paste a personal access token: a long secret string GitHub can issue in place of a password, which is fiddly to make and easy to leak. 05 — Get it on GitHub uses it throughout.

# macOS
brew install gh

# Windows without WSL
winget install GitHub.cli

# Debian / Ubuntu / WSL — GitHub's own repository, because the built-in one lags
(type -p curl >/dev/null || sudo apt install -y curl) \
  && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
    | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
  && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
  && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
    | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
  && sudo apt update && sudo apt install -y gh

That last block looks alarming. It is four steps: fetch GitHub's signing key, save it, tell apt about GitHub's package repository and that this key vouches for it, then install. The signing key is what stops someone substituting a fake package.

gh --version
gh version 2.88.1 (2026-03-12)
https://github.com/cli/cli/releases/tag/v2.88.1

You'll log in with gh auth login in 05 — not yet.

curl — fetches a URL#

curl asks a web address for its contents and prints them. In this guide it's how you check a site is actually live, and what headers it's returning — the handful of labels a server sends alongside the page saying what it is, how long it may be cached and whether the request succeeded. curl shows you the real answer, without your browser's cache lying to you about it.

Already present on macOS, on every Linux, in Git Bash, and in modern Windows.

curl --version
curl 8.7.1 (x86_64-apple-darwin23.0) libcurl/8.7.1 (SecureTransport) LibreSSL/3.3.6
Protocols: dict file ftp ftps gopher gophers http https imap imaps ...

PowerShell warning. In Windows PowerShell 5.1 — the version most Windows 10 and 11 machines open by default — curl is an alias for a completely different PowerShell tool that takes different flags. curl -I https://… will not do what this guide expects. Write curl.exe explicitly, or use WSL or Git Bash, where curl is the real thing.

dig — asks DNS a question directly#

DNS is the layer that turns yourthing.com into an address, and it's where most "my site isn't working" turns out to live. dig asks a DNS server a question and shows you the raw answer, which is the only way to see past your own computer's cache. The three layers explains what to ask it.

# macOS — already installed

# Debian / Ubuntu / WSL
sudo apt install -y dnsutils          # newer releases: bind9-dnsutils
dig +short example.com
104.20.23.154
172.66.147.243

One or more IP addresses means it works. The exact addresses change over time and some names answer with several, so don't compare yours against the ones above — what matters is that you get addresses at all. No output means the lookup failed, usually a network problem rather than a dig problem.

No dig on Windows outside WSL. Use nslookup example.com instead, which is built in and answers the same basic question with a different layout. For anything more involved, dnschecker.org shows you what the rest of the world sees, which is often more useful than what your own machine sees.

jq — reads JSON#

AWS commands answer in JSON — a structured text format full of braces that is precise and unreadable in bulk. jq pulls single values out of it and pretty-prints the rest. Track B uses it constantly; Track A barely needs it.

# macOS
brew install jq

# Debian / Ubuntu / WSL
sudo apt install -y jq

# Windows without WSL
winget install jqlang.jq
jq --version
jq-1.7.1

A better proof, because it shows it actually parses:

echo '{"live":true,"visits":3}' | jq .visits
3

zip — packages files into one archive#

AWS Lambda — Amazon's service for running a small piece of your code on demand, with no server for you to look after — takes that code as a .zip file. So Track B needs zip if, and only if, your project has a backend: code that runs on a server rather than in the visitor's browser. Track A never uses it.

# macOS — already installed

# Debian / Ubuntu / WSL
sudo apt install -y zip unzip
zip --version

The output is a wall of copyright text starting with Copyright (c) 1990-2008 Info-ZIP. That's a healthy answer — it's an old tool with old manners.

aws — the AWS command line#

The tool that drives your AWS account from the terminal: creating buckets (an S3 bucket is just a named folder in Amazon's storage that a website can be served out of), uploading files, and clearing the CDN cache — a CDN, or content delivery network, being the layer of copies of your site kept near your visitors so pages load fast. Track B only — skip this entirely if you're taking Track A.

# macOS
brew install awscli
# Linux and WSL — AWS's own install script, because distribution packages are old.
# It picks the right build for Intel or ARM machines by itself.
curl -fsSL https://awscli.amazonaws.com/v2/install.sh | bash

That script installs into your own home folder (~/.local/bin) and needs no sudo. If aws isn't found afterwards, close the terminal and open a new one — see when it doesn't work below.

# Windows without WSL
winget install Amazon.AWSCLI
aws --version
aws-cli/2.34.15 Python/3.13.12 Darwin/25.5.0 source/arm64

The aws-cli/2. at the start matters — this guide assumes version 2. If you see aws-cli/1.… you have an old install (often from pip, Python's package installer) shadowing the new one; remove it, or fix your PATH so version 2 comes first. PATH is the ordered list of folders your shell searches when you type a command name — the first match wins, which is exactly how an old copy keeps answering.

You'll connect it to your account in Track B, after keys and access. Don't run aws configure yet.

node and npm — only if your project builds#

Node.js runs JavaScript outside a browser, and npm is its package manager, installed alongside it. You need these only if your project has a build step — if you run something like npm run build and get a dist/ or build/ folder out of it. React, Vue, Svelte, Vite, Astro and Next all work this way. A hand-written HTML page does not.

Not sure? Look in your project folder for a file called package.json. If it's there, you need Node.

# macOS
brew install node

# Debian / Ubuntu / WSL — the distribution version is usually too old.
# nvm lets you install and switch Node versions per project.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
# then close and reopen your terminal, and:
nvm install --lts

# Windows without WSL
winget install OpenJS.NodeJS.LTS
node --version
npm --version
v22.14.0
10.9.2

The nvm install prints instructions and then does nothing until you open a new terminal. If nvm: command not found immediately after installing, that is why — close the window, open a new one, try again.

Claude Code — the agent that reads this guide with you#

Every page in this guide is written to be handed to Claude Code, which can run the commands and explain what it's doing. You don't have to use it — the guide stands alone — but the prompts scattered through it assume you might.

The current install instructions live at code.claude.com/docs/en/setup, and they change more often than anything else on this page, so check there rather than trusting a command in a Markdown file. As of writing:

# macOS, Linux, WSL
curl -fsSL https://claude.ai/install.sh | bash

# macOS, via Homebrew
brew install --cask claude-code

# or, if you already have Node
npm install -g @anthropic-ai/claude-code
claude --version
2.1.226 (Claude Code)

Then run claude in your project folder to start it. It'll walk you through signing in the first time. There's also claude doctor, which checks its own install and tells you what's wrong.

On Windows, prefer installing Claude Code inside WSL, from the Ubuntu prompt. It does run natively on Windows from PowerShell — there's an official installer for it — but this guide's commands are bash, and Claude Code is a great deal happier when the shell underneath it is bash too.

Claude Code needs a paid Claude plan (Pro, Max, Team or Enterprise) or a Console account with API credit; the free Claude.ai plan doesn't include it. Prices and plan limits change, so check claude.com/pricing rather than any number you read in a guide.


Check everything at once#

Paste this whole block into your terminal and press Enter. It prints one line per tool with a tick or a cross, and it changes nothing.

for tool in git gh curl dig jq zip aws node npm claude; do
  if command -v "$tool" >/dev/null 2>&1; then
    printf '  ✓  %-6s  %s\n' "$tool" "$(command -v "$tool")"
  else
    printf '  ✗  %-6s  not installed\n' "$tool"
  fi
done

A healthy result looks roughly like this:

  ✓  git     /opt/homebrew/bin/git
  ✓  gh      /opt/homebrew/bin/gh
  ✓  curl    /usr/bin/curl
  ✓  dig     /usr/bin/dig
  ✓  jq      /opt/homebrew/bin/jq
  ✓  zip     /usr/bin/zip
  ✓  aws     /opt/homebrew/bin/aws
  ✓  node    /opt/homebrew/bin/node
  ✓  npm     /opt/homebrew/bin/npm
  ✓  claude  /Users/you/.local/bin/claude

Crosses are not automatically a problem. Read them against what you're actually doing:

Tool Needed for
git, gh, curl Everything. A cross here is a real problem
dig Useful everywhere; essential when DNS misbehaves. On Windows outside WSL, use nslookup and ignore the cross
jq, zip, aws Track B — AWS. Ignore entirely on Track A
node, npm Only if your project has a package.json
claude Only if you want Claude Code to drive

The second column of the output — the path — is worth a glance too. If a tool shows up somewhere you don't expect (an aws under /usr/local/bin when you installed via Homebrew, say), you have two copies and the wrong one is winning.


When it doesn't work#

What you see What's actually going on What to do
command not found for something you just installed Your terminal built its list of programs when it opened and hasn't noticed the new one Close the terminal window and open a new one. This fixes it perhaps four times out of five. If it doesn't, the tool went somewhere your PATH doesn't cover — see the next two rows
brew: command not found on a Mac, even though Homebrew installed fine Apple Silicon puts Homebrew in /opt/homebrew, which isn't searched by default, and you skipped the "Next steps" block Run eval "$(/opt/homebrew/bin/brew shellenv)" now, and add it to ~/.zprofile so it sticks — see Homebrew above
command not found and reopening didn't help PATH — the list of folders your shell searches — doesn't include where the tool landed Find it with ls /usr/local/bin, ls ~/.local/bin or the installer's own output, then add that folder: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc (use ~/.bashrc on Linux and WSL). Reopen the terminal
Permission denied You're writing somewhere your user doesn't own, usually a system folder Prefix with sudo — but only for install commands. If you're getting this inside your own project folder, sudo is the wrong answer and something else owns your files: sudo chown -R $(whoami) . fixes that
Permission denied running a script you downloaded The file isn't marked executable chmod +x thescript.sh, then ./thescript.sh
running scripts is disabled on this system in PowerShell Windows blocks unsigned scripts by default In PowerShell: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, answer Y. This allows scripts you wrote locally and signed ones from elsewhere, which is the sensible middle setting. It only affects your own user
sudo: command not found You're in Git Bash or PowerShell, which have no sudo Close it and open an Administrator terminal (right-click → Run as administrator) — or use WSL, where sudo works normally
apt: command not found on a Mac You ran the Linux instructions Use the macOS ones — brew install …
brew: command not found on Linux or WSL You ran the macOS instructions Use sudo apt install …
You installed something in Windows and WSL can't see it They're separate systems that happen to share a screen Install it again, inside Ubuntu, using the Linux instructions
aws-cli/1.x when you installed version 2 An old copy from pip is earlier in your PATH pip uninstall awscli, reopen the terminal, check again
Everything is fine but the terminal feels hostile Entirely normal on day one You need about six commands total for this guide, and every one of them is written out for you. Paste, read the output, move on

Anything not covered here goes in 90 — When it breaks, and any word you don't recognise is in the glossary.

And the genuinely fastest route when a command fails: copy the command you ran and the entire error message, paste both into Claude Code, and add what you were trying to do. Error messages are written for people who already know the answer, and translating them is something an agent is very good at.


Next: The accounts you need →