Every codebase accumulates rituals: the four commands to set up a new module, the checklist before a release, the manual edit in three files whenever an endpoint is added. Each is small. Collectively they are the reason a change that should take an hour takes an afternoon, and they are invisible because everyone has internalised them.
The arithmetic is worth doing once. A five-minute task performed twice a week by six engineers is roughly a working week per year. Most such tasks take an hour to automate.
Automate the error-prone before the tedious
Time saved is the obvious criterion and not the best one. The higher-value target is anything where a human doing it manually makes mistakes: a multi-step process with an easily forgotten step, an edit that must be applied consistently across several files, or a checklist where one omission causes an incident. Those are worth automating even when they are infrequent.
# A Makefile is the discoverable entry point. If it is not here, it does not
# exist as far as a new engineer is concerned.
.PHONY: help
help: ## Show this help
@grep -E '^[a-z-]+:.*?## ' $(MAKEFILE_LIST) | awk -F':.*## ' '{printf " %-18s %s\n", $$1, $$2}'
bootstrap: ## Set up everything needed to work on this repo
uv sync --frozen && docker compose up -d && uv run python tools/seed.py
new-module: ## Scaffold a module with its tests, wiring and boundary config
uv run python tools/scaffold.py $(NAME)
check: ## Everything CI will run, locally, in parallel
ruff check . & mypy src/ & uv run pytest -x -q & wait
release: ## Tag, changelog, and the three things people forget
uv run python tools/release.py --check-migrations --check-flagsThe help target matters more than it looks. Automation nobody can find gets rewritten as a manual process by the next person who joins, and then you have both. One command that lists every command is the cheapest discoverability mechanism available.
Keep the automation cheap
- Automation is code: it breaks, it needs owners, and a script nobody maintains is worse than a documented manual step.
- Prefer generating a starting point over enforcing a framework. A scaffold that produces editable files ages better than one that owns them forever.
- Make hooks fast. A pre-commit hook over ten seconds gets bypassed with --no-verify, which is strictly worse than not having it.
- Fail loudly with an actionable message. A script that silently does nothing when a precondition is missing costs more than the task it replaced.
- Delete automation for processes that no longer exist. Stale scripts are traps for whoever tries them next.
The test of good tooling is not whether it saves time. It is whether a new engineer can do the thing correctly on their first attempt without asking anyone.
Coding agents shift this balance further, because the cost of writing a small internal tool has dropped substantially. Tasks that were not worth forty minutes of scripting are now worth five, which means the reasonable threshold for automating something has moved — and a fair amount of the friction people still tolerate is tolerated out of habit rather than arithmetic.