Isolated local Stack
The local environment is runnable on macOS with an already-running OrbStack
Kubernetes cluster. It starts one disposable namespace containing dedicated
runtime and Temporal PostgreSQL storage, Temporal primary/visibility database
declarations, MinIO-compatible blob storage, telemetry, and all eight
trust-scoped runtime roles: API, orchestration, model, tool, blob, codec,
sandbox control, and sandbox host. Each role uses the actual cmd/runtime
binary and its one checked operator configuration. Tilt groups their logs and
rebuilds stack-scoped copies of the production composition image. This proves
binary build, configuration validation, secret-reference injection, readiness,
and lifecycle—not the complete public Agent Runtime API, Temporal payload codec
behavior, or any example app.
For the explicitly local profile only, the model and tool roles can run the
checked-in local-demo-v1 fixture. It has separately named local-only
credentials, emits a deterministic research Tool call, and still requires a
policy created through the public admin API plus an owner Approval before the
tool role can produce its bounded citation artifact. It is topology evidence,
not a model-provider integration, Codex subscription path, or production
provider claim. CI and production profiles do not mount or configure this
fixture.
Declared local evidence fixtures
Section titled “Declared local evidence fixtures”The local profile explicitly declares the normal ten-minute reset/replay scenario. A second short-expiry scenario exists only for retained local evidence. Both are recorded in private Stack lifecycle state and rejected by CI and production rendering. They do not accept a prompt, Stack-name convention, ambient environment value, or ConfigMap mutation as a selector.
go run ./tools/dev up --stack=workspace-reset-proof --root=. --kubeconfig=/absolute/path/to/kubeconfig --actor=local-operator --fixture-scenario=workspace-approval-reset-v1go run ./tools/dev up --stack=workspace-expiry-proof --root=. --kubeconfig=/absolute/path/to/kubeconfig --actor=local-operator --fixture-scenario=workspace-approval-expiry-v1workspace-approval-reset-v1 keeps the normal ten-minute lifetime for a
reset/reconnect replay proof. workspace-approval-expiry-v1 uses only the
declared short local fixture lifetime for a pending-Approval late-decision
proof. Both still emit the same bounded artifact-only fixture response and
never execute a workspace service, a Sandbox, or Firecracker.
Main CI invokes the same two-Stack isolation harness against a checksum-pinned,
disposable k3d/K3s cluster using the typed ci profile. Its twelve-minute
readiness bound includes a clean node’s immutable dependency-image pulls and
Temporal startup. The lane must bring both full stacks
Ready concurrently, observe three allowed declared-egress connections and
three blocked default-deny connections, prove the second stack is unchanged
after the first teardown, retain bounded evidence/diagnostics, and delete the
cluster. It is Kubernetes-in-container lifecycle and NetworkPolicy evidence,
not Linux/KVM or Firecracker evidence.
Each CI attempt owns a generated k3d cluster and registry name derived from the run and attempt IDs. It uses a private kubeconfig and deterministically derived loopback API and registry-port candidates, then availability-checks them before creation. A TOCTOU collision during the subsequent k3d bind fails safely rather than using an OS-selected port or adopting a pre-existing resource. After successful registry creation, it passes the discovered registry addresses to Tilt. The workflow will not reuse or delete a pre-existing resource; cleanup requires the successful-create record and matching immutable Docker container IDs.
just dev-preflightjust devThe omitted Stack name deterministically derives from the current worktree. To run two worktrees or two explicit stacks at once, use different names:
just dev stack=research-ajust dev stack=research-bThe public Tilt identity is the same in both forms—there is no instance
identity:
tilt up -- --stack=research-aThe just wrapper additionally selects orbstack, the explicit
ar-<stack> namespace, and an OS-selected dashboard port. It writes private
per-worktree state beneath ignored .runtime/dev/; it never changes your
Kubernetes current context.
To rerun the containment proof locally against OrbStack and retain evidence:
just two-stack-smoke local orbstack /absolute/path/to/two-stack-evidence.jsonInspect the Stack
Section titled “Inspect the Stack”just dev-status stack=research-aThe checked-in Stack deliberately contains no runtime-api Service or
port-forward command while its pinned image lacks the durable API executable.
The source API remains runnable against disposable dependencies, but that is
separate from this local Stack and does not imply a deployed public endpoint.
Tilt exposes links for declared runtime-role readiness endpoints and these docs.
Credentials and persistence
Section titled “Credentials and persistence”The checked-in Stack contains only Secret references and their key names. The
local materializer enumerates those references from the reviewed local profile,
generates random development-only values once per Stack, and stores them in a
mode-0600, ignored local file. Each role receives only its declared
credential keys. Startup enumerates the known credential-key inventory and
refuses a role with any present key that it is not entitled to use. Values never
appear in the typed Stack document, logs, health response, or repository.
dev-down removes the namespace and those Kubernetes Secrets; remove the
ignored local state if you want entirely fresh development credentials next
time.
Every runtime role has its own explicit ServiceAccount with token automounting
disabled and a default-deny, role-scoped egress NetworkPolicy. The local role
images do not call the Kubernetes API. Policies for workloads that resolve a
declared Service opt into a narrow DNS rule: UDP and TCP port 53 only to
CoreDNS pods in kube-system. It grants no general namespace or Internet
egress.
Runtime PostgreSQL, Temporal PostgreSQL, and blob storage each use finite per-Stack persistent claims. Temporal task-queue routing, the Temporal namespace declaration, primary/visibility database declarations, blob prefix, resource labels, Secret names, and image names derive from the same Stack identity.
Reset and teardown
Section titled “Reset and teardown”just dev-reset stack=research-ajust dev-down stack=research-adev-reset restarts only the eight declared runtime-role Deployments.
Before reset or teardown, the launcher re-reads the target Namespace and
requires its UID plus Agent Runtime, Stack, and local-profile labels to match.
It refuses a missing, relabelled, or foreign namespace. It never targets
default, another Stack, or a cluster-scoped object.
This is local container/Kubernetes infrastructure, not Firecracker evidence or hostile-tenant sandbox isolation. A compile-tested public Go contract and deterministic in-memory Agent kernel now exist, but their HTTP, PostgreSQL, and Temporal production adapters—and all three examples—remain separate implementation work.