Back to blog
Jun 12, 2026
11 min read

The README Is Dead

Install docs were always a letter mailed to a stranger's machine you'd never see. Now there's an agent sitting on that machine — and that quietly ends the install README.

Editorial illustration in near-black and warm amber: a woman works at a laptop in a dim workspace, looking at her screen, while a translucent amber-glowing figure rendered in fine luminous contour lines leans in over her shoulder, studying the same screen with her. A desk lamp glows at right; a coffee mug and papers rest on the desk.

The message arrives at 9:47 on a Tuesday.

“Hey! Loving the tool so far. Quick question — the instructions say to add it to my PATH. Is that a folder? Should I make one?”

You stare at this message for a long time. You wrote a README for this. A good README. Install steps with copy-paste blocks. Screenshots. A troubleshooting section that anticipated eleven distinct failure modes. You tested it on a clean machine, like a professional. He’s very proud of his README. I was. For about six hours.

Every builder knows the cycle, because every builder is currently in it. You make something fantastic, then you spend twice as long imagining all the ways a stranger could get hurt using it. So you document. Examples, guides, an FAQ, a troubleshooting tree. You polish the install flow until it gleams, you push the thing into the world, and Slack lights up before lunch. The user has the one machine configuration you never imagined — not even a hard one; once you see it, the fix takes five minutes. So you fold it into the docs, ship again, and a Discord pings. Different machine. Different surprise. Repeat until retirement.

Here’s the secret nobody puts in the postmortem: none of this is a documentation problem. Your README was fine. Your README was a work of art that nobody read. Nobody reads anything. He knows that, right? The actual failure modes are always the same three: a configuration you couldn’t have predicted, a user missing a skill you assumed was universal, or some corporate IT “control” silently vetoing step three. Every one of them is trivial to fix — if you’re physically in the room, looking at the machine. You are not in the room. You are in a thread, typing “huh, that’s odd — can you send a screenshot?”

So what would it take to actually be in the room?

Turns out the room already has someone in it. Almost every company is leaning into a coding harness right now: Claude Code, Windsurf, Cursor, Codex, Antigravity, Kiro, Kilo, Roo, Devin, Trae, Cline, Augment, Amp, Smithery, Qwen Code, Crush, Qodo, Factory, Zed, Gemini, Forgecode, Grok, Qoder, Pi, Droid, Plandex, OpenHands, Hermes, Aider. Those are just the ones I’ve personally installed. Is he collecting them? I’m evaluating them. Continuously. Forever.

That changes software distribution in a way I don’t think we’ve absorbed yet. If your consumer has an agent on their desktop, you are one skill installation away from having a competent assistant present at every install — one that can read their files, grep their configs, and glob its way around the actual machine, then use what it finds to get them through whatever’s in the way.

Here’s what that looks like in practice. I built a deliberately small example: a skill that sets up a custom status line in Claude Code. Drop it into the consumer’s ~/.claude/skills directory, and they get a /statusline command that installs, verifies, or uninstalls the status line — scoped to a single project or applied globally across all of them.

---
name: statusline
description: Use when the user runs /statusline, or asks to install, set up, wire up, verify, or uninstall their ccstatusline status line (model, git branch, fish-style cwd, and pixi/python segments).
allowed-tools: Bash, AskUserQuestion
---

# Status Line (ccstatusline) for Claude Code

