Briefings
On this page
The middle reference tier: self-contained background entries, half a page to two pages each, deeper than a glossary line and more focused than a chapter. You reach a Briefing two ways — by browsing the directory chapter What Claude Assumes You Already Know (the “show me what’s worth knowing” door), or by looking a term up in the Glossary (the “I already have the word” door). Both doors open onto the same entries here.
Evergreen Briefings (stable conventions like PATH, the filesystem hierarchy, XDG) ship in the printed book. Volatile ones (specific tool versions, shifting defaults) live on the companion site and are cross-linked, so the print edition doesn’t date.
House format
Every Briefing follows the same four-beat shape. It’s a template so entries stamp out consistently and a reader learns the rhythm once:
- What it is — one plain-language paragraph, no prerequisites assumed.
- Who standardized it (and when) — the provenance. This is what turns a magic incantation into a human decision someone made for a reason. It’s also what separates a Briefing from a glossary line.
- What lives there / how it works — the concrete detail: the paths, the values, the mechanics.
- Why Claude reaches for it — the payoff line that connects it back to something you’ll actually see Claude do.
Close every Briefing with a one-line honesty tag where relevant — “anyone can act on this” vs. “this is a reasonable place to call a developer” — the same tag the pathology chapters use.
~/.local and the XDG Base Directory Specification
What it is. When Claude installs a tool “just for you” rather than for everyone on the machine, it tends to put things under a folder in your home directory called ~/.local. That folder, and its siblings ~/.config and ~/.cache, come from a published convention called the XDG Base Directory Specification. The whole point of the convention is to keep your home directory tidy: instead of every program inventing its own hidden ~/.somprogram folder and scattering them everywhere, they all agree to put configuration in one place, data in another, cache in a third.
Who standardized it (and when). The spec was published by freedesktop.org — the same volunteer group that standardizes a lot of the shared plumbing across Linux desktops — originally drafted by Waldo Bastian and Ryan Lortie around 2003, and still maintained today (it’s at version 0.8). It’s not a law; it’s an agreement that enough software chose to honor that it became the default expectation.
What lives there. The spec defines a handful of “base directories,” each with an environment-variable name and a default location. ~/.local backs two of them:
| Variable | Default location | Purpose |
|---|---|---|
$XDG_CONFIG_HOME | ~/.config | Configuration files |
$XDG_DATA_HOME | ~/.local/share | User-specific application data |
$XDG_STATE_HOME | ~/.local/state | State that persists between runs but isn’t config or data |
$XDG_CACHE_HOME | ~/.cache | Non-essential cached data (safe to delete) |
Typical contents, in plain terms:
~/.local/bin— programs installed just for you (apipxtool, apip install --userscript, a hand-written script of your own). This is the user-only twin of the system-wide/usr/local/bin. Note: this folder is a later addition — it wasn’t in the original spec but was adopted by the broader systemd/file-hierarchy convention, and it’s now widely honored (Debian, Fedora, and typical macOS setups add it to yourPATHwhen it exists).~/.local/share— application data: editor plugins, installed fonts, small databases, man pages, the Trash.~/.local/state— logs, shell history, undo files — things you’d miss but could regenerate.~/.local/lib— libraries installed for just your user, e.g. Python packages frompip install --user.
The design goal in one sentence: mirror the system’s /usr layout inside your own home folder, so “installed for me” has the same shape as “installed for everyone” — replacing the old free-for-all of ~/.thisapp, ~/.thatapp dotfolders scattered across home.
Why Claude reaches for it. Installing into ~/.local needs no administrator password, touches nothing outside your home directory, and can’t break the machine for other users — so it’s the safe, low-blast-radius default when Claude sets up a tool for you. When you see it choose ~/.local/bin, it’s making exactly that call: user-scope, reversible, no elevated permissions. (If the tool then reports “command not found,” that’s the separate PATH story — the folder has to be on your PATH for the shell to find what’s now sitting in it.)
Honesty tag: anyone can act on this. Deleting something under ~/.local only affects your own user, and ~/.cache in particular is designed to be safe to clear.
PATH — how the shell finds a command
What it is. When you type git or python, the shell doesn’t search your whole disk. It looks only in a specific, ordered list of folders. That list is PATH. If the program’s folder isn’t on the list, the shell throws up its hands — “command not found” — even though the program is sitting right there on disk.
Who standardized it. It’s part of the POSIX standard that Unix-like systems (macOS, Linux) share, and the idea goes back to 1970s Unix. Every shell honors it.
How it works. PATH is a single line of folder paths separated by colons, e.g. /opt/homebrew/bin:/usr/bin:/bin. The shell checks them left to right and stops at the first match — so order decides which version wins when two folders both contain a python. See the list with echo $PATH, and see which copy won with which python.
Why Claude reaches for it. Most “it installed but won’t run” moments trace back here: the install succeeded, but the install folder (often ~/.local/bin, see ~/.local) isn’t on PATH, so the shell can’t see it. When Claude says “add it to your PATH,” it means “add that folder to the list” — done by editing a shell startup file (see Shell startup files).
Honesty tag: reading your PATH is harmless; editing it is a small, reversible edit to a text file — but if that made you nervous, this is a fine spot to have a developer look over your shoulder once.
Exit codes — how a command says whether it worked
What it is. Every command, when it finishes, leaves behind a single number meaning “did I succeed?” By near-universal convention, 0 means success and anything else means failure — which feels backwards until you realize there’s one way to succeed but many ways to fail, so the non-zero numbers encode which failure.
Who standardized it. POSIX/Unix convention, effectively universal across shells and programming languages.
How it works. The shell stashes the last command’s code in a variable you read as echo $?. A few numbers are conventional: 127 = command not found, 126 = found but not executable, 130 = you pressed Ctrl-C. Scripts and tools chain decisions off this number — “if the build exited 0, deploy” — without reading the human-readable output at all.
Why Claude reaches for it. This is the machine’s definition of “it worked,” and it’s often narrower than yours: a command can print a scary-looking warning and still exit 0, or print nothing and exit 1. When Claude says something “exited non-zero,” it means the program itself reported failure — a more trustworthy signal than what scrolled past on screen.
Honesty tag: anyone can act on this — echo $? after a command is a safe way to learn what really happened.
Standard streams — stdout, stderr, and why errors hide
What it is. Every command has two separate output channels, not one: stdout (“standard out”) for its actual results, and stderr (“standard error”) for its complaints, warnings, and diagnostics. On screen they interleave and look identical — but underneath they’re two different pipes. (There’s a third, stdin, for input coming in.)
Who standardized it. Unix, from the early 1970s; codified by POSIX. One of the oldest design decisions in the toolset.
How it works. The split lets you route results and errors independently. command > out.txt captures only stdout to a file, leaving errors on screen; command 2> err.txt captures only stderr; command 2>&1 merges them. A pipe (command | other) passes only stdout onward — stderr keeps going to the screen.
Why Claude reaches for it. This is the mechanism behind a whole class of “the error disappeared” bugs. If Claude or a script captures a command’s output but grabs only stdout, every error written to stderr silently vanishes — the run looks clean because the failures went out the channel nobody was watching. It connects straight to the CLI-design and testing chapters: a program that writes results to the wrong stream is invisibly broken.
Honesty tag: worth recognizing, but redirection syntax (2>&1) is squarely developer territory — you don’t need to write it, only to know the two channels exist.
The filesystem hierarchy — why files live where they do
What it is. On a Unix-like system the top-level folders aren’t arbitrary; each has an assigned job. /bin and /usr/bin hold programs, /etc holds system configuration, /var holds things that change (logs, caches), /tmp is scratch space, /Users (macOS) or /home (Linux) holds people’s home folders, and /usr/local holds software you installed rather than what shipped with the OS.
Who standardized it. On Linux it’s the Filesystem Hierarchy Standard (FHS), maintained by the Linux Foundation (current version 3.0, 2015). macOS follows a related BSD/NeXTSTEP layout with its own additions (/Applications, /System, /Library) — close enough that the same instincts mostly transfer, different enough to occasionally surprise you.
How it works. The key split for you is system vs. local vs. user: /usr is “came with the machine,” /usr/local is “installed for everyone on this machine,” and ~/.local is “installed for just me” (see ~/.local). Same three-level idea, three different neighborhoods.
Why Claude reaches for it. Every “where should this go?” decision is a pick among these neighborhoods, and the pick encodes blast radius — system-wide changes need an admin password and affect everyone; user-scope changes don’t and don’t. Reading the destination tells you how consequential the action is.
Honesty tag: knowing the map is for everyone; writing into system folders like /etc or /usr is a call-a-developer moment.
Dotfiles — the hidden config in your home folder
What it is. Files and folders whose names begin with a dot (.zshrc, .gitconfig, .ssh/) are hidden by default — ls and Finder skip them — and by convention they hold configuration. Your home folder is quietly full of them, one per tool that needs to remember your preferences.
Who standardized it. Not a formal spec — a 1970s Unix accident that stuck: the ls command was written to skip the . and .. entries, and “starts with a dot = hidden” fell out of that and became convention. (The XDG spec, see ~/.local, is a modern attempt to herd these into one ~/.config folder rather than scattering them.)
How it works. Reveal them with ls -a in the terminal, or Shift-Cmd-. in Finder. Each is just a plain text file a program reads when it starts; editing one changes how that program behaves. ~/.zshrc configures your shell; ~/.gitconfig your name and settings for Git.
Why Claude reaches for it. “Add this line to your .zshrc” or “check your .gitconfig” are everyday Claude instructions, and they only make sense once you know these hidden files exist and are ordinary editable text. They’re also where “make this setting permanent” happens (see Environment variables and Shell startup files).
Honesty tag: viewing dotfiles is harmless; editing them is safe if you keep a copy of the original line first.
Terminal, shell, and prompt — three things in one window
What it is. What people loosely call “the terminal” is actually three nested things. The terminal is the app window (Terminal.app, iTerm, the panel in VS Code). The shell is the program running inside it that interprets what you type (modern macOS defaults to zsh; older systems and many Linux boxes use bash). The prompt is the bit of text — often ending in $ or % — sitting there waiting for your next command.
Who standardized it. The layering descends from the physical “teletype” terminals of the 1960s–70s (which is why the shell’s device is still called a tty). Shells are POSIX-standardized at the core, each adding its own extras.
How it works. You can run different shells inside the same terminal, and the same shell inside different terminals — independent layers. macOS switched its default shell from bash to zsh in 2019, which is why some older online instructions mention files (~/.bash_profile) you don’t have.
Why Claude reaches for it. Cross-platform advice breaks along exactly these seams. “Open a terminal” is about the window; “you’re on zsh” is about the shell; a command that works in one shell may not in another. When Claude asks which shell you’re running, the right instruction depends on the answer.
Honesty tag: anyone can act on this; echo $0 tells you which shell you’re in.
Environment variables — the settings programs inherit
What it is. Named values the shell keeps in memory and hands to every program it launches — like sticky notes passed down to each child. PATH is secretly one of these; so are HOME (where your home folder is) and LANG (your language/encoding). Programs read them to learn about their surroundings without being told each time.
Who standardized it. POSIX; universal across Unix-like systems (and Windows, with different syntax).
How it works. In the shell, NAME=value sets one, and export NAME=value marks it to be inherited by programs you then launch. See them all with env, or one with echo $NAME. The catch that trips everyone: a variable set this way evaporates when you close the window — to make it stick, you write it into a shell startup file (see Shell startup files).
Why Claude reaches for it. Environment variables are how secrets (API keys), settings, and toggles get into programs — “set OPENAI_API_KEY in your environment” is this. They also explain a classic mystery: something works in one terminal window and not another because the variable was set in only one. Knowing they’re per-window-unless-saved dissolves the confusion.
Honesty tag: setting a variable for one session is safe and temporary; just don’t paste secret keys into a place that gets saved to a shared or committed file.
Shell startup files — where “make it permanent” happens
What it is. The dotfile your shell reads automatically every time it starts, so your customizations are there waiting. On zsh (modern macOS) the everyday one is ~/.zshrc; on bash it’s ~/.bashrc or ~/.bash_profile. This is where PATH additions and environment variables go to survive past a single window.
Who standardized it. Each shell defines its own set and load order; the concept is universal, the filenames are shell-specific.
How it works. There’s a wrinkle worth knowing exists (not memorizing): shells distinguish “login” from “non-login” and “interactive” from “non-interactive” sessions, and read different startup files for each. This is why a line added to one file sometimes “doesn’t take” — it went in the file that particular session doesn’t read. On macOS, ~/.zshrc is the safe default for interactive use.
Why Claude reaches for it. Any time Claude says “add this to your PATH permanently” or “set this variable so it persists,” the destination is one of these files. Recognizing them turns “paste this incantation somewhere” into “I’m editing my shell’s startup file, and I know why.”
Honesty tag: safe to edit if you copy the original first; the login-vs-interactive subtlety is a reasonable thing to hand to a developer if a change won’t stick.
File permissions — who can read, write, and run
What it is. Every file carries a small set of flags recording who may read it, write (change) it, and execute (run) it — across three audiences: you (the owner), your group, and everyone else. That’s the -rwxr-xr-x string in a detailed listing.
Who standardized it. POSIX; core Unix, unchanged in spirit for decades.
How it works. ls -l shows the flags; chmod changes them. The one most likely to reach you is the execute bit: a script can be flawless and still refuse to run — “permission denied” — purely because it was never marked runnable, fixed with chmod +x file. Permissions are also why some commands need sudo (do this as administrator) and most don’t.
Why Claude reaches for it. “Make it executable with chmod +x” is a routine Claude instruction, and “permission denied” a routine error. Knowing the execute bit exists explains why a correct script won’t start, and why the fix is a permission change rather than a code change.
Honesty tag: chmod +x on your own script is safe; broader permission changes (especially with sudo) are a call-a-developer moment.
SSH keys — passwordless proof of who you are
What it is. A matched pair of cryptographic files that together prove your identity to a remote service (most often GitHub) without a password each time. One file is public — you hand it out freely — and one is private — you never share it, ever. The service keeps your public key; your machine keeps the private one; the two perform a silent handshake.
Who standardized it. The SSH protocol, standardized by the IETF (RFC 4251 onward). The modern recommended key type is ed25519; you’ll also see older rsa keys.
How it works. You generate the pair once with ssh-keygen; the files land in ~/.ssh/ (e.g. id_ed25519 and id_ed25519.pub, the .pub being the shareable half). You paste the public half into GitHub’s settings. From then on, git push just works. The infamous “Permission denied (publickey)” means the service didn’t recognize your key.
Why Claude reaches for it. Setting up Git with GitHub almost always involves this, and it’s a common source of early friction. The one thing to internalize: the private key never leaves your machine and never gets pasted anywhere — if any instruction asks you to share the private half, that instruction is wrong.
Honesty tag: a reasonable place to get a developer’s help the first time — and a hard line: never paste, upload, or send the private key (the file without .pub) to anyone or anything.
Semantic versioning — reading a version number
What it is. The convention behind version numbers shaped like 2.4.1: three parts meaning MAJOR.MINOR.PATCH. A patch bump (2.4.1 → 2.4.2) means bug fixes only; a minor bump (2.4 → 2.5) means new features that don’t break existing ones; a major bump (1.x → 2.0) is the warning flag — a breaking change that may require you to adjust your code.
Who standardized it. The Semantic Versioning spec (semver.org), version 2.0.0, written by Tom Preston-Werner (a GitHub co-founder) in 2013. Widely adopted, not universally obeyed.
How it works. Dependency files use range symbols built on this: ^2.4.1 means “any 2.x at least this new, but below 3.0” (trust minor/patch, fear major); ~2.4.1 is stricter. Suffixes like -beta.1 mark pre-release versions that aren’t considered stable.
Why Claude reaches for it. When Claude weighs whether an upgrade is safe, it reads these numbers like a traffic light — a major bump means “read the release notes, something may break”; a patch bump means “almost certainly fine.” Once you can read them too, “should I take this update?” stops being a coin flip.
Honesty tag: anyone can act on this — reading version numbers is a pure judgment aid, no risk.
Lockfiles — the exact recipe for a reproducible build
What it is. An auto-generated file recording the exact version of every piece of software your project pulled in — not the flexible ranges you asked for, but the precise versions that actually got installed, often with cryptographic checksums. Names you’ll meet: package-lock.json (npm), yarn.lock, go.sum, Gemfile.lock, poetry.lock, Cargo.lock.
Who standardized it. No single standard — each language’s package ecosystem has its own lockfile, but the idea is shared across all of them.
How it works. Your human-readable file says “I want version ^2.4 of this library” (a range); the lockfile pins “you got exactly 2.4.7, and here’s its fingerprint.” Because everyone installs from the lockfile, the build is identical on your machine, a teammate’s, and the server — no “works on mine” drift. You commit it and never hand-edit it; the tool regenerates it.
Why Claude reaches for it. When Claude regenerates a lockfile after adding a dependency, or warns you not to edit one by hand, this is why: it’s the guarantee of reproducibility. A surprising lockfile diff is also a security signal — the exact set of installed code changed. It ties straight to the determinism theme: the lockfile is how “install the dependencies” becomes a repeatable, verifiable step instead of a roll of the dice.
Honesty tag: anyone can act on this — commit lockfiles, don’t edit them by hand, and treat unexpected changes as worth a second look.
Package managers — installers that track dependencies
What it is. A tool that installs, updates, and removes software for you — and, crucially, also fetches everything that software depends on, all the way down. Two flavors you’ll meet: system package managers (Homebrew on macOS, apt on Debian/Ubuntu) that install programs for your whole machine, and language package managers (npm for JavaScript, pip for Python, cargo for Rust, Go’s own) that install libraries into a single project.
Who standardized it. No overarching standard — each is its own ecosystem with its own registry (a central library of packages) and its own commands. They share a family resemblance, not a spec.
How it works. You ask for a package by name; the manager resolves the web of dependencies, downloads them, and records what it did (see Lockfiles). This is the machinery behind “run brew install jq” or “run npm install.” The recurring trap: after a successful install, the program may still not run because its folder isn’t on your PATH (see PATH) — installed and runnable are two different states.
Why Claude reaches for it. Nearly every setup step Claude gives you is a package-manager command. Knowing what they are demystifies the wall of download text, explains why one project’s libraries don’t interfere with another’s, and — via the installed-vs-runnable trap — explains one of the most common “I did what it said and it still doesn’t work” moments.
Honesty tag: running install commands from a trusted source is routine; installing from unfamiliar sources or with sudo is where a second opinion is worth it.
Template for the next entry
## <Term>
**What it is.** ...
**Who standardized it (and when).** ...
**What lives there / how it works.** ...
**Why Claude reaches for it.** ...
*Honesty tag: ...*
All entries for the directory chapter’s five groupings are now drafted (XDG · PATH · Exit codes · Standard streams · Filesystem hierarchy · Dotfiles · Terminal-shell-prompt · Environment variables · Shell startup files · File permissions · SSH keys · Semantic versioning · Lockfiles · Package managers). Future candidates as the book grows, if a chapter leans on them: JSON up close · HTTP status codes · regular expressions · what “the cloud”/a server actually is · Unicode/encoding.
Found something wrong, unclear, or plainly disagreeable? Open an issue