Skip to main content

Desktop app

The ERun desktop app is how most people use ERun day-to-day. It runs on macOS and Windows and gives you a single control panel for everything: your projects, your environments, the Agents attached to them, and the cloud machines that back them.

For CI/CD pipelines and headless workflows, use the CLI instead.

Control panel

  • Sidebar of projects and environments. Every project and environment at a glance, with live status — running, stopping, idle, errored. Switch between them without typing commands. An open environment carries a status indicator that reflects its real condition, not just that its tabs exist: a green dot while it runs, a hollow ring when its cloud machine is stopped (start it from the titlebar), and a warning triangle when its deploy failed or reconnecting gave up (recover from the Activities panel). The triangle also covers an environment that has stopped answering: the desktop re-establishes a dead connection on its own — whether the connection is wedged or gone outright, which is what an ordinary pod replacement leaves behind — and when repeated attempts do not help it flags the row as unreachable, rather than letting it read as quiet or as an environment nobody opened. See Agent can't reach MCP. Clicking the indicator closes the environment's tabs.
  • Environment details on hover. Hover an environment row to see its runtime version, the issue it's working on (the current git branch and, when the branch names an issue, its title), and what it's doing right now — the operation in flight, Stopped, Deploy failed, Not open, or Idle. Branch and issue come from your machine's worktree for local environments and from inside the pod for remote environments while they're open; an environment that isn't open says so instead of guessing.
  • One-click lifecycle. Start, stop, restart, and delete environments from the sidebar.
  • Cloud status in real time. Start, stop, and watch the cloud machines that back remote environments. The sidebar shows status as they wake up or shut down.
  • Deploy a version from the Runtime tab. An environment's settings → Runtime carries a Version to deploy picker. Choose a published version and Deploy installs exactly that version by reference — it never rebuilds — so the button stays disabled until you pick one. The same picker lists the component charts to roll out (and you can save them as this environment's default), but only once you've picked a version — the panel is sequential: pick a version, then choose which charts deploy. The charts offered are the ones published at that version — the same for every environment, because the version decides which charts exist. When the environment builds from your local source, a separate Create & deploy new version action builds a fresh version, publishes it, and deploys it in one step. See command primitives.
  • State which chart the runtime rides. Under the version picker, Runtime chart names the second half of what a deploy installs. A version normally names both artifacts — the chart and the runtime image — because erun push publishes them together. When a project versions its runtime image on its own release line, it does not: the chart is ERun’s and exists only at ERun’s versions. The field offers the ERun chart versions available to this environment (every offered entry is a chart that exists), writes the full reference it picked, and remembers it, so later deploys — including from this tab — install that chart while the version keeps naming the image. Left as Published with the deployed version, nothing changes. See erun deploy.
  • A version with no chart says so before you deploy it. Picking a version resolves which chart it would install and reports it: a version on your project’s own release line has no chart at all, so the panel names that where you are choosing, Deploy is disabled rather than starting a rollout that cannot succeed, and a one-click Use ERun ‹version› sets the chart that fixes it. When the environment already states a chart, the same line reads back what will be installed (Runtime chart erun-devops 1.0.178, set on this environment). A registry ERun cannot list (private or unreachable) is never reported as “no chart” — it says nothing and leaves the deploy to you.
  • See what an environment is running, and take resources back. Under the Runtime tab's resource sliders, Running in this environment reports what the pod is doing right now: how many sessions actually have a live program behind them, and the processes holding memory — Gradle daemons a finished build left resident, the container build cache — grouped by what they are. It is a reading, not a cleanup: nothing is stopped until you click the action beside a group, and your worktree, sessions, and Agent are never touched. The resource figures above it are a live snapshot of the node, and when the maximum is capped by the node being full rather than by a limit on the environment, the tab says so and points at stopping an environment nobody is using. See Runtime pods.
  • Upgrade all. The Upgrade all button in the Environments header redeploys every environment opted into the upgrade set to the latest version for its channel (stable or snapshot; a snapshot-channel environment adopts a stable release once one is published on top of the latest snapshot). It opens a preview dialog listing each member and its current → target version, and only upgrades the ones that lag — opt an environment in and pick its channel from the environment's Runtime settings. Confirming runs each member's upgrade in its own environment, in parallel: progress and any failure show up on that environment's Local tab, sidebar row, and Activities entry, not in someone else's terminal. A member whose latest version can't be determined (for example the registry refused the lookup) shows latest unknown with the reason and is left untouched rather than guessed at. When an environment's listed registries offer more than one newer version, the row shows a picker — choose the version (each labelled with the registry it came from) and that member joins the upgrade. See erun upgrade.
  • Reviews tab. The tenant dashboard's Reviews tab lists every review for the signed-in tenant — status, source and target branch — with a color badge that always carries a text label alongside it. Open a row for that review's own detail: its recorded builds, its position in its target branch's merge queue, and its comment threads. Reply to an existing thread from there; the reply is attributed to you and, if the submit fails, your draft text stays put so you don't lose it. Starting a review, and commenting on a specific diff line for the first time, are CLI-only for now — see erun review. A queue of recent and in-flight operations — deploys, opens, builds. When a deploy fails, the entry keeps the captured command output (the real helm/kubectl error behind the one-line summary): expand Show output to read it, or use Copy failure report to package that output together with the environment, version, and container status so you can hand the whole picture to whoever can help. The failed entry also offers one-click recovery: Run doctor to troubleshoot (see erun doctor), Rebuild & redeploy to force a clean rebuild, and Clear pending helm release when a release is stuck.
  • Closing the window while work is running asks first. If a build, deploy, or release is still in progress when you close ERun, a confirmation names every job that would be cut off before you commit — closing anyway stops them immediately rather than pausing them, so treat a release interrupted mid-flight as one to check (its image or chart may have published without its git tag). Closing with nothing running is unchanged. If you close anyway, the next launch reports what was interrupted so you're not left guessing.
  • Investigate, within limits. The same failed entry offers Investigate, which hands the failure report to an Agent that reads it and either fixes the problem or improves the reporting behind it. That Agent runs on the account every Agent of yours runs on, so investigations are bounded rather than unlimited, and each refusal says which limit applied and when it lifts: a report with nothing to work from — no command, no exit status, no captured output — is refused, and the missing evidence is named as the thing to fix; further reports from a failure already being investigated join that investigation instead of starting another; the same failure is not investigated again for two hours; at most two run at once; and one that has not concluded within thirty minutes is stopped, which you are told about. While it runs, an investigation holds the environment's activity lease and appears as one of its jobs, so the environment reads as busy and you can see what is spending the account.
  • Settings in one place. Runtime sizing, AI tooling configuration, port mappings, SSH keys, and cloud bindings — all editable from one screen per environment.