Wires up a [ccstatusline](https://github.com/sirmalloc/ccstatusline) status line — model, git
branch, fish-style current dir, and Starship-parity **pixi** (🧚) + **python** (🐍) segments. The
native widgets travel inside the config JSON; the two segment scripts live in this repo's
`helpers/` and the config points at them by absolute path. This skill is symlinked from the
`claude-statusline` repo.

## Resolve the repo root first

This skill is symlinked into `~/.claude/skills/statusline`; the repo is two levels above that
symlink. Run this and use its output as `REPO` (an absolute path) in every command below:

!`cd -P "$HOME/.claude/skills/statusline/../.." && pwd`

## Parse the argument

The user's argument is whatever follows `/statusline` (it may be empty). Read it as
`[action] [scope] [path]`:

- **action**`uninstall`**Uninstall** graph; `verify` → run `bash REPO/scripts/verify.sh` and
  show the output; anything else (`install`, or empty) → **Install** graph.
- **scope** (install/uninstall) — if the argument contains `global`, scope = **global**. If it
  contains `project`, scope = **project** and the next token is the absolute **path**.
- **If scope was supplied in the argument, USE IT and do NOT ask.** If scope is missing (e.g. a bare
  `/statusline install`), you MUST ask for it. If scope is `project` but no path was given, ask only
  for the path.

Examples: `install global` → install globally, no prompt. `install project /abs/path` → install to
that project, no prompt (still warn about the project limitation). `install` (or bare `/statusline`)
→ ask global vs project.

## Install

**First, create a `TodoWrite` checklist** with these items and work them top to bottom — mark each
`in_progress` when you start it and `completed` when it finishes:

1. **Check prerequisites** — two *separate* checks with different remediation:
   - **Node.js / `npx`** (`command -v npx`): if MISSING, **STOP and report** — tell the user to
     install Node.js via the official docs (https://nodejs.org/en/download, or their version
     manager / pixi) and re-run `/statusline install`. `npx` ships with Node and the status line
     cannot run without it. **Do NOT attempt to install Node automatically.**
   - **`jq`** (`command -v jq`): if missing, offer to run `brew install jq` (run it only after the
     user agrees); STOP if they decline. jq is safe to auto-install.
2. **Determine scope** — if the user already gave it in the argument (`global`, or `project <abs-path>`),
   USE THAT and skip the question. Otherwise ask with **AskUserQuestion**: **Global** (every project,
   `~/.claude/settings.json`) or **Project** (a single repo). If scope is **project** with no path,
   ask for the absolute path. Whenever scope is **project**, TELL THE USER plainly: *"a project-scoped
   status line only renders while Claude is running inside that directory — step outside it and it
   disappears."*
3. **Wire it up**`bash REPO/scripts/configure-statusline.sh global`
   (or `bash REPO/scripts/configure-statusline.sh project <abs-path>`).
4. **Verify**`bash REPO/scripts/verify.sh`; show the rendered sample line.
5. **Report** — tell the user it is live (restart/refresh to see it), that ccstatusline is fetched on
   demand via `npx` (first render may lag briefly), and that the 🧚/🐍 segments self-gate (they appear
   only inside pixi / python projects).

```dot
digraph install {
    "User runs /statusline install" [shape=doublecircle];
    "Resolve REPO" [shape=box];
    "node/npx installed? (command -v npx)" [shape=diamond];
    "STOP: install Node.js via official docs, then re-run" [shape=octagon, style=filled, fillcolor=red, fontcolor=white];
    "jq installed? (command -v jq)" [shape=diamond];
    "Ask user: brew install jq?" [shape=diamond];
    "brew install jq" [shape=plaintext];
    "STOP: jq is required" [shape=octagon, style=filled, fillcolor=red, fontcolor=white];
    "scope given in args? (global / project <path>)" [shape=diamond];
    "AskUserQuestion: Global or Project?" [shape=diamond];
    "Ask for abs path + WARN: only renders inside that dir" [shape=box];
    "bash REPO/scripts/configure-statusline.sh global" [shape=plaintext];
    "bash REPO/scripts/configure-statusline.sh project <abs-path>" [shape=plaintext];
    "bash REPO/scripts/verify.sh" [shape=plaintext];
    "Report: live; npx-fetched; 🧚/🐍 self-gate" [shape=box];
    "Status line wired up" [shape=doublecircle];

    "User runs /statusline install" -> "Resolve REPO";
    "Resolve REPO" -> "node/npx installed? (command -v npx)";
    "node/npx installed? (command -v npx)" -> "jq installed? (command -v jq)" [label="yes"];
    "node/npx installed? (command -v npx)" -> "STOP: install Node.js via official docs, then re-run" [label="no — npx ships with Node"];
    "jq installed? (command -v jq)" -> "scope given in args? (global / project <path>)" [label="yes"];
    "jq installed? (command -v jq)" -> "Ask user: brew install jq?" [label="no"];
    "Ask user: brew install jq?" -> "brew install jq" [label="yes"];
    "Ask user: brew install jq?" -> "STOP: jq is required" [label="no"];
    "brew install jq" -> "scope given in args? (global / project <path>)";
    "scope given in args? (global / project <path>)" -> "bash REPO/scripts/configure-statusline.sh global" [label="global in args"];
    "scope given in args? (global / project <path>)" -> "bash REPO/scripts/configure-statusline.sh project <abs-path>" [label="project + path in args (warn)"];
    "scope given in args? (global / project <path>)" -> "Ask for abs path + WARN: only renders inside that dir" [label="project, no path in args"];
    "scope given in args? (global / project <path>)" -> "AskUserQuestion: Global or Project?" [label="no scope in args"];
    "AskUserQuestion: Global or Project?" -> "bash REPO/scripts/configure-statusline.sh global" [label="global"];
    "AskUserQuestion: Global or Project?" -> "Ask for abs path + WARN: only renders inside that dir" [label="project"];
    "Ask for abs path + WARN: only renders inside that dir" -> "bash REPO/scripts/configure-statusline.sh project <abs-path>";
    "bash REPO/scripts/configure-statusline.sh global" -> "bash REPO/scripts/verify.sh";
    "bash REPO/scripts/configure-statusline.sh project <abs-path>" -> "bash REPO/scripts/verify.sh";
    "bash REPO/scripts/verify.sh" -> "Report: live; npx-fetched; 🧚/🐍 self-gate";
    "Report: live; npx-fetched; 🧚/🐍 self-gate" -> "Status line wired up";
}
```

## Uninstall

**First, create a `TodoWrite` checklist** and work top to bottom (mark each `in_progress``completed`):

1. **Determine scope** — if given in the argument (`global` / `project <abs-path>`), use it; otherwise
   ask with **AskUserQuestion** whether it was installed **Global** or **Project** (get the path if Project).
2. **Undo the wiring**`bash REPO/scripts/deconfigure-statusline.sh global` (or
   `project <abs-path>`). This removes our `statusLine` entry and restores the previous ccstatusline
   config from the most recent backup.
3. **Report** — the status line is removed (restart/refresh to see it revert). The skill itself stays
   installed; remove it with `./uninstall.sh` from the repo.

```dot
digraph uninstall {
    "User runs /statusline uninstall" [shape=doublecircle];
    "Resolve REPO" [shape=box];
    "AskUserQuestion: was it Global or Project?" [shape=diamond];
    "bash REPO/scripts/deconfigure-statusline.sh global" [shape=plaintext];
    "bash REPO/scripts/deconfigure-statusline.sh project <abs-path>" [shape=plaintext];
    "Report: removed; restore-from-backup done" [shape=box];
    "Done (skill stays; remove via ./uninstall.sh)" [shape=doublecircle];

    "User runs /statusline uninstall" -> "Resolve REPO";
    "Resolve REPO" -> "AskUserQuestion: was it Global or Project?";
    "AskUserQuestion: was it Global or Project?" -> "bash REPO/scripts/deconfigure-statusline.sh global" [label="global"];
    "AskUserQuestion: was it Global or Project?" -> "bash REPO/scripts/deconfigure-statusline.sh project <abs-path>" [label="project"];
    "bash REPO/scripts/deconfigure-statusline.sh global" -> "Report: removed; restore-from-backup done";
    "bash REPO/scripts/deconfigure-statusline.sh project <abs-path>" -> "Report: removed; restore-from-backup done";
    "Report: removed; restore-from-backup done" -> "Done (skill stays; remove via ./uninstall.sh)";
}
```

## Notes

- The skill is symlinked, so editing the repo updates the skill in place.
- `configure-statusline.sh` backs up any existing `~/.config/ccstatusline/settings.json` to
  `.bak.<timestamp>` before overwriting; uninstall restores the most recent backup.
- The status line looks identical on every machine because the helper scripts ship in the repo's
  `helpers/` and the config references them by absolute path (resolved from `REPO`).
- To customize segments/order/colors, edit `REPO/ccstatusline.template.json` (or
  `REPO/helpers/*.sh`) and re-run `/statusline install`.

The obvious objection: “That’s a README and a shell script with extra steps.” On a good day, on your machine, it is. But this install needs Node, and the person running it is increasingly not a developer. Harnesses have escaped engineering — they’re on desktops in marketing, finance, ops. Picture a marketing associate who has never installed Node, doesn’t know Node is a thing that gets installed, and doesn’t know that “language” in this context has nothing to do with French. Your script dies at the first missing prerequisite. The agent notices Node is missing, explains what it is, and walks her to the official installer before she knows there was anything to panic about.

Two engineering notes, because “will the AI actually behave?” is the real question. First, the skill encodes its install flow as a digraph — a literal flowchart of steps and decision points — and Anthropic’s models treat these graphs like scripture: hand them a flow and they walk it node by node. Second, the skill opens by writing itself a TodoWrite checklist, so every step gets tracked to completion and nothing silently falls through. Those two structures are how you wring repeatable behavior out of a model that is, by nature, not repeatable.

I believe this is where distribution goes. Not better READMEs — no install READMEs at all. An agent over every consumer’s shoulder, handling whatever their machine throws at it.

Somewhere out there right now, someone is typing “what’s a PATH?” For the first time in forty years, something on their own computer can answer.