mando-cli build variants per profile (SHELVED 2026-05-06)
SHELVED — NOT IMPLEMENTED
This is a captured design proposal from 2026-05-06. No code shipped for it. The note exists so we don’t lose the analysis or re-derive it from scratch when somebody picks this up. Do not assume any field, command, or behaviour described here exists in the codebase.
Problem statement
The mando Dockerfile is runtime-only: its only COPY is the prebuilt binary, e.g. COPY target/release/mando_bess /usr/local/bin/mando_bess. So mando build mando does NOT actually build mando — it only docker-packages a binary that the user must have built on the host first via cargo build --release. Out of the box, on a fresh checkout, this fails because target/release/mando_bess doesn’t exist yet.
The same code path also has the alternate container.linux.chef.build.Dockerfile (multi-stage cargo-chef build, builds inside Docker, no host pre-step needed). That one would work on a fresh checkout, but is much slower for the inner-loop dev case where the host already has an incremental target/.
Today the choice between them is not first-class. There is no profile field that says “use the runtime-only dockerfile and run cargo first” vs “use the multi-stage one and don’t”.
Proposed shape (NOT IMPLEMENTED)
Make the dev/release dockerfile choice a profile concern, with the existing profile infrastructure (src/runtime/profile.rs::ServiceIntent).
YAML side — service config
build:
image: mando
tag: dev
default_variant: dev
variants:
dev:
dockerfile: Dockerfile
pre_command: "cargo build --release -p mando_bess"
context_includes:
- mando-bess/certs
- lib/libduckdb/libduckdb.so
- target/release/mando_bess
release:
dockerfile: container.linux.chef.build.Dockerfile
context_includes:
- Cargo.toml
- Cargo.lock
- mando-bess
- mando-core
- mando-lib
- mando-lib-macro
- py-mando
- mando-scrtpre_command runs in context_dir (so cargo runs from the workspace root, finding the workspace Cargo.toml). On non-zero exit, the build fails with captured stderr — same error model as the docker build itself.
Profile side — per-service intent
ServiceIntent would gain a variant: Option<String> slot. The profile syntax extends from the current 2-field build:run to a 3-field variant:build:run:
mando=dev:build:watch # variant=dev, build_mode=build, run_mode=watch
mando=release:build:real # variant=release, build_mode=build, run_mode=realResolution: if the variant slot is omitted, fall back to default_variant from the service yaml. default_variant: dev keeps the inner-loop case ergonomic.
Why this builds on the 2026-05-06 work
The context_includes field that landed in commit 6b1f7c7 (see mando-cli-build-context-filter-2026-05-06) is a per-build-def list. Variants extend that to one list per variant per service. Same field, scoped lower. No new tar machinery — build_filtered_tar is already variant-agnostic.
Open questions for whoever picks this up
These need answers before implementation starts
pre_command: single string or list of steps? Single string is simpler but forces users into shell composition (&&) for multi-step setups. A list is more verbose but each step gets its own success/fail row in the UI.- Profile syntax: hard break to 3-field, or fallback parser? A fallback parser that accepts old 2-field
build:run(with the variant defaulting todefault_variant) is friendlier to existing users. A hard break is cleaner for the codebase and forces explicit choice, but requires a migration of every existing profile string.- CLI variant override:
--variant=releaseflag, or always go through profiles? A flag is convenient for one-off “build the release artefact” commands but it duplicates the profile mechanism. Always-via-profile is purer but meansmando build mandofrom a dev profile never gives you the release artefact without changing profile.- Failure semantics for
pre_command: if cargo fails, do we surface the cargo stderr verbatim (potentially huge) or a summary? Same question for partial failures in a list-of-stepspre_command.- Caching: should
pre_commandbe skipped if its outputs (the artefacts named incontext_includes) are already up-to-date relative to source? Cargo handles its own caching, but a no-op cargo invocation still costs ~200ms of startup. Probably not worth a dedicated cache layer.
What is intentionally NOT in the proposal
- No multi-arch matrix — variants are about dev/release split, not platform multiplexing.
- No per-variant image tag override — current
build.tagstays at the build-def level. If a future need arises we can addtaginside the variant block, but the simple case is “all variants of the same service produce the same image, just built differently”. - No global
--variantflag yet — see open question above.
Status
Deferred. Don't pretend it shipped.
- The 5 fixes that DID ship on 2026-05-06 are documented in their own notes (see Related).
- This design is captured for the next person who hits the “build mando from a fresh checkout doesn’t work” friction.
- Until this lands, the workaround is to remember to run
cargo build --release -p mando_bessbeforemando build mando, OR to manually swap the Dockerfile to the chef variant.
Related
- mando-cli-build-context-filter-2026-05-06 — the
context_includesinfrastructure this design extends - mando-cli-v2 — current architecture (where
ServiceIntentlives) - mando-cli-mock-down-idempotent-2026-05-06 — sibling fix from the same session
- mando-cli-status-readonly-2026-05-06 — sibling fix from the same session
- Mando