From 0dee1f1e2e0364381f216b9840e6e52eb8105460 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Wed, 19 Aug 2026 20:49:35 -0600 Subject: [PATCH] Correct the skill's env precedence, and its ports/hostname advice The deploy-with-stack skill states env precedence backwards: it says config.env overrides the inline environment: block, when later sources win and inline beats config.env, as docs/stack-files.md describes and test_pod_file_env_overrides_deployment_config asserts. It then recommends the pattern that mistake implies -- put defaults inline, override with --config at init -- which is exactly the shadowing the warning added in e4cb078 exists to report. Following it silently discards the deployer's value. In the case that prompted this, a composefile default of PUBLIC_BASE_URL=http://localhost survived --config PUBLIC_BASE_URL=https://, and the application used it to decide whether to mark its session cookie Secure, so a public HTTPS deployment issued session cookies without it. Replace the bullet with the real ordering, the forwarding form (- SOME_VAR=${SOME_VAR}) as the way to let a deployment-time value through, and a note that stack deploy now reports shadowing. Also extend the hostnames bullet with the consequence of 56fd7df: a service needs no ports: to be addressable, so publishing one merely to obtain a hostname is unnecessary, and on compose exposes it on the host under --map-ports-to-host. docs/stack-files.md was updated alongside those fixes; the skill was not, and is the copy an agent reads first. Co-Authored-By: Claude Opus 5 (1M context) --- skills/deploy-with-stack/SKILL.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/skills/deploy-with-stack/SKILL.md b/skills/deploy-with-stack/SKILL.md index d623e8d..4a23312 100644 --- a/skills/deploy-with-stack/SKILL.md +++ b/skills/deploy-with-stack/SKILL.md @@ -145,12 +145,18 @@ volumes: - **Hostnames:** every service reaches every other by its service name (`db`, `backend`), even across pods, on both compose and k8s. Use service names in connection URLs. + Declaring `ports:` is not what makes a service addressable — a service with no `ports:` + still answers to its own name (on k8s, via a headless Service). Don't publish a port + merely to obtain a hostname; on compose `--map-ports-to-host` would then expose it. - **Ports:** list the container port bare (`- 8080`); host mapping is decided later at `init` time. Don't hardcode host ports here. -- **Env precedence:** deployment-time `config.env` overrides `env_file:` entries, which - override the inline `environment:` block. Put sane defaults inline for non-secret - settings; anything the deployer should choose (external URLs, feature flags) is - supplied via `--config` at init. +- **Env precedence:** later sources win — the deployment's `config.env`, then `env_file:` + entries, then the inline `environment:` block. So an inline literal beats a value the + deployer supplied with `--config`, identically on both targets. Anything the deployer + should choose (external URLs, feature flags) must therefore be *forwarded* rather than + defaulted: write `- SOME_VAR=${SOME_VAR}`, not `- SOME_VAR=some-default`. `stack deploy` + warns when an inline literal shadows a differing key in `config.env`, naming the + service, the key and both values. - **Secrets are not composefile environment entries.** The `secrets:` block in stack.yml delivers each declared secret to every container, so the database and its clients share `POSTGRES_PASSWORD` automatically — have the app read it from the environment