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.

code
   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 undo

How 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.json such 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 lint was removed in version 16, so call eslint directly, and next typegen is what generates the route types tsc --noEmit would 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 check and pnpm build mean the same thing to you, to a new contributor, and to an AI assistant reading the file.
  • A , 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:

bash
#!/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

  1. 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.
  2. Standardise on pnpm check (or npm run check) as the one command that runs every verification your project has. Name it in CLAUDE.md so 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.
  3. Keep each script to one job with a name that says what it does. A scripts/deploy.sh that 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.