Files

159 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Experimental durable exe.dev environments
Enable **exe.dev Environments** in Instance → Experimental, install this bundled
plugin, and create a sandbox environment using **exe.dev VM (experimental)**.
Daytona remains the preferred Cloud default. Cloud installs this plugin only for
releases and stacks explicitly opted into `enableExeEnvironments` with `exe-dev`
selected in the release-validated bundled plugin list.
An environment owns one named VM. Each agent/workspace lease has a separate home,
working directory, socket, and systemd cgroup on that VM. Agents sharing a VM must
trust each other: these directories are not security boundaries. A VM cannot be
bound to two Paperclip companies or environments.
## Credentials and creation
Register an SSH public key with exe.dev; save its matching private key in a
Paperclip company secret using the environment form. Management commands and VM
execution both use SSH, so an exe.dev HTTPS API token is unnecessary. An operator
may instead configure an absolute `sshIdentityFile`, or use
`EXE_DEV_SSH_PRIVATE_KEY` / `EXE_DEV_SSH_KEY_FILE` on a self-hosted controller.
Credentials remain on the controller and are never forwarded to the VM.
For a private image registry, set `registryAuth` to a company secret containing
`username:token` (or `EXE_DEV_REGISTRY_AUTH` for the explicit live harness). exe.dev
uses this credential to pull the image; agent commands do not receive it.
- **Attach:** specify `vmName` for an existing compatible VM.
- **Create:** specify an immutable `image@sha256:…` published from
`docker/exe-dev-runner/Dockerfile`. A stable name is derived from the company and
environment unless `vmName` is supplied. Retrying an uncertain create reconciles
that name. A connection test validates the account; the first run provisions
and verifies the image. An attached VM is inspected without modification.
Arbitrary images and boot-time package installation are unsupported. The image
contains Node, systemd, the execution supervisor, the Rust runner, its matching
provider pack, and the supported legacy CLIs. Missing runtimes fail with an image
compatibility error. Existing 0.1 per-run configurations require explicit migration
to a compatible named VM; upgrading the plugin never deletes those old VMs.
SSH uses a dedicated identity, disables agent forwarding, and rejects changed
host keys. `accept-new` persists first-use keys in
`~/.ssh/paperclip-exe-known_hosts`. For preverified keys, supply `knownHosts` entries
for both `exe.dev` and the VM; this forces strict checking.
## Lifetime and concurrency
Normal release retains the VM and reusable lease. Cancellation or lease destruction
stops only that lease's cgroup, waits for confirmation, and leaves files intact.
An SSH disconnection is not a termination receipt. A requested lease deadline
limits its systemd service; it never deletes the VM. Controller restart reattaches
to the same VM identity and disk. Missing or replaced VMs fail closed and require
explicit recovery into a new environment.
The controller stores the resource identity in reserved environment metadata,
independently of run leases. Concurrent acquisitions must agree on that identity.
A durable marker on the VM detects replacement even if its DNS name is reused.
There is no automatic VM deletion, disk reclamation, or in-place image upgrade.
Disconnecting an environment retains its VM; delete it explicitly in exe.dev when
its data is no longer needed.
Reusable directories are scoped to the agent and project workspace, or to the
agent and task when no project workspace exists. Concurrent runs receive distinct
leases; a retained lease can be reused only after its previous run releases it.
Agent homes and workspaces live under `/var/lib/paperclip-exe/<scope>/<lease>/`.
Use the normal isolated-workspace policy for concurrent task work. Separate Git
worktrees avoid two agents modifying the same checkout. This feature does not add
a service registry or port allocator. Start a persistent web server as a separate
systemd service if it must survive agent cancellation; choose its port explicitly.
VM previews must remain private and use exe.dev's own HTTPS sharing/authentication.
Native runners connect outward to a reachable `PAPERCLIP_RUNNER_PUBLIC_URL=wss://…`.
Cloud derives this origin from the stack's canonical hostname. Paperclip does not
proxy exe.dev preview pages.
## Files and backups
The first run seeds the remote workspace. Later runs adopt its persisted files;
legacy initialization is marked only after a successful seed. Completion uses the
existing baseline-based Git/file copyback pipeline. Unrelated host edits survive,
but a changed remote file takes precedence when the same file also changed on the
host. Use isolated worktrees for concurrent editing; this is not a conflict merge.
Native runs additionally use
the existing verified harness/session checkpoint and restart-recovery contract.
OpenCode checkpoints preserve its session database and history while excluding
disposable launch homes (including npm caches),
regenerated configuration (including launch credentials and npm executable
aliases) and caches. Codex launch credentials and scratch aliases are also excluded.
The existing exclusions still apply, including dependencies, generated/cache
folders, ignored files, and runtime scratch.
This is the same backup coverage as Daytona, not a disk image or continuous mirror
into object storage. In Cloud, copyback and native checkpoints under `PAPERCLIP_HOME`
land on the tenant's persistent volume, which has daily/weekly/monthly provider
backups. Explicitly uploaded artifacts use the separate object-storage path.
Files outside copied paths, live process memory, database consistency, ignored
files, and VM-wide state are not included. A controller filesystem outside the
backed-up volume needs its own backup policy. Restore is explicit and must be tested
against the data classes the application actually needs.
## Build and verification
```sh
pnpm --dir packages/plugins/sandbox-providers/exe-dev install --ignore-workspace
pnpm --dir packages/plugins/sandbox-providers/exe-dev build
pnpm --dir packages/plugins/sandbox-providers/exe-dev test
node cli/node_modules/tsx/dist/cli.mjs scripts/build-exe-dev-image.ts --push --metadata-file /tmp/exe-image.json
```
The manual **Experimental exe.dev image** workflow publishes a content-addressed
Linux amd64 image and an immutable digest artifact. Production builds require a
clean checkout and frozen dependencies. `PAPERCLIP_IMAGE_ALLOW_DIRTY=1` is only for
explicit local development builds.
Run the explicit paid browser matrix and provider stress campaign:
```sh
pnpm test:e2e:runner -- --suite exe-compatibility
pnpm test:e2e:runner -- --suite exe-recovery
pnpm test:e2e:runner -- --suite exe-warm-continuity
EXE_DEV_LIVE_SMOKE=1 node cli/node_modules/tsx/dist/cli.mjs tests/exe-dev-live/stress.ts
```
Both require `EXE_DEV_SSH_PRIVATE_KEY` and `PAPERCLIP_E2E_EXE_IMAGE`; browser cells
also require their model credentials. Native browser cells need an externally
reachable WSS origin. Native OpenCode/ACPX also require
`PAPERCLIP_RUNNER_REMOTE_PROVIDER_PACK_PATH` pointing to a build-owned Linux amd64
provider pack on the controller. The Cloud image builds and configures this pack;
self-hosted controllers must export `/opt/paperclip-runner/provider-pack` from the
matching exe image and configure its local path (including on macOS). Never use a
macOS provider pack for a Linux VM. For local testing, set `PAPERCLIP_E2E_RUNNER_TUNNEL_BIN` to an
installed `cloudflared` binary. The harness exposes only authenticated runner
WebSocket upgrades; all ordinary HTTP requests and board API paths return 404.
The matrix has seven profiles × three workflows. Stress
covers eight shared leases, concurrent commands, UTF-8/stdin, copyback, restart,
SSH loss, VM reboot, large output, escaped descendant cancellation, timeout,
cancellation isolation, and a separate private HTTP service. Set
`EXE_DEV_SOAK_MS` for an explicit idle soak. Campaign cleanup deletes only
campaign-owned VMs; production provider hooks never delete VMs.
The native Codex message cell additionally runs two native and one legacy agent
concurrently on its VM and checks distinct homes/workspaces. The four-cell
recovery suite covers structured question/resume with and without a controller
restart for legacy and native Codex. The two-cell warm suite checks three turns
on one workspace and stable native runner/process/session identity.
For longer campaigns, accountless Cloudflare tunnels can rate-limit new endpoints.
Use a single operator-owned WSS relay instead: run `tests/exe-dev-live/relay.ts`
with `PAPERCLIP_E2E_RUNNER_RELAY_REGISTRY` set to a private local directory, and
forward its loopback listener through a TLS endpoint. Set the same registry path
and `PAPERCLIP_E2E_RUNNER_RELAY_URL=wss://your-relay.example` in the E2E process.
Each harness registers its own random route and removes it on shutdown. The relay
forwards only registered runner WebSocket upgrades, retains the runner's capability
authentication, and returns 404 for ordinary HTTP and board APIs. Its TLS/SSH
endpoint is test infrastructure and must be removed after qualification.
`tests/exe-dev-live/preview.ts` provides an
interactive private Vite fixture with `create`, `cancel`, `edit`, and `cleanup`
commands; it deliberately keeps its VM until cleanup so a signed-in browser can
verify HMR and an idle soak.