Build, Deploy and Tooling
Overview
Build scripts, CI pipelines, deploy jobs, and tooling choices are part of the codebase. Own the build as code. Build one artifact and promote it. Deploy from day one. Choose tools that fit the project, not the resume. Automate everything you do twice. This skill enforces the decisions to make whenever you touch infrastructure or evaluate a tool.
This is a rigid skill. Run the checklist in order. If you can't satisfy a step, stop and tell the user what's blocking you.
These checks matter most when shaping a release artifact — production deploy, shared CI pipeline, tool adoption that other contributors will inherit. In MVPs, prototypes, internal dev tools, and one-off scripts where the architecture is not yet settled, prefer the simplest thing that works.
When to invoke
Invoke when you're about to:
- Write or modify a build script,
Makefile,package.jsonscript,Dockerfile, or build configuration - Change a CI workflow (
.github/workflows/*,.gitlab-ci.yml, Jenkinsfile, etc.) - Author or change a deploy pipeline, release script, or environment promotion job
- Add a new dependency, framework, linter, formatter, or developer tool to the project
- Set up a new repository, devcontainer, or onboarding script
- Add a new repeated manual step to anyone's workflow (a candidate for automation)
- Configure a bug tracker, issue template, or defect-triage workflow
- Write or change an installer, a "getting started" page, or a
READMEquick-start - Review CI config, deploy pipelines, build scripts, or tooling choices
Non-triggers — do NOT invoke for
- Running the existing test suite or build (
npm test,make,docker buildon an unchanged config) - Tailing a log file or reading CI output to diagnose a failure
- Asking "what does this Makefile target do?" — read it; no design decision is being made
- Using a linter, formatter, or tool the repo already mandates with its current configuration
- Bumping a single dependency patch version because of a security advisory
- Editing a deployed service's runtime configuration through the platform's normal config interface
- An early-stage MVP or prototype where the architecture is still in flux
- An internal dev tool or one-off script whose build needs are "run this command"
- Throwaway code expected to be replaced before reaching users
If you're not sure whether a change counts as "authoring infrastructure," invoke anyway — the checklist is short and skipping it produces build scripts nobody understands.
Build/deploy/tooling checklist
Run every step in order. The sub-area headings group related principles; the numbered items run end-to-end.
Version control
- Put everything the project needs into version control before anything else. Source, build scripts, CI configuration,
Dockerfile, infrastructure-as-code, fixtures, sample data, generated-docs config, design notes, the README itself. A new contributor's setup should be a single clone plus running the documented bootstrap script — no "copy this file from Slack." Each commit should isolate one logical change, carry a message that explains the why, and not break the build. (Spinellis, 97/68.)
Builds
- The dev team owns the build as code, and refactors it. Build scripts are not someone else's problem or a configuration file beneath your attention — they decide what the executable artifact actually is, define the component boundaries, and gate every change on the way to production. Treat them with the same discipline you apply to source: name the targets clearly, factor out duplication, delete dead branches, document non-obvious steps. A build that takes a new contributor a day to get green is a bug. (Berczuk, 97/63.)
- Build one immutable artifact and promote that through every environment. The deployable artifact (container image, JAR, binary, bundle) is built once from a tagged commit. The same bytes flow through dev, staging, and prod. Environment-specific values — endpoints, credentials, feature flags — live in the environment (container env vars, config service, mounted file), never baked into the image. If the build rewrites code per environment, you cannot prove that what shipped to prod is what staging tested. (Freeman, 97/61.)
Deploy
- Deploy to a realistic clean environment from week one, and refactor the deploy process like code. Hand-crafted demo environments hide the assumptions your code makes about a developer's laptop. The first deployment should happen before there is anything interesting to deploy, so the pipeline matures alongside the application. Each environment promotion uses the same artifact from step 3 with a different config bundle. When the deploy is painful, treat the pain as a defect — change the deploy script, change the code that complicates it, do not normalize the workaround. (Berczuk, 97/20; promotion model from Freeman, 97/61.)
Tooling choice
- Respect the project's existing tool conventions before recommending a new one. If the repo already uses a linter, a test runner, a build system, a deployment target — that is the convention until the team agrees otherwise. Adding a parallel tool because you prefer it doubles maintenance and fragments contributor knowledge. When you do propose a new tool, evaluate the real costs: architectural fit with the existing stack, upgrade lifecycle and how it interacts with the other tools' upgrade cycles, configuration burden, license compatibility, lock-in risk, and whether "free" hides a paid support tier you will eventually need. Start with the smallest set that works; isolate each external tool behind an internal interface so it can be swapped later with bounded pain. (Asproni, 97/10.)
- Treat the installer / "getting started" path as the user's first impression of the product. The user has no patience for friction at install time. Detect what you can detect (platform, architecture); ask only what you cannot. Tell the user where files are written so they can clean up later. For a library or CLI, ship a five-line "Hello, world" that produces exactly the output advertised — not a wizard, not an XML scaffold. (Baker, 97/40.)
- Set up the bug tracker so reports are conversations, not accusations. A good defect report has three parts: how to reproduce (and how often), what should have happened, what actually happened. Configure issue templates that ask for those three. Make the standard query for "open bugs in my area" a one-click link every contributor knows. Status changes carry a short reason; closed-without-explanation invites re-open wars. Do not overload subject lines or fields for personal triage signals — add a real field, document it. A bug is not a unit of work, any more than a line of code is a unit of effort. (Doar, 97/38.)
Automation
- Automate the coding standard; do not rely on humans to follow it. Formatting, import order, banned APIs, complexity thresholds, test-coverage floors — encode them as commit-blocking checks and break the build when violated. A standard nobody enforces is abandoned one rule at a time under deadline pressure. The rules you cannot automate are guidelines, and you should expect them to drift. (van Laenen, 97/4.)
- Run static analysis as a first-class quality gate, not an optional script. Tests find behavioral bugs the tests imagined; static analyzers find the bug class your tests forgot — null dereferences, unused returns, possible races, unreachable branches. Pick the strongest analyzer your language supports, configure it to your project's signal/noise tolerance, and gate the build on it. When no off-the-shelf checker covers your project's specific anti-pattern, write a small one — most languages expose the AST in their standard library. (Mount, 97/79.)
- Reach for the Unix toolchest before reaching for a custom script or a heavyweight platform.
grep,sed,awk,sort, `uni