refactor(env): explicit defaults.env with placeholders; drop auto-injection
A service/job's env is now exactly its defaults.env — castle injects no hidden
convention vars. Values support ${port}/${data_dir}/${name} placeholders
(resolved at deploy, alongside ${secret:…}), so a program's own env var names
map to castle's computed values without hardcoding.
Why: the auto-injected <PREFIX>_PORT/<PREFIX>_DATA_DIR were a guess at the
program's env names — right for castle-scaffolded services, dead weight for
adopted ones (lakehouse carried two dead vars; notification-bridge/backup jobs
too). They also weren't visible in the config editor (computed at deploy), which
was the source of the 'four env vars but the UI shows none' mystery.
- core: resolve_env_vars gains a context (${port}/${data_dir}/${name});
deploy builds env from defaults.env only — no <PREFIX>_* injection, no
port_env. Removed the port_env field and the dead _env_prefix helper.
- cli: 'service/job create' gains repeatable --env KEY=VALUE (replaces
--port-env); 'program create' scaffolds <PREFIX>_PORT/_DATA_DIR: ${…} for new
daemons.
- app: removed the 'Port env' field; the Environment editor (defaults.env) is
the single place, with a placeholder hint.
- live migration: central-context/castle-api/power-graph/protonmail mapped their
real vars explicitly; lakehouse → just LAKEHOUSED_DAEMON_PORT: ${port}, data
stays in ~/.lakehoused. Verified all services healthy on their ports, dead
vars gone, zero failed units.
- docs: registry.md/design.md/stack guides + findings updated to the explicit
model.
core 94 / cli 24 / api 52 green; ruff + app build clean.
This commit is contained in:
@@ -195,9 +195,9 @@ Services and jobs can reference a program via `program:` for description
|
||||
fallthrough and source code linking. They can also exist independently
|
||||
(e.g., `castle-gateway` runs Caddy — not our software).
|
||||
|
||||
Convention-based env vars (`<PREFIX>_PORT`, `<PREFIX>_DATA_DIR`) are
|
||||
generated automatically during deploy. Only non-convention values need
|
||||
`defaults.env`.
|
||||
A service's env is exactly its `defaults.env` — castle injects nothing
|
||||
implicitly. Values may use `${port}`/`${data_dir}`/`${name}`/`${secret:…}`
|
||||
placeholders, which deploy resolves into the registry's flat `env`.
|
||||
|
||||
**`$CASTLE_HOME/artifacts/specs/registry.yaml`** (per-node, not in the repo, generated by `castle deploy`) — Node config:
|
||||
|
||||
@@ -222,8 +222,8 @@ deployed:
|
||||
```
|
||||
|
||||
The node config says what's deployed *here* and with what concrete
|
||||
values. `castle deploy` reads the spec from the repo, generates
|
||||
convention-based env vars, resolves secrets, resolves binary paths,
|
||||
values. `castle deploy` reads the spec from the repo, resolves the
|
||||
`defaults.env` placeholders and secrets, resolves binary paths,
|
||||
and writes the registry. Systemd units and Caddyfile are then generated
|
||||
from the registry — never from the spec directly.
|
||||
|
||||
@@ -521,9 +521,9 @@ What exists today:
|
||||
`$CASTLE_HOME/artifacts/specs/registry.yaml` (node config). Systemd units and
|
||||
Caddyfile generated from registry with fully resolved paths. No repo references
|
||||
in runtime artifacts.
|
||||
- **Convention-based env generation** — `castle deploy` auto-generates
|
||||
`<PREFIX>_DATA_DIR=$CASTLE_DATA_DIR/<name>` and `<PREFIX>_PORT` from
|
||||
the manifest. Only non-convention values need `defaults.env`.
|
||||
- **Explicit env with placeholders** — a deployment's env is exactly its
|
||||
`defaults.env`; `castle deploy` resolves `${port}`/`${data_dir}`/`${name}`/
|
||||
`${secret:…}` into concrete values. No hidden convention injection.
|
||||
- **Gateway** — Caddy on port 9000, Caddyfile generated from registry
|
||||
- **API** — `castle-api` on port 9020, reads from registry (optional
|
||||
castle.yaml fallback for non-deployed programs)
|
||||
|
||||
Reference in New Issue
Block a user