makefile-script-developer
Skill1 starsChanged 4 months agoMITView on GitHub
Write production-ready GNU Makefiles with strict shell mode (`SHELL := /bin/bash` + `.SHELLFLAGS := -euo pipefail -c`), validated multi-environment configuration via `$(filter ...)`, pre-flight check targets (`check-tools`, `check-env`), structured logging with timestamps, confirmation gates for destructive ops, layered `.env` includes, platform detection, and self-documenting help. Use this skill whenever the user asks to write a Makefile, harden an existing one, add a target, build a deploy/release pipeline, automate Terraform/Helm/Kubernetes/Docker/build workflows, or expose tasks as `make <target>` — including casual phrasings like "write a Makefile", "add a make target", "automate this in make", "give me a build pipeline", or "clean up the Makefile". Also use when reviewing an existing Makefile for safety, error handling, or organization issues.
- Reads credentials
In this repository24 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- architecture-auditSkill
- autodreamSkill
- deep-discoverySkill
- generic-by-designSkill
- gitops-cd-developerSkill
- gitops-pipeline-developerSkill
- golang-script-developerSkill
- humanizerSkill
- information-architectureSkill
- interactive-deck-builderSkill
- javascript-script-developerSkill
- linux-script-developerSkill
- plan-interviewSkill
- pre-commit-setupSkill
- python-script-developerSkill
- qaSkill
- skill-builderSkill
- teacher-modeSkill
- terraform-module-developerSkill
- typescript-script-developerSkill
- ui-deslopSkill
- xquik-x-dataSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. About 0 are common, 0 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 47
Every Makefile you write starts from this skeleton.
- Very specific: line 93
Validate the result: Run bash scripts/validate-makefile.sh <your-Makefile> — it grep-scans the file for shell strict mode, .PHONY …
- Very specific: line 128
Start every Makefile from assets/templates/.
- Very specific: line 133
Use a define run_with_log ...
- Very specific: line 135
Add confirmation gates (read -p "Type 'destroy-$(ENV)' to confirm") on destructive ops.
- Very specific: line 136
Use := (simple expansion) by default.
- Very specific: line 137
Use $$ to refer to shell variables inside recipes.
- Very specific: line 138
Write a help target with grouped sections and concrete examples.
- Very specific: line 139
Use $(MAKE) (not make) for sub-invocations.
- Very specific: line 140
Run scripts/validate-makefile.sh on the result.
- Very specific: line 147
Use = (recursive) where := (simple) would work — it bites later.
- Very specific: line 148
Run destructive ops without a read -p confirmation, or without CI=true to bypass for automation.
- Very specific: line 150
Use make instead of $(MAKE) in recursive invocations.
- Very specific: line 152
Write a Makefile without a help target, or a help that just lists targets without examples.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Makefile Script Developer
Production-ready GNU Makefiles. Strict shell + validated env + logging + safety gates.
When to use
- The user asks to write, scaffold, or harden a
Makefile. - The user wants to add or refactor a
maketarget / workflow / build pipeline. - The user wants to automate Terraform / Helm / kubectl / Docker / build / release through
make. - The user wants a self-documenting
helptarget or wants to clean one up. - A task chain ends in "and put it in a Makefile so I can run
make deploy ...".
Required structure
Every Makefile you write starts from this skeleton. Do not omit SHELL := /bin/bash, the .SHELLFLAGS line, or .DEFAULT_GOAL := help. Recipes are TAB-indented, not spaces.
SHELL := /bin/bash
.SHELLFLAGS := -euo pipefail -c
.DEFAULT_GOAL := help
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables --no-print-directory
# ---- Configuration --------------------------------------------------
ALLOWED_ENVS := dev staging prod
ENV ?= dev
ifeq (,$(filter $(ENV),$(ALLOWED_ENVS)))
$(error ENV must be one of: $(ALLOWED_ENVS))
endif
TIMESTAMP := $(shell date +"%Y-%m-%d_%H-%M-%S")
LOG_DIR := logs/$(ENV)
# ---- Pre-flight -----------------------------------------------------
.PHONY: check-tools
check-tools:
@command -v terraform >/dev/null 2>&1 || { echo "terraform not installed"; exit 1; }
@echo "Tools verified"
# ---- Help -----------------------------------------------------------
.PHONY: help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'Workflow
- Pick a starting template from
assets/templates/— copy and edit, do not rewrite from scratch:simple.mk.template— small build / lint / test Makefile.infrastructure.mk.template— Terraform / multi-env with logging, state backup, rollback.helm-deploy.mk.template— Helm install / upgrade / rollback / uninstall with timing.chart-package.mk.template— Helm chart lint / package / push to OCI registry.binary-build.mk.template— Cross-platform binary build with platform detection.
- Apply the patterns in
references/patterns.mdfor any non-obvious case (env validation, logging macros,foreacharg expansion,$(eval CMD=...)for per-recipe variables, layered.envincludes,definemacros for shared multi-step bodies). Read it on demand — don't preload it. - For multi-environment workflows (dev/staging/prod, multi-instance, multi-region, multi-layer), load
references/multi-env.md— it covers$(filter ...)validation, per-env plan files, layered-include .envpatterns, and instance auto-discovery fromenvs/*.env. - For Helm / kubectl / Terraform recipes, load
references/helm-kubectl-terraform.md— it covershelm upgrade --install --wait --timeout,helm-recover/helm-purgefor stuck releases,kubectl delete pod --force --grace-period=0, terraform plan/apply with state backup, and S3-compatible backend credential export. - For self-documenting help targets, load
references/help-target.md— covers grep-based auto-help (## comment), grouped sections, andmake helpdefaults. - For cross-platform Makefiles (Linux/macOS/Windows), load
references/cross-platform.md— coversunameplatform detection, separator differences (:vs;), exe suffix, BSD vs GNU sed. - Cross-check anti-patterns in
references/anti-patterns.mdbefore finishing — TAB vs spaces,$$vs$, missing.PHONY, recursive (=) vs simple (:=) assignment, unquoted$(VAR)in shell, missingset -o pipefail. - Validate the result. Run
bash scripts/validate-makefile.sh <your-Makefile>— it grep-scans the file for shell strict mode,.PHONYdeclarations, help target, env validation, TAB indentation,$$usage in recipes, and confirmation gates on destructive ops. Aim for ≥ 90%.
Available resources
assets/templates/simple.mk.template— minimal lint / build / test Makefile.assets/templates/infrastructure.mk.template— Terraform-style multi-env with logging, state backup, rollback, confirmation gates.assets/templates/helm-deploy.mk.template— Helm install/upgrade/rollback/uninstall with per-step timing and stuck-release recovery.assets/templates/chart-package.mk.template— Helm chart lint/package/push to OCI registry.assets/templates/binary-build.mk.template— Cross-platform binary build with platform detection.assets/examples/terraform-multi-env.mk— full reference implementation (3-env, logging, backup, rollback, helm-recover).scripts/validate-makefile.sh— score a Makefile against the checklist (run after writing).references/patterns.md— load when implementing logging macros, foreach var expansion,definebodies,$(eval)per-recipe vars, layered-include.references/anti-patterns.md— load when reviewing or rewriting an existing Makefile.references/multi-env.md— load when handling dev/staging/prod, multi-instance, multi-region, or multi-layer setups.references/helm-kubectl-terraform.md— load when wrapping Helm / kubectl / Terraform inmaketargets.references/help-target.md— load when writing a self-documentinghelptarget.references/cross-platform.md— load when targeting macOS or Windows alongside Linux.
Top gotchas (always inline — do not skip)
- Recipes are indented with a TAB, not spaces. GNU make rejects space-indented recipes with
*** missing separator. Stop.Configure your editor to keep tabs inMakefilefiles. - Use
$$to escape$in recipes.$VARin a recipe is interpreted by Make first; write$$VARto mean "shell variable" and$(VAR)for "Make variable". Single$followed by an unrecognized character silently expands to empty. SHELL := /bin/bash, never the default/bin/sh. Without it,pipefail,[[ ]], process substitution, and arrays are unavailable. macOS and Alpine/bin/share dash-like — recipes that work locally will fail on CI..SHELLFLAGS := -euo pipefail -cis the minimum.-eexits on error,-uon undefined vars,-o pipefailmakescmd1 | cmd2fail whencmd1fails. Without these, a failed step in a pipeline is silently swallowed.- Always declare non-file targets
.PHONY. Otherwise a stray local file nameddeployorcleanmakes Make skip the recipe with "target is up to date". :=(simple) vs=(recursive). Use:=for almost everything — it expands once at parse time.=re-evaluates on every reference, which is slow and surprising (e.g.TIMESTAMP = $(shell date)regenerates the timestamp on every reference). Use=deliberately when you need lazy evaluation (e.g.LOG_FILE = $(LOG_DIR)/$(CMD).logwhereCMDis set per-target via$(eval CMD=apply)).- Validate
ENVearly with$(filter ...).ifeq (,$(filter $(ENV),$(ALLOWED_ENVS)))+$(error ...)halts before any side effects. Don't rely on a runtime[ ... ] || exit 1inside a recipe — it runs after dependencies. - Confirmation gates use
read -p+ check.[ "$$confirm" = "destroy-$(ENV)" ] || (echo "Cancelled"; exit 1)— the$(ENV)ties the confirmation string to the environment so a copy-pasted prompt can't destroy prod by mistake. - Secrets in recipes: prefix lines with
@to suppress the echoed command, and neverecho $$SECRET. Pull credentials from env vars or ayq-readable secrets file rather than hardcoding them; use--password-stdininstead of-pflags. make -jis unsafe by default: targets sharingLOG_FILEor temp files will clobber each other. Use.NOTPARALLEL:for workflows that must serialize, or generate per-target temp paths.$(MAKE)notmakefor sub-invocations —$(MAKE)propagates-n,-j, andMAKEFLAGS. Plainmakestarts a fresh process and breaks dry-run / parallel mode.shellis evaluated at parse time.TIMESTAMP := $(shell date)runs once when Make reads the file — that's usually what you want, butfind ... -deleteinside$(shell ...)will run before any target executes.
What you DO
- Start every Makefile from
assets/templates/. - Set
SHELL := /bin/bash,.SHELLFLAGS := -euo pipefail -c,.DEFAULT_GOAL := help,.DELETE_ON_ERROR:, andMAKEFLAGS += --warn-undefined-variables --no-print-directory. - Validate
ENV(and any other enum input) up-front with$(filter ...)+$(error ...). - Declare every non-file target as
.PHONY. - Provide pre-flight
check-tools/check-env/check-statetargets and depend on them. - Use a
define run_with_log ... endefmacro to capture all output tologs/<scope>/<env>/<cmd>_<timestamp>.log. - Group related operations into composite workflow targets (
deploy: validate init plan apply). - Add confirmation gates (
read -p "Type 'destroy-$(ENV)' to confirm") on destructive ops; bypass withCI=truefor non-interactive runs. - Use
:=(simple expansion) by default; reserve=for genuinely lazy values. - Use
$$to refer to shell variables inside recipes; use$(VAR)for Make variables. - Write a
helptarget with grouped sections and concrete examples; make it the.DEFAULT_GOAL. - Use
$(MAKE)(notmake) for sub-invocations. - Run
scripts/validate-makefile.shon the result; iterate until ≥ 90%.
What you do NOT do
- Indent recipes with spaces, or rely on auto-detection.
- Forget
set -e/pipefailand let pipe failures slip past silently. - Skip
.PHONYdeclarations on non-file targets. - Use
=(recursive) where:=(simple) would work — it bites later. - Run destructive ops without a
read -pconfirmation, or withoutCI=trueto bypass for automation. - Leak secrets to logs (no
echo $$PASS, no missing@on credential-bearing lines). - Use
makeinstead of$(MAKE)in recursive invocations. - Hardcode
/home/<user>/...or/Users/<user>/...— use relative paths or$(CURDIR). - Write a Makefile without a
helptarget, or ahelpthat just lists targets without examples. - Mix multiple unrelated responsibilities in a single recipe (deploy + log-cleanup + notify) — split them and depend.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