Orchestrators

Above your environments, the sidebar's ERUN section lists your host-side orchestrators — AI sessions that coordinate work across the environments you link to them, reviewing each one's code on your machine and delegating every change to the Agent inside it. Open an orchestrator's menu to manage it: restart, delete, or reveal the guidance it operates under.

Each orchestrator runs under two layers of guidance, and the dialog opens either one in your editor (VS Code or IntelliJ):

  • Role — what this orchestrator does. Yours to edit; ERun creates it once and never overwrites it.
  • Shared contract — the rules every orchestrator follows. ERun-managed and rewritten on every launch, so edits here don't stick.

For the exact files behind these two layers and how they're injected into a session, see Agent reference · Skills spec.

Diagnostics console

The panel at the bottom of the terminal area follows whatever you're looking at, so it always has real evidence rather than a blank pane:

  • An environment selected. The env's persistent trace log: every erun command that ran for it, at full trace detail, timestamped — including commands that finished before you opened the console. Capture is always on; the log is capped and rotated automatically (see where it lives). For a remote environment the timeline merges two vantage points: the commands you ran from this machine and, while the environment is open, the Agent-driven ones from inside the pod — the in-pod lines are marked [pod].
  • An orchestrator session focused. Its name, status, background shell (if any), and the environments it links — plus the desktop's own log, since an orchestrator fault is desktop-side, not env-side.
  • Neither. The desktop's own log on its own, for a fault that belongs to the app itself.

UI trace — the desktop's own action history, what the app just did, in order — sits in a second tab next to whichever of the above is active, for reporting a desktop bug rather than an environment or orchestrator one.

