Generating Makefiles as Ops Task Runners with AI (Without the Tab Pain)
A Makefile is the simplest task runner that's already installed everywhere. Use AI to draft self-documenting targets, then review for the classic make footguns.
- #bash
- #python
- #make
- #automation
Every repo I inherit eventually grows a pile of shell scripts named deploy.sh, deploy-staging.sh, deploy-staging-but-skip-tests.sh, and a README nobody updated explaining which one is current. The cure is boring and it’s been sitting on every Unix box since 1976: a Makefile. It’s a task runner that’s already installed, needs no dependencies, and gives you make deploy instead of a directory of ambiguous scripts. The catch is that make syntax has sharp edges — tabs, not spaces; shell-per-line semantics; variable expansion that surprises people — and that’s exactly the kind of fiddly-but-bounded work an AI assistant handles well.
I use the AI as a fast junior who knows the make quirks cold. I still review every target before it runs against anything real.
Why a Makefile beats a folder of scripts
A Makefile gives you a single discoverable entrypoint. Tab-complete make and your shell offers the targets. New engineers run make help and learn the repo’s operations in one screen instead of spelunking through scripts/.
.PHONY: lint test build deploy
lint: ## Run all linters
ruff check .
shellcheck scripts/*.sh
test: ## Run the test suite
pytest -q
.PHONY declares targets that aren’t files — without it, make test would do nothing if a file named test happened to exist. That’s the first thing I check in any AI-generated Makefile, because models forget it constantly.
The self-documenting help target
The single best pattern to ask the AI for is a help target that parses the ## comments out of the file itself. It means your documentation can never drift from your targets, because it is your targets.
.DEFAULT_GOAL := help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}'
This is a perfect AI task: it’s a gnarly one-liner mixing grep, awk, and ANSI color codes that almost nobody writes from memory. Ask for it, drop it in, and every target with a ## comment shows up automatically. Note the doubled $$ — in a Makefile, a single $ means a make variable, so a literal shell $ must be escaped. That doubling is the second classic bug to review for.
Real ops targets, generated from intent
Describe what you want in plain language and let the AI produce the targets. A prompt I reuse:
Generate Makefile targets for a Python service:
venvto create a virtualenv,installdepending onvenv,test, andclean. Use.PHONYcorrectly and add## help comments.
VENV := .venv
PY := $(VENV)/bin/python
$(VENV)/bin/activate:
python3 -m venv $(VENV)
$(VENV)/bin/pip install -U pip
install: $(VENV)/bin/activate ## Install dependencies
$(PY) -m pip install -r requirements.txt
clean: ## Remove build artifacts and venv
rm -rf $(VENV) .pytest_cache __pycache__ *.egg-info
Notice the AI used the file $(VENV)/bin/activate as the prerequisite rather than a .PHONY target — that’s the right call, because it lets make skip recreating the venv if it already exists. When the model gets that subtlety right, you get real dependency tracking; when it doesn’t, you get a venv rebuilt on every run. Reviewing for it is the difference.
Pro Tip: Each line in a recipe runs in its own subshell, so cd foo on one line does not affect the next. If a generated target does cd dir then expects to be there on the following line, it’s broken. Chain with && on a single line, or set .ONESHELL: at the top of the file.
The dangerous targets need the most review
The further a target reaches toward production, the harder you look. A make deploy that AI drafts will look clean and might still be wrong in a way that costs you.
deploy: ## Deploy to the current kube context — DANGER
@echo "Deploying to context: $$(kubectl config current-context)"
@read -p "Continue? [y/N] " ans && [ "$$ans" = "y" ]
kubectl apply -f k8s/
That confirmation prompt and the echo of the current context are things you should add during review even if the AI omitted them, because a deploy target that doesn’t tell you which cluster it’s about to hit is an outage waiting for a tired engineer. Treat any target that mutates infrastructure as needing the same scrutiny you’d give a code review on a hot path.
Passing arguments and environment safely
A frequent ask is parameterized targets, and there’s a clean idiom the AI should reach for:
ENV ?= staging
release: ## Release to ENV (default staging): make release ENV=prod
@echo "Releasing to $(ENV)"
./scripts/release.sh "$(ENV)"
ENV ?= staging sets a default only if unset, so make release ENV=prod overrides it. What you must not let creep in is secrets baked into the Makefile — no API tokens, no passwords as variables. Those belong in the environment or a secrets manager, read at runtime, never committed. If an AI-generated target hardcodes a credential, that’s an automatic reject; hand the model placeholder values and wire the real ones in yourself.
Keep the Makefile honest over time
The reason a Makefile rots less than a script folder is that it’s small and central, but it still needs tending. As targets accumulate, ask the AI to factor common prefixes into variables and to verify every recipe target is in .PHONY. I keep a standing prompt for “review this Makefile for missing .PHONY entries, unescaped $, and cd-across-lines bugs” — the three failure modes that account for nearly every broken Makefile I’ve debugged. You’ll find that prompt and others in our prompt library and the curated prompt packs.
For drafting and reviewing, I reach for Claude or GitHub Copilot inline; the rest of the Bash and Python automation category covers the scripts these targets end up calling.
The standing rule
A Makefile is glue that runs other people’s destructive commands, which makes it deceptively high-stakes for how simple it looks. The AI is your quick junior for the syntax; you’re the one who confirms a deploy target points at the right cluster, that no secret is hardcoded, and that every recipe does what its ## comment claims. Draft fast, review hard, ship clean.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.