Environment types
Every ERun environment is one of three types, determined by where its project worktree lives. Operator and Agent collaborate in agent envs (local-agent or remote-agent); runtime envs serve deployed services.
| Type | Worktree source | Used for |
|---|---|---|
| local-agent | Mounted from the local machine's filesystem (Kubernetes hostPath) | An operator or agent developing on their own machine. |
| remote-agent | Cloned into the pod, persisted on the env's PVC | An operator or agent developing on a remote cluster where the local machine plays no role. |
| runtime | None — no worktree at all | Running deployed services. No development happens here; the env receives released artifacts and serves them. |
The three types form a spectrum from "developer iterates here" (local-agent and remote-agent) to "production serves here" (runtime).
local-agent
The classic developer experience. The Kubernetes pod sees your local machine's working directory live; edits in your editor are immediately visible to the agent inside the pod. Builds happen here and produce snapshot-tagged artifacts.
Typical names: local, <operator>-develop, <operator>-hotfix.
Used when the cluster runs on your machine (Docker Desktop, kind, k3d) or shares a filesystem with your machine.
remote-agent
Same iteration model as local-agent — builds happen here, snapshot tags, agent develops in the pod — but the project is cloned from git into the pod's PVC instead of mounted from the local machine. You attach via SSH (any IDE) or MCP (Codex, Claude Code) just like a local-agent env.
Typical names: <operator>-develop against a cloud cluster, or any agent env on a cluster whose nodes don't share your local filesystem.
runtime
Where services run. No worktree, no development. Receives versioned artifacts via erun deploy and serves them.
Typical names: dev, test, dr, prod.
You don't develop in a runtime env. To make a change, you:
- Develop the change in a local-agent or remote-agent env.
- Build a new artifact (locked to a version).
- Deploy that artifact to the runtime env.
What concretely changes per type
The type describes the environment — where its worktree comes from and what it's for. It does not change what the build / push / deploy commands do: those are pure primitives with no environment-type branch. What differs per type is whether the env has source to build from at all, and who supplies the commands (an Operator at the terminal, or the desktop app orchestrating them).
| Behavior | local-agent | remote-agent | runtime |
|---|---|---|---|
| Worktree in pod | Mounted from host | Cloned to PVC | None |
| Source to build from | Yes | Yes | None — nothing for build to act on |
| Typical loop | iterate: build → push → deploy a snapshot | iterate: build → push → deploy a snapshot | consume: deploy --version a published version |
| Editor / IDE attach | Yes (SSH + MCP) | Yes (SSH + MCP) | Not the normal pattern |
| Per-env helm overlay | Defaults are fine | Defaults are fine | Yes — each runtime env wants its own |
A runtime env has no worktree by default, so there's no source for build to act on and no reason to build there — you deploy a version into it that was built and pushed elsewhere. (You can opt one into a mutable source worktree for live patching; see Hotfix pattern.) An agent env has source, so it's where the iterate loop runs. The desktop app reads the env's type to decide which primitives to run on the Operator's behalf, but the primitives themselves stay the same everywhere (see Command primitives).
The exact snapshot tag format and how erun build resolves it lives at Build path resolution.
Hotfix pattern
A runtime env has no editable source by default. You can opt one into a mutable source worktree — the desktop's env settings (Runtime tab → Mount source code, backed by EnvConfig.mountsource + repourl) clone the repository into the pod at the deployed release, checked out for live edits — when you genuinely need to patch the running release in place. The lower-risk pattern, and the default, is to spin up a local-agent env beside it, on the same cluster:
erun deploy rolls the result into the runtime env beside it.To hotfix erun-backend-api in erun-prod:
- Create
erun-prod-local— a local-agent env targeting the same Kubernetes context aserun-prod, with theerun-prodworktree mounted from your local machine. - Open it. Operator + Agent have a normal development surface — editor, terminal, build tools — attached to a pod inside the prod cluster.
- Make the change; build the new version.
- Deploy to
erun-prod:erun deploy erun-backend-api --tenant erun --environment prod --version 1.0.77 erun-prod-localstays as your active development surface against prod.
Baked release artifacts
Mount source (above) is for editable source. When a runtime env instead needs read-only artifacts present — a platform Terraform tree, seed data, fixtures the deployed services expect — a tenant's <tenant>-devops image can bake them into the image and have them appear in the pod's git folder.
The one rule: bake them into /opt/erun/release/, never under /home/erun. A runtime pod mounts a persistent PVC over /home/erun, which shadows anything baked beneath it — so a COPY into /home/erun/git/<repo>/… silently never appears. Artifacts baked into /opt/erun/release (outside that PVC) survive, and on boot a sourceless runtime env symlinks its git folder (~/git/<repo>) at /opt/erun/release. The result shows through as ~/git/<repo>/…, always matching the deployed image — no copy step, nothing to keep in sync. erun terraform and other repo-rooted commands then resolve the tree there. Unlike a mounted worktree, this content is read-only image state: to change it, rebuild and redeploy the image.
Mapping to configuration
Set EnvConfig.type to one of local-agent, remote-agent, or runtime. When type is set it is the source of truth for the env's shape — its worktree storage (worktreeStorage=host|pvc|none) and the ERUN_ENV_TYPE the helm chart wires in. The build / push / deploy commands do not branch on it; the caller (the desktop app, or an Operator) decides which primitives to run for a given env.
The retired EnvConfig.remote and EnvConfig.snapshot fields no longer exist. A config written before type existed is migrated on read — ERun derives type from the old remote/snapshot keys per the legacy migration table and discards them. New envs created by erun init --type set type directly.
# Local-agent env (default if neither flag is given):
erun init team local --type local-agent
# Remote-agent env (replaces the older --remote flag):
erun init team dev --type remote-agent --no-git
# Runtime env (worktree-less; serves deployed artifacts):
erun init team prod --type runtime --no-git
--remote is preserved as a deprecated alias for --type=remote-agent; passing both flags with conflicting values is an error.
The desktop app's New environment dialog exposes the same choice as an Environment type field. Picking Local agent also reveals a Local repo path input (with a native folder picker) — that's the host directory mounted into the agent pod as the worktree, equivalent to the CLI's --project-root.
The type is editable after creation from either surface. In the desktop, the Environment type field on an existing env's Manage → General tab is a selector. From the CLI, re-run init with the type you want (erun init team dev --type remote-agent) — it moves the env between any two types and does the work the new type implies, and omitting --type leaves the env's type alone (see erun init · Re-running on an existing environment). Changing the type alters build and deploy behaviour and reconfigures the worktree, so reach for it to fix a wrong type, not as a routine toggle.
Inside a runtime pod, the on-disk env config is a projection of the env's configuration, written from the helm-injected ERUN_* env vars. It carries the build/deploy-relevant fields the pod acts on — runtimeregistry, containerregistries, and disablebuildscript (a remote-agent pod builds in-pod and needs the build/push registry list; a runtime pod only deploys and needs the deploy/runtime registry). If a pod's config drifts from the deploy spec, erun doctor --sync-config reconciles it in place (injected env wins), preserving the keys the env does not carry.