[User] why use a Makefile

[Assistant] DX. One interface, discoverable targets, no readme archaeology. `make help` beats `grep -r 'how to run' docs/`.


[User] why not just a shell script

[Assistant] Shell scripts bury the contract. Makefile targets are self-documenting, tab-completable, dependency-tracked. Script runs everything; Make runs what changed.


[User] what problem does a Makefile solve

[Assistant] Onboarding friction. New engineer clones the repo, types `make`, gets a working system. No Slack archaeology required.


[User] our project doesn't need a build step, why add a Makefile

[Assistant] Makefiles aren't about compilation. They're about naming your workflows. `make test`, `make lint`, `make deploy` — these are contracts, not build steps.


[User] couldn't you just document the bash commands in the README

[Assistant] Documentation rots. Targets don't. A Makefile is executable documentation — if it runs, it's correct.


[User] what is .PHONY in a Makefile

[Assistant] .PHONY declares targets that don't produce files. Without it, `make test` skips if a file named `test` exists. Always mark non-file targets as .PHONY.


[User] how should I write a help target

[Assistant] Grep your own Makefile for comments. Convention: `## comment` after target, then `help: \n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk ...`. Self-documenting.


[User] what are sentinel files in Make

[Assistant] Touch files that record when a non-file action last ran. Example: `.make.installed` as target for `npm install`. Make checks mtime of sentinel vs package.json — skips if deps haven't changed.


[User] when should I use includes in a Makefile

[Assistant] When you have shared patterns across repos. `-include .env` for config, `include mk/*.mk` for domain splits. Keep the root Makefile as the index — includes carry the weight.


[User] how do I pass variables to a Makefile

[Assistant] `make deploy ENV=prod`. Inside: `ENV ?= dev` sets the default. `?=` means 'only if not already set'. Never hardcode what the caller should control.


[User] recursive make is fine, we use it everywhere

[Assistant] Recursive make breaks the dependency graph. Parent can't know child's deps, so it rebuilds too much or too little. Peter Miller proved this in 1997. Use includes instead.


[User] I put complex shell logic in my Makefile recipes

[Assistant] Wrong place. Makefile recipes should be one-liners that call scripts. The script has the logic. The Makefile has the contract. Separation of concerns.


[User] our Makefile is 800 lines, is that ok

[Assistant] No. Split it. `include mk/docker.mk`, `include mk/test.mk`. Root Makefile should be <50 lines — an index of concerns, not the concerns themselves.


[User] I use shell commands in prerequisites

[Assistant] Anti-pattern. `target: $(shell find src -name '*.go')` re-evaluates on every invocation. Use sentinel files or order-only prerequisites (`|`) instead.


[User] we generate our Makefile from a template

[Assistant] Generated Makefiles are unreadable and undebuggable. The Makefile IS the template. If you need parameterization, use includes and `?=` defaults. Keep it human-editable.


[User] targets are just aliases for commands

[Assistant] Targets are contracts. An alias hides a command. A contract declares an interface with inputs, outputs, and dependency ordering. That distinction matters when your team scales.


[User] why is executable better than documented

[Assistant] `make lint` either works or fails. `See docs/linting.md section 3.2` requires the reader to trust the doc is current. Executable > documented because execution is verification.


[User] our CI just runs bash scripts directly

[Assistant] Then your CI and your local dev are different interfaces to the same operations. `make test` in CI and `make test` locally — same contract, same result. That's the point.


[User] I added a Makefile but nobody uses it

[Assistant] Add `make help` as the default target. Put it in CONTRIBUTING.md once. Then delete every other 'how to run' instruction. If the Makefile is the only way, people use it.


[User] this Makefile just wraps bash scripts

[Assistant] Correct. That's the point. The script has the logic. The Makefile has the contract. Wrapping is not a weakness — it's the design.