Architecture specification

Command Surface

An identical root Makefile in every repository, with the repository’s own components declared once in scripts/build/repository.mk.

Applies at
Makefile
Status
Stable
Source · managed
Makefile

01 Defines

The repository’s stable set of make commands: a generic, managed root Makefile that loads repository configuration and then a fixed sequence of make modules, so the same verbs work the same way in every repository.

02 Applies when

  • Developers, CI workflows, and agents need one predictable way to build, check, and deploy.
  • Several repositories should share commands without sharing their component lists.
  • Shared make modules are provided by the development environment as well as by the repository.

03 Boundaries

  • The root Makefile contains no repository-specific targets or paths.
  • Which components exist is declared in repository.mk; nothing is discovered.
  • Make orchestrates; larger behaviour lives in scripts the targets call.

Expected behaviour

  1. 01
    The root Makefile is byte-for-byte the same in every repository and is never edited locally.
  2. 02
    repository.mk declares concrete components such as HUGO_DIRS, TERRAFORM_DIRS, and LINT_COMMAND.
  3. 03
    Modules load in MAKE_MODULE_ORDER; each resolves from library directories first, then scripts/build/.
  4. 04
    A module missing from every directory is simply not loaded.
  5. 05
    Running make with no target prints the generated help.

Behaviour#

The command surface is what a developer or workflow actually types: make doctor, make build, make validate, make lint, make deploy. Behind it, the root Makefile does only three things — it finds the repository root, reads repository.mk, and includes each module in a fixed order.

FlowHow make assembles the surface
  1. 01 Root REPO_ROOT from the Makefile’s own location
  2. 02 Configure Include scripts/build/repository.mk
  3. 03 Resolve For each name in MAKE_MODULE_ORDER, the first <name>.mk across the library and repository directories
  4. 04 Include Load the resolved modules in order Make Module Registries

How the modules then contribute targets without editing each other is the Make Module Registries pattern.

Library and repository modules#

Module lookup searches MAKE_LIBRARY_DIRS — ~/.mklib/make and the usual system share and lib locations — before the repository’s own scripts/build/. A module can therefore be installed once by the Development Container and shared, or carried in the repository. The order is fixed either way, and a name found nowhere is skipped, because wildcard returns nothing for it.

Examples#

Makefile (excerpt)
MAKE_MODULE_DIRS := $(MAKE_LIBRARY_DIRS) $(MAKE_REPO_MODULE_DIR)

MAKE_MODULE_ORDER := 00-config 10-help 20-doctor 30-repo 40-docs 52-hugo 53-terraform 60-scripts 70-security 80-artifacts 81-deploy 90-aggregates

include $(MAKE_REPO_CONFIG)

define resolve_make_module
$(firstword $(wildcard $(foreach dir,$(MAKE_MODULE_DIRS),$(dir)/$(1).mk)))
endef

This repository has no 60-scripts or 80-artifacts module, and the surface works without them.

scripts/build/repository.mk (excerpt)
HELP_START := Start here: make doctor (check tools), make check.hugo (build site), make help (all targets)

HUGO_DIRS := www/specifications
HUGO_PREPARE_COMMAND := node scripts/docs/prepare-site-content.mjs

TERRAFORM_DIRS := workspaces/site env/staging/release env/prod/release

LINT_COMMAND := bash "$(REPO_ROOT)/scripts/lint.sh"