Every deploy, you type the same six commands in the same order. You have typed them forty times. Twice you have typed five of them, forgotten the sixth, and spent twenty minutes working out why the server was serving last week's build.
The idea
When a sequence stops changing, give it a name. The name can be a shell script,
an entry in the scripts block of package.json, or a slash command your AI
tool expands into a prompt. All three do the same thing: they let you invoke a
known-correct sequence in one move, so the order and the flags stop depending on
your memory. The cost is that whoever runs the name can no longer see what it
does, including you in six months.
before after
────── ─────
pnpm build pnpm deploy
rsync -a .next/static … │
ssh box 'systemctl stop …' └─► scripts/deploy.sh
scp -r .next box:/srv/app (the same six lines,
ssh box 'systemctl start …' in the same order,
curl -sf https://site/health every time)
worth naming when: the order matters, you run it often,
and getting it wrong is annoying to undoHow it works
Pick the smallest wrapper that fits.
- A shell script in
scripts/, committed to the repository. Best when the sequence touches the outside world: a deploy, a database backup, a migration run. It is a plain text file, so it is reviewable in a diff, and anyone on the project can read exactly what it will do. - An npm script, meaning a line in
package.jsonsuch as"check": "next typegen && tsc --noEmit && eslint . && vitest run". Best for the checks a developer runs constantly. (Two Next.js details, both current on 2026-08-13:next lintwas removed in version 16, so calleslintdirectly, andnext typegenis what generates the route typestsc --noEmitwould otherwise not see. Note that&&stops at the first failure, so a broken link in this chain means the later checks quietly never run.) It gives the project a vocabulary:pnpm checkandpnpm buildmean the same thing to you, to a new contributor, and to an AI assistant reading the file. - A A saved prompt in your AI tool, invoked by typing a short name like /review. It expands into the full instruction text you wrote once.,
a markdown file in
.claude/commands/. Best when what repeats is an instruction rather than a command: the way you want a code review framed, the checklist you want walked before closing a session.
Write the first version by copying what you actually typed, not what you think you should have typed. Then run it on a real case and fix what it got wrong. A procedure invented in advance encodes a workflow nobody has tested.
Make scripts fail loudly, and make them fail safely. A script that keeps going
after step three failed will happily deploy a half-built bundle, so start it
this way and make it executable with chmod +x scripts/deploy.sh:
#!/usr/bin/env bash
set -euo pipefail-e stops at the first failing command, -u on an unset variable, and
-o pipefail when any stage of a pipe fails. The shebang has to name bash
rather than sh, because pipefail does not exist in the smaller shell that
/bin/sh points at on most Linux machines.
Stopping at the first failure is right when a half-finished run is harmless. It is wrong when the middle of your script leaves the system broken. A deploy that stops the service, copies files, then starts it again will exit with your site down if the copy fails. Order those scripts so the reversible part happens first: upload the new build alongside the old one, check it answers, and only then switch over.
What to do
- Look at your terminal history for the sequence you have retyped most. That is the first script, and usually the only one you need this month.
- Standardise on
pnpm check(ornpm run check) as the one command that runs every verification your project has. Name it inCLAUDE.mdso Claude Code knows how to prove its work, and wire that same command to the hook from the previous page. The line in the file is documentation; the hook is what makes it happen on a long session. - Keep each script to one job with a name that says what it does. A
scripts/deploy.shthat also seeds the database will eventually seed the database when you did not want it to.
Where it breaks
The wrapper is also a blindfold. Once pnpm deploy exists, you stop watching
the six steps, and when step four starts failing silently you will not notice
for a while. That is a fair trade for something you have run forty times. It is
a bad trade for something you have run twice, where you are still learning what
the steps mean and the script would rob you of the learning.
A named procedure also makes it much easier for an AI assistant to run a large
action, since one short word now stands for a deploy. Keep anything that touches
production, money, or customer data behind a script you run yourself. In
practice that means keeping it out of permissions.allow in
.claude/settings.json, the patterns Claude Code may match without stopping to
ask you. A scripts/deploy.sh on that list is a deploy that can happen while
you are reading something else, and permissions.deny is the stronger
statement, because deny wins. See
what never to delegate.