Both panes have a Copy button for their own stream, and the console's Copy report button packages everything at once — app build, the active context's identity and state, and the UI trace — into a single paste-ready block, so a bug report carries the evidence instead of a description of it. Report an erun issue goes one step further: it opens a prefilled github.com/sophium/erun issue in your browser (title and reproduction/environment sections filled in from the same evidence) for you to review, fill in what happened, and submit yourself — it never files anything on your behalf. The full report stays on your clipboard too, so nothing is lost even if the prefilled body is trimmed to fit the link.

On a busy environment the erun trace can be a wall of scrollback. Clear baselines the view — it hides the lines shown so far so whatever happens next stands out — without deleting anything: the persistent log stays intact, Show all brings the earlier lines back, and Copy and Copy report always include the full log. The baseline is per-environment, so switching environments starts fresh.

Open it in your editor

  • Persistent terminal sessions. Each environment owns its own terminals, and switching tabs doesn't kill them. For an environment backed by a runtime pod, the sessions live in the pod and keep running even while the environment is closed — a long-running Agent keeps working while you're away — so reopening reconnects you to the same sessions and scrollback instead of starting fresh ones.
  • Copying out of a terminal. Select text in a terminal tab and copy it with your platform's chord — Cmd+C on macOS, Ctrl+C or Ctrl+Shift+C on Windows — and it lands on your machine's clipboard, not the pod's. Ctrl+C stays the interrupt: with nothing selected it always reaches the program in the terminal, and on macOS it does so even when something is selected. Right-clicking copies the selection too, or pastes when there is none. A program running inside the environment can also hand you text directly — an Agent that prints a sign-in URL with a "press c to copy" hint puts it on your clipboard, so you can paste it into the browser on your machine. That direction is one-way by design: nothing inside the environment can read your clipboard back.
  • VS Code or IntelliJ in one click. The IDE attaches to the environment's filesystem — editor, extensions, language servers, debugger, everything sees the same files the Agent sees.
  • Any other editor that supports SSH. Cursor, Zed, JetBrains Gateway, Neovim with remote plugins, anything else — the desktop publishes the local SSH details, point your editor at them.

Works with or without an Agent

The desktop is equally useful as a clean development surface for human-driven work — open as many isolated environments as your machine can host, develop in any one, and let ERun handle the infrastructure underneath.

Side by side with an Agent

By default, the Agent runs inside the env — the runtime pod ships the configured Agent's CLI (claude, codex, …) pre-wired against the in-pod MCP loopback. The desktop's AI panel surfaces it; any terminal inside the pod can launch it directly. If the Agent ends — you exit it, it crashes, or the container's memory limit kills it — the AI tab says so instead of silently turning into a shell: it names the exit (a memory kill includes the hint to raise Memory in the env's Runtime settings) and prints the exact command to resume the conversation.

Opening the AI tab checks whether the environment is already held by another job — one started by an orchestrator, another desktop, or the CLI. If it is, the desktop names the job and asks before starting a second Agent alongside it, since the two would compete for the same pod's CPU, memory and disk. Starting anyway is a deliberate choice, not a blocked one — there are good reasons to run two (a long build in one tab, a quick question in the other) — and a small persistent reminder stays on the AI tab for as long as the other job keeps running.

For a Claude env, the AI tab of the env settings dialog carries the Claude launch controls. Effort sets how hard Claude works per turn: the levels from low through max trade response time for thinking depth, and ultracode — the default for new envs — runs at xhigh thinking effort and additionally turns on standing multi-agent workflow orchestration, so Claude can fan work out across coordinated agents without being asked. Pick a plain level (for example max) when you want pure single-agent thinking instead. Default model picks the model the env's Claude session starts on, chosen from the environment's available models — tick fable under Available models to make it selectable. Left on Default it starts the first of the env's available models (opus by default), so a session never lands on an unavailable model; fable is never chosen automatically. Launch Claude in verbose + debug mode streams Claude's own diagnostics into the AI tab. The desktop applies your choices when it opens the env's Claude session, and saving a changed launch setting reopens the env's open AI tabs so it takes effect immediately — the Claude conversation resumes where it left off. For the exact levels and how the values resolve, see Agent reference · Configuration.

The AI tab's Claude session also has Remote Control on by default, so you can watch and steer it from the Claude iOS app (or claude.ai/code) while you're away from the desktop: sign into the app with the same Claude account and the running session appears in its Code tab named <tenant>/<env>. Pairing rides your claude.ai login — the same one the session prompts you for when it first starts — so it needs a Claude subscription plan, and it's turned off automatically for environments whose Claude runs through the Bedrock or Mantle gateways, which the pairing relay can't sign into.

