This should have shipped with the extraction PR and did not: the file was
written after that commit was already pushed, so it landed nowhere. The
infra PR meanwhile removed the same content from that repo's README, so
between the two merges these notes existed only in git history.
They are the expensive part of the executor — apply's guarantees (never
deletes, never recreates a database, fails loudly on un-updatable drift),
the dockercompose build pack, hostname-overlay shapes, and each place
Coolify 4.1.2 misbehaves, with citations verified against coollabsio/coolify
v4.1.2 and the vendored OpenAPI rather than its published docs.
Linked from the README so it is found before someone changes apply.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Public tool, private state. cast holds no hostnames, no bindings, no
secrets: it joins a product repo's .infra/ manifest with a state directory
you point it at, and makes Coolify match.
Extracted from heavy-duty/infra, which was half tool and half state — the
inconsistency that made it impossible to say whether "infra" named a CLI
or a runbook. rig builds the boxes; cast fills them; infra is what they
are filled with.
Two changes were required to make it genuinely stateless and publishable:
- The implicit cwd contract (environments.yaml / secrets/ / .coolify.env
resolved against the working directory, silently reading the wrong file
from the wrong place) is now an explicit --state <dir> / $CAST_STATE.
- BANNED_IN_PROD — a hardcoded list of one product's ALLOW_* flags, the
only product knowledge in the executor — becomes the generic, operator-
owned environments.<env>.forbidden_var_patterns. The guard now lives in
private state, so a product-side change cannot lower its own guard, and
it is a pattern rather than a list, so it catches unforeseen siblings.
Age identities resolve as $CAST_AGE_KEY_FILE_<ENV> then
~/.config/cast/age-<env>.key — which is the entire attended-vs-unattended
apply mechanism, with no environment names known to the tool.
Instance identity (org names, the GitHub App name, founder domains) is out
of the fixtures and out of register-github-app.sh, which took APP_NAME and
ORG as arguments rather than baking them in.
69 tests green; bin/cast + curl installer mirror rig's shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>