ADR-024: Tilt as the canonical local-development orchestrator
Context
New engineers and coding agents cannot reliably boot the Aucert stack. The golden path lives
in tribal knowledge and throwaway /tmp scripts; the committed Tiltfile is an abandoned
Day-1 stub pointing at paths that no longer exist; the committed dev docker-compose has the
wrong Postgres image and a mis-set worker flag; there is no local auth (Kong is absent, so
everyone hand-rolls a proxy); and nothing in CI executes the environment, so it drifts
freely until it costs a teammate a day.
Forcing functions and constraints:
- ADR-002 mandates a native inner loop during MVP — so the daily loop must not require a local Kubernetes cluster.
- ADR-013 established that "things that must stay true" are enforced by CI/hooks, not discipline. The dev environment must be enforced the same way.
- Developers are on macOS (Apple Silicon); CI is Linux. The Android emulator cannot run in
Docker on macOS (
/dev/kvm), so any full-fidelity or device path is platform-specific.
Decision
Adopt Tilt as the single sanctioned way to run services locally, in native mode:
infrastructure (Postgres, Redis, Temporal, dev gateway) in docker compose; application code
(backend, console, opt-in rover-worker) as Tilt local_resources — no local
Kubernetes in the daily loop. tilt up is the one command for humans; tilt ci is the
headless, self-verifying entry for CI and agents.
The environment becomes self-testing: a tilt ci job (on dev-file-touch + nightly) boots
the stack, waits for readiness, and runs a smoke test — so drift surfaces as a red build, not
a lost afternoon. This same rule binds agents: they start services via tilt up/tilt ci,
never bazel run/pnpm dev directly (encoded in AGENTS.md → CLAUDE.md).
Kubernetes-based prod fidelity (kind + Helm + Kong) is on-demand only, materialized from
CI-validated charts (helm lint + kubeconform); it is never a standing, maintained
environment. The shared Azure dev cluster is the normal fidelity target, reachable by flipping
one env target.
The full design, corner cases, and acceptance criteria live in SPEC-052.
Alternatives considered
| Option | Pros | Cons |
|---|---|---|
| Tilt (native mode) — chosen | one command + dashboard; native inner-loop speed (ADR-002); tilt ci makes it self-testing; one path for humans + agents | a new required tool (Tilt) + Docker; a Tiltfile/compose to maintain (now CI-enforced) |
| Make/scripts + compose + native | zero new dependency; most portable | dumb conductor — no dashboard/health/auto-reload; still needs its own CI executor; misses the "don't babysit / easy debugging" bar |
| Standing local k8s (kind + Helm + Kong) | highest prod fidelity | heaviest; slow inner loop (image builds); most rot-prone (few run it → it dies) |
Status quo (tribal + /tmp + hand-rolled proxy) | none | the very cause of the problem |
Consequences
What becomes easier
- Clone-and-go: one command to a working console; onboarding in minutes.
- Debugging: one dashboard with per-service logs, health, and restart.
- Agents (incl. cloud) bring the stack up the same self-verifying way, instead of ad-hoc spawning.
- A clean, on-demand upgrade path to real k8s/Kong fidelity when genuinely needed.
What becomes harder
- One more required install (Tilt) plus Docker.
- A
Tiltfile+ compose to keep correct — but CI (tilt ci) now forces that maintenance. - The dev gateway is a proxy, not real Kong — a deliberate local-fidelity gap.
Risks
tilt ciadds CI minutes (mitigated: gate on dev-file-touch + nightly, cache Bazel/pnpm).- The rover-worker/emulator stays platform-specific (macOS native AVD vs Linux KVM container) — irreducible; contained behind an opt-in profile.
- If the
tilt cigate is ever disabled, the environment reverts to rotting — the gate is the whole guarantee and must not be treated as optional.