When you do want a laptop-side Agent in addition, the env has two endpoints on the runtime pod — SSH and MCP — and both accept any client.

  • IDEs (VS Code, IntelliJ, Cursor, Zed, …) attach over SSH.
  • The Claude Code desktop app and Codex desktop app attach the same way — they open the env as a remote workspace, edit files, run commands. They also use MCP for structured ERun operations (idle, list, doctor, build, …).
  • Custom agents (any MCP client) typically stick to MCP for structured calls and reach for SSH only when they need shell access.

A commit you make in VS Code is immediately visible to the Agent's next file read. An action the Agent takes shows up in your terminal scrollback and in the audit trail. No parallel worlds.

Workspace sync (optional)

For a remote-agent env, the worktree lives in the pod. Workspace sync mirrors it down to a folder on your machine so you can review and act on it host-side — open it in a host IDE, read the synced files, and run binaries the Agent built in the pod — without reaching into the pod for every step. It's the piece that makes an agent-driven env comfortable on Windows, where the pod-side worktree isn't directly openable by a host editor.

Enable it from the desktop's env settings panel and pick the local folder to mirror into. The sync is one-way, pod → host: the desktop keeps the folder matching the pod's worktree (tracked and untracked-but-not-ignored files), so treat it as read-only — host edits are overwritten on the next pass. Files removed in the pod are removed from the mirror too. The mirror is a plain directory — it needs no local git; to see the Agent's uncommitted diff, view it from the pod (the desktop's review, or ask the in-pod Agent to run git diff).

Build artifacts land alongside it. Anything the Agent writes to the pod's outputs directory — a cross-compiled .exe, a report, a bundle — is mirrored into a read-only .erun-outputs folder next to the synced source. That's how a Windows binary built in the Linux pod reaches your machine: it syncs down, and you run or debug it from the desktop (the same artifacts are also available via Download on the env's Outputs dialog). On a Mac, an arriving macOS binary is signed and made runnable on the way in — macOS kills an unsigned one on launch without saying so — and the desktop posts a notification naming the signer it used, or why it could not sign. See erun outputs for the exact rule.

For the polling cadence, the cleanup semantics, and the size budget, see Agent reference · Workspace sync spec.

Contribute to ERun from any environment

The titlebar's Contribute toggle (the git-fork icon) lets you patch ERun itself without leaving the env you're working in. It is available for any non-erun agent env (local-agent or remote-agent); it is hidden for runtime envs and for the special erun tenant.

When you toggle Contribute on, the desktop:

  1. Clones the ERun source into ~/git/erun inside the env (the host for a local-agent env, the runtime pod for a remote-agent env). The clone is idempotent — a checkout that already points at the canonical ERun remote is reused as-is.
  2. Installs a small shim at ~/.erun/contribute/bin/erun that forwards every invocation to the clone's erun-cli/run.sh. Subsequent erun calls inside the contribute tabs — whether typed at the prompt or spawned as child processes by an Agent — go through that script, which rebuilds the binary from the current source on each run.
  3. Opens two extra tabs alongside the env's normal ERun + AI + Local tabs: ERun (contribute) is a shell pointing at the clone; AI (contribute) is the Agent attached to the clone. Both tabs are marked with the git-fork icon in the tab strip so you never confuse a contribute terminal with the env's own.
  4. Adds an Env / ERun segmented control in the review panel's changed-files sidebar. Flipping it switches what the diff view shows: the env's worktree or the ERun clone's worktree, side by side as you iterate.

To try your changes to the desktop app itself, click the Open contribute app button (external-link icon) that appears next to the Contribute toggle while contribute mode is on. The desktop boots erun app --headless inside the contribute terminal — building the binary on the fly from your clone — brings up a port-forward from the env's contribute-app port out to your host, and opens the locally-built desktop app in a new browser tab. Subsequent code edits are picked up on the next rebuild (Ctrl-C the running process in the ERun (contribute) tab and click the launcher again).

Toggle the switch off when you're done. The contribute tabs close, the headless app and its port-forward shut down, the diff view reverts to the env, and the clone stays on disk so re-enabling later is instant.

Install

Install ERun via Homebrew or Scoop. One command installs both the CLI and the desktop app.