Skip to main content
Xum can run workspaces in Daytona sandboxes. Each new Daytona workspace gets its own sandbox, and Xum connects to it over SSH through Daytona’s SSH gateway. Builds, tests, and other agent commands use the sandbox’s CPU and memory, not your machine’s. Under the hood a Daytona workspace is an SSH workspace, so XUM_RUNTIME is ssh.

Requirements

  • A Daytona account and an API key from the Daytona dashboard
  • ssh installed on the machine running Xum
  • A Linux snapshot (or Daytona’s default) with git and your toolchain. Xum runs Linux shell commands over SSH, so it does not offer Windows snapshots, and refuses one before it creates a sandbox.

Set up access

  1. Open Settings > Runtimes and find the Daytona row.
  2. Paste your API key and click Save.
  3. Click Test connection.
Xum stores the key in ~/.xum/daytona.json (under XUM_ROOT when it is set) with file mode 0600. The settings page never shows a saved key again: to change it, enter a new one, or click Remove key. Without a saved key, Xum uses DAYTONA_API_KEY from its own environment. A saved key wins over the environment. For a self-hosted (BYOC) Daytona install, set DAYTONA_API_URL in the environment of the Xum server. It must use https://, so that no one on the network can read the API key; http:// works only for a loopback host (localhost, 127.0.0.1 or ::1). A DAYTONA_API_URL that is not accepted keeps Daytona unavailable until you fix it; Xum never sends the key to another deployment instead. DAYTONA_TARGET picks a default region; without it, Daytona uses its default.
Do not put your Daytona API key in Secrets. Xum passes secrets to agent turns and terminals, so an agent could read the key and create or delete sandboxes in your organization.

Sizes

Small is the default. Xum offers only these sizes, which keeps costs predictable.

Create a workspace

  1. In the new-workspace controls, choose Daytona as the runtime.
  2. Pick a snapshot and a size.
  3. Xum creates the sandbox, waits until it starts, clones the project, and runs the init hook.
Xum labels each sandbox it creates with xum.instance, xum.workspaceId, and xum.project. If Daytona rejects the size for a snapshot, Xum creates the sandbox at the snapshot’s size and then resizes it. Xum uses only sandboxes it creates: a workspace cannot use an existing sandbox.

Lifecycle

Each sandbox belongs to the workspace that created it. Archiving or deleting that workspace deletes the sandbox, even while forks of it (sub-agent worktrees) still use it; Settings > General > Remote box on archive does not apply to Daytona. Unarchiving a workspace whose sandbox was deleted does not bring the sandbox back, so push or copy any work you need before you archive. An agent cannot archive the workspace that created a sandbox: it asks you to do it. Archiving or deleting a fork removes only its worktree and never stops or deletes the sandbox. Xum records the id of each sandbox it creates in the workspace’s settings, and every Daytona request about the sandbox uses that id, so a sandbox that later gets the same name is never touched. Before Xum starts a sandbox, opens SSH access to it, or deletes it, it also checks that the sandbox carries this install’s xum.instance label. A sandbox without it (for example one whose label was removed) is never used or deleted, and Xum notes it in its log. A forced delete removes the workspace even when Daytona refuses to delete the sandbox; it then shows a warning that names the sandbox, which you delete in the Daytona dashboard. Xum does not stop or delete sandboxes that no workspace uses (for example one whose delete failed); Daytona stops them after 30 minutes idle. Delete them in the Daytona dashboard.

SSH setup

Xum writes the SSH settings for its sandboxes to ~/.xum/ssh/daytona.conf and adds a managed block to the top of ~/.ssh/config that includes it for hosts named <sandbox-name>.xum--daytona. The gateway’s access token is the SSH user name; Xum keeps it in memory and gets it for one hour. When Xum brings a sandbox up for a turn or a terminal, it replaces a token that has less than 15 minutes left. Xum does not replace tokens in the background, so your own SSH clients can be refused after the hour until Xum uses the sandbox again. Xum revokes the token when it replaces it, when you change the Daytona settings, and when it deletes the sandbox. At startup, Xum takes over the tokens that an earlier run left in daytona.conf, so it can filter and revoke them too. Before each SSH command it reads the file again, in case that read failed at startup. When an SSH command to a running sandbox fails (for example the gateway refuses a token revoked outside Xum, or Daytona moved its gateway or changed its host keys), Xum reads the gateway settings from Daytona again, rewrites the SSH settings, gets a new token, and runs the command again once. Xum replaces any token it finds in SSH errors and logs with <daytona-token>; output of commands that you or an agent run in a terminal is not filtered. Xum pins the gateway’s host keys in ~/.xum/ssh/daytona_known_hosts and refuses a gateway whose key does not match, with OpenSSH and with the built-in SSH2 transport alike. This holds for xum server too, which otherwise skips host key checks for SSH hosts. Xum’s own SSH connections to sandboxes read only daytona.conf (OpenSSH runs with -F), so nothing in your ~/.ssh/config or in /etc/ssh/ssh_config applies to them: a Host * entry’s User, ProxyCommand, KnownHostsCommand, forwards or Match exec never run for a sandbox, and neither does a system-wide proxy or jump host. The managed block in ~/.ssh/config is for your own SSH clients, such as an editor’s Remote-SSH, which do read your config. OpenSSH uses the first value it finds for each setting, and Xum keeps its block first in the file, so its settings win for sandboxes in those clients too: strict host key checking against the pinned keys, the token as the user name, no proxy or jump host, no agent or X11 forwarding, and LogLevel QUIET, because an ssh error message would print the token. Your other entries still apply to every other host. A KnownHostsCommand or Match exec line in your config still runs for sandboxes in your own clients, with the token as %r; scope such lines to the hosts that need them. OpenSSH adds up RemoteForward lines instead of keeping the first, so a RemoteForward in a Host * entry also opens a tunnel from the sandbox to your machine in those clients; scope it to the hosts that need it.

Notes

  • Costs: Daytona bills running sandboxes by size and time. Archive or delete workspaces you no longer need, and pick the smallest size that works.
  • CPU count: nproc inside a sandbox reports the host’s CPUs, not the sandbox’s, so builds may start too many parallel jobs. Set job counts (for example MAKEFLAGS=-j4) in your snapshot or in the project’s .xum/tool_env.
  • User-level hooks and skills in a sandbox live under ~/.mux, the same as on other SSH hosts.