An install under a custom prefix (--prefix ~/.local) could not find the
catalogue it had just cloned into <prefix>/share/myos: only the three system
paths were searched.
The skill documents how to use myos: what to check before touching a host
stack, how a reference resolves, what the three kinds of stack mean, and where
each failure comes from. Every command it shows was run against the fixtures
before being written down, which is how exec, run and scale turned out to be
missing.
AGENTS.md covers the other side: how to change myos without breaking the
deployments that already run it.
holcommon's empty .env made the loader evaluate one blank line, which
tripped set -u. Verified afterwards on holcommon's real host stack: the CLI
and the make engine resolve the same five files and render a byte-identical
241-line compose config.
Both engines now go through the same 68 cases. 31 produce byte-identical
output; the rest have a recorded CLI expectation and a reason in DELTAS.md,
the bulk of it being that the CLI does not shell out to a recursive make and
calls compose once per project.
Fixed while comparing: the CLI was missing the COMPOSE_FILE_* defaults, so
overlays such as supabase.labels.yml would not have been loaded at all.
A stack is a directory of compose files; the current directory is a stack when
it holds one. The same command works for a project, a catalogue stack, a group
and a host singleton, and stacks sharing a project are now a single compose
call.
Two traps of the make engine are closed on the way: an unknown command is an
error instead of a silent success, and a group is only expanded when its name
is lowercase, so an environment variable can no longer be mistaken for one.
That guard spells out its character class because a-z matches uppercase too
under a dictionary collation.
config: dotenv files are parsed, never sourced, so a value can hold a # or a
$(...) without breaking or executing. The make engine included .env with
make syntax, which neither allowed.
compose: one call per project instead of one per sub-stack.
Replaces the 500-character stack_path expression of
make/apps/def.docker.mk:159 and its leaked $(stackz) loop variable with
three readable functions, covered by 20 assertions.
Ported from make/utils.mk, make/def.mk, make/apps/def.docker.mk and
make/apps/def.mk, with the examples that sat as dead comments in
make/apps/def.mk turned into actual assertions.
Two deviations from the make macros are pinned and documented in DELTAS.md;
both only show up on code paths nothing uses.
stack/ and docker/ now live in the myos-stacks project (extracted with their
history). What the framework itself needs stays here:
- stack/myos/*.yml -> share/compose/
- docker/myos/ -> share/docker/myos/
- docker/compose/ -> dropped, docker compose >= 2.24.4 is now required
Residues fixed along the way: DOCKER_IMAGES scanned a hardcoded ./docker,
include.mk filtered a hardcoded stack/*.mk, and docker-image-myos expanded an
undefined MYOS_DOCKER_IMAGES on every up/build.
README and CHANGELOG rewritten: they still documented make host,
host-certbot-* and user-config, all removed when the catalogue was split out.
- spec/golden/cases.txt: 69 black-box cases (CLI wrapper mode and make
include mode) run in a hermetic sandbox with a mocked docker
- spec/golden/expected/*.txt recorded from this engine (baseline)
- make test / test-golden / golden-record / lint dev targets
181a3e9 wrapped both $(or) alternatives in a single $(realpath …), which
turned the argument separator into a literal comma glued to the last path.
host/<svc> stacks were only resolved when the project stack dir happened to
sort before the other STACK_DIR entries.