The Durable Runtime

How cordy-runtime keeps terminals, TUIs, and agents alive — env overrides, per-workspace config, and runtime states.

Underneath Cordy's terminals and agents runs cordy-runtime, a durable, cross-platform process supervisor written in Rust. It is the reason your shells, TUIs, and CLI agents survive a window reload, a renderer crash, or — on Windows — closing to the tray.

Crucially, cordy-runtime is a terminal and process supervisor, not an LLM gateway. It makes no model calls, assembles no prompts, and manages no context windows — that is entirely the job of the external CLI agents it launches. This boundary is enforced at the source level: the runtime's crates deliberately depend on no HTTP or LLM libraries at all.

Why terminals and agents are durable

Your terminal sessions (the PTYs) and CLI agent child processes do not live inside the Electron window. They live inside the separate cordy-runtime process. The window only ever attaches to and detaches from a session over a local channel — it never owns the process itself.

That single design choice has a direct consequence:

  • Switching workspaces, unmounting a panel, or reloading the renderer only detaches.
  • Only when you explicitly close a terminal tab is the underlying process killed.

So a long-running build, a vim session, or a running agent keeps going even while the UI that was showing it goes away and comes back.

Attach as snapshot

Each session runs a headless terminal emulator inside the runtime, fed every byte of PTY output and resized in lockstep with the real terminal. When the UI re-attaches, the runtime returns one of two things:

  • a delta — just the frames buffered since the UI last saw the session (used when the same view is still alive and the gap is small); or
  • a snapshot — the full serialized screen state at the terminal's current size (used after a fresh reload, a tray restore, or when the buffered delta window has been evicted).

Reattaching from an emulator snapshot — rather than replaying raw scrollback — is what lets full-screen TUIs come back reconstructed instead of redrawing piecemeal, and it removes a whole class of duplicated-output bugs. (One residual limitation on alternate-screen TUIs is covered in Troubleshooting.)

Supervision and auto-restart

The Electron main process supervises the runtime and restarts it if it exits unexpectedly. Restarts use exponential backoff so a runtime that crashes on every launch cannot hammer your machine:

  • Backoff grows 1s → 2s → 4s → 8s → 16s, capped at 30s.
  • Once the runtime has stayed healthy (ready) for 60 seconds, the backoff resets to its base delay, so a much-later, unrelated crash restarts quickly.
  • There is no fixed cap on restart attempts; each crash schedules exactly one more bounded restart.

Every auto-restart (attempt number, backoff, exit code, signal) is written to the diagnostics log, so a crash loop is visible after the fact — see Troubleshooting. You can also restart the runtime manually from the runtime status indicator in the app.

The runtime keeps your terminals alive across renderer reloads and brief main-process restarts. Surviving a crash of the runtime process itself is not yet guaranteed — that is a planned hardening area.

Runtime states

The runtime status indicator surfaces one of these states:

StateMeaningWhat to do
startingThe runtime process is launching.Wait a moment.
readyHealthy and connected; terminals and agents work normally.Nothing.
binary-missingNo runtime binary was found at any known path.Build it, or set CORDY_RUNTIME_BIN (see below).
incompatibleThe runtime's protocol version does not match what this app build expects.Rebuild the runtime from matching source, or reinstall a matching app build.
crashedThe runtime exited unexpectedly; a bounded auto-restart is scheduled.Usually self-heals. If it keeps restarting, check the diagnostics log.
stoppedThe runtime was stopped deliberately (for example, at app shutdown).Restart the app or the runtime.

When the state is binary-missing, the app reports every path it tried, so you can see exactly where it looked. There is no separate "crash-loop" state — a crash loop shows up as crashed recurring in the diagnostics log with an increasing restart count.

Environment overrides

These environment variables tune runtime and window behavior. They are optional; the defaults are correct for normal use.

CORDY_RUNTIME_BIN

Points the app at a specific runtime binary — primarily for developers running a custom build. Binary resolution follows this order:

  1. CORDY_RUNTIME_BIN, if set and the file exists.
  2. <repoRoot>/cordy-runtime/target/debug/cordy-runtime[.exe] — an in-repo development build.
  3. <resourcesPath>/runtime/<platform>/cordy-runtime[.exe] — the packaged binary.

If none exists, the app surfaces binary-missing with the list of paths it tried, rather than silently disabling features.

CORDY_WINDOW_CLOSE_MODE

Controls what happens when you close the window to the tray on Windows. Values: hide or destroy. Default: destroy.

  • destroy (default) tears down the renderer after a data-safety suspend handshake to release its memory, while the runtime, PTYs, and agents keep running. Reopening reattaches to everything.
  • hide keeps the renderer resident in memory instead.

This variable only affects the Windows close-to-tray path.

CORDY_DEFAULT_SHELL

Sets the shell used for new terminals on Windows (default pwsh.exe). On macOS and Linux the shell comes from $SHELL, falling back to /bin/bash; this variable is the Windows-side override.

CORDY_USER_DATA_DIR

Overrides where Cordy stores its user data (projects, workspaces, notes, layout, settings, themes). When unset, Cordy uses the standard per-OS application-data location. See Privacy for what lives there.

Per-workspace configuration: .cordy/config.json

Each workspace can carry an optional config file at .cordy/config.json in its code directory. It defines setup and teardown commands that Cordy runs around the workspace lifecycle — the equivalent of "prepare this worktree" and "clean it up afterward."

{
  "schemaVersion": 1,
  "defaultAgent": "claude-code",
  "setup": ["./.cordy/setup.sh"],
  "teardown": ["./.cordy/teardown.sh"]
}
FieldTypePurpose
schemaVersionnumber (must be 1)Config format version. Required.
defaultAgentstring, optionalThe agent preset id to offer by default in this workspace.
setupstring array (default [])Commands run after the workspace (or its worktree) is created — for example, copy an env file or install dependencies.
teardownstring array (default [])Commands run before the workspace and its worktree are deleted — for example, tear down containers or scratch files.

Each entry in setup and teardown is a shell command string; you can inline commands or point at scripts you keep alongside the config in the .cordy/ directory. If the file is absent, the workspace behaves as if it had an empty config. A malformed file (invalid JSON or an invalid schema) is reported rather than silently ignored, and unknown fields are rejected.

Because setup and teardown run real shell commands from your repository, treat a project's .cordy/ directory with the same trust you would give any script committed to that repo.

No model calls, ever

To restate the boundary plainly: cordy-runtime supervises terminals and processes. It never calls a language model, never sees your provider keys, and never assembles prompts or manages context. Each CLI agent it launches talks to its own provider, in its own process, using its own configuration. See Agents and Privacy.

  • Troubleshooting — runtime failure states and diagnostics.
  • Agents — the CLI agents the runtime launches.
  • Privacy — where user data is stored.