Files
PaperClipAI/packages/plugins/sandbox-providers/exe-dev
Valentin PalkovicandClaude Opus 5.5 bb73f2fe39 feat(exe-dev): copy a source VM with exe.dev cp (#14975)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The exe.dev sandbox provider plugin gives each run its own exe.dev
VM
> - Today the plugin always creates that VM with `exe.dev new`, so every
run starts from a bare image
> - Large repositories need a long setup on each VM: toolchain, agent
CLIs, package caches, and browsers for tests
> - exe.dev has a `cp` command that copies an existing VM, disk and
config included
> - This pull request adds an optional `sourceVm` setting. When it is
set, the plugin copies that VM with `exe.dev cp` instead of creating a
new one
> - The benefit is that operators prepare one VM once, and each run
starts from it

## Linked Issues or Issue Description

Refs #13575. That open PR rewrites this plugin for durable exe.dev
environments. It does not add `cp`. The two changes touch the same files
and can conflict.

I found no issue for this. Feature description:

**Subsystem affected**
packages/plugins: the exe.dev sandbox provider plugin
(`packages/plugins/sandbox-providers/exe-dev`).

**Problem or motivation**
Each run gets a fresh exe.dev VM from `exe.dev new`. We use a large
monorepo (Storybook). Before the agent can work, each run must install
Node, the agent CLIs, and Playwright browsers. Each run must also fill
the package manager cache. This setup takes a long time on each run.

**Proposed solution**
Add a `sourceVm` setting ("Source VM" in the environment form). When it
is set, lease acquisition and probes run `exe.dev cp <sourceVm>
<generated-name> --json`. The command also sends the configured `cpu`,
`memory`, and `disk`. The VM name, the SSH setup, the workspace, and the
release and destroy steps do not change. When the setting is blank, the
plugin uses `exe.dev new` as before.

**Alternatives considered**
- A custom image with `--image`: the operator must build and push a
large image for each change. A private registry needs `--registry-auth`,
and the plugin does not support it.
- `--setup-script`: it runs on every new VM, so each run still pays the
setup cost. It also has a 10 KiB limit.
- `reuseLease`: it keeps one VM for one lease. It does not give each run
a fresh copy of a prepared VM.

**Roadmap alignment**
The change stays inside an existing sandbox provider plugin.
`ROADMAP.md` lists "Cloud / Sandbox agent support" as done and does not
plan VM copies. CONTRIBUTING.md asks to discuss features in Discord
`#dev` first. I open this pull request as a draft and start that
discussion in `#dev`.

**Additional context**
exe.dev documents `cp` here: https://exe.dev/docs/cli-cp. exe.dev token
permissions are documented here: https://exe.dev/docs/https-api.

## What Changed

- `plugin.ts`: add `sourceVm` to the driver config.
- `plugin.ts`: `buildCreateCommand` sends `cp` when `sourceVm` is set.
- `plugin.ts`: config validation rejects `sourceVm` together with
settings that `cp` cannot apply (`image`, `command`, `comment`, `env`,
`integrations`, `tags`, `setupScript`, `prompt`). The error names the
settings to clear. The server shows validation errors in the form, but
it does not show warnings after a successful save.
- `manifest.ts`: add the "Source VM" field to the "VM creation" group.
Its description says that the API token must allow `cp`, because exe.dev
returns 403 for a command that the token does not list. The API key
description now also mentions `cp`.
- `README.md`: document `sourceVm`, its limits, and the token
permission.
- `plugin.test.ts`: add tests for the `cp` command, the validation
error, and the form field. Add `sourceVm: null` to the expected
normalized config.

## Verification

- `vitest run --config vitest.config.ts` in
`packages/plugins/sandbox-providers/exe-dev`: 38 tests pass. The three
new tests fail without the change.
- `tsc --noEmit -p packages/plugins/sandbox-providers/exe-dev`: no
errors.
- Manual test on a self-hosted Paperclip instance (2026.1001.0). I
applied the same change to the installed plugin. I prepared a source VM
and set "Source VM" on an exe.dev environment. Then I ran agent tasks.
Each run copied the source VM and ran in the copy. Paperclip deleted the
copy at release.
- With an API token that does not list `cp`, the run fails with `exe.dev
API command failed (403) for: cp '<source>' '<name>' --json ...`. The
new field description tells operators about this.

## Risks

- Low risk. The new code runs only when `sourceVm` is set. The `new`
path is unchanged.
- `cp` uses the same `/exec` endpoint and its 30-second request limit. A
copy of a very large disk can take longer than the limit.
- Every copy inherits the source VM disk. The README tells operators not
to keep secrets on the source VM.
- Can conflict with #13575.

## Model Used

- Provider and model: Anthropic Claude Opus 5.5.
- Model ID: `claude-opus-5-5`.
- Tool: Claude Code, with tool use (shell commands and file edits) and
extended thinking.
- Context window: the tool does not report it.
- The model wrote the change and the tests. A human tested the feature
on a real exe.dev setup.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<img width="1166" height="852" alt="Bildschirmfoto 2026-10-02 um 23 04
32"
src="https://github.com/user-attachments/assets/c057bee4-9f27-4a69-945e-0f71d5bcc1ba"
/>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 22:11:59 -07:00
..
…
…

@paperclipai/plugin-exe-dev

Published exe.dev sandbox provider plugin for Paperclip.

This package lives in the Paperclip monorepo, but it is intentionally excluded from the root pnpm workspace and shaped to publish and install like a standalone npm package. That lets operators install it from the Plugins page by package name without introducing root lockfile churn.

Install

From a Paperclip instance, install:

@paperclipai/plugin-exe-dev

Configuration

Configure exe.dev from Instance Settings -> Environments, not from the plugin's plugin page.

  • Put the exe.dev API token on the sandbox environment itself.
  • When you save an environment, Paperclip stores pasted API keys and pasted SSH private keys as company secrets.
  • EXE_API_KEY remains an optional host-level fallback when an environment omits the API token.
  • The current implementation provisions VMs through exe.dev's HTTPS API and runs commands through direct SSH to the created VM.

To use the provider successfully, the environment/host needs all of the following:

  • An exe.dev API token that allows the lifecycle commands the provider uses: new, ls, and rm, plus cp when sourceVm is set. exe.dev answers 403 for a command the token does not list. whoami and help are recommended for manual debugging. restart is only needed if you extend the provider to restart retained VMs.
  • SSH access from the Paperclip host to the resulting *.exe.xyz VMs.
  • An SSH private key that exe.dev already recognizes. You can either:
    • paste the private key into the environment config via sshPrivateKey
    • point sshIdentityFile at an absolute host path
    • or leave both blank and rely on the host's default SSH agent/keychain
  • The matching public key must already be registered with exe.dev before the provider can execute commands inside the VM.

Operational notes:

  • If exe.dev replies Please complete registration by running: ssh exe.dev, the host key has not finished exe.dev onboarding yet.
  • Reusable leases keep the VM alive between runs. exe.dev does not expose a documented "stop and later resume" command in the public CLI docs, so reuseLease: true means "retain the VM" rather than "suspend it."
  • The provisioning path uses https://exe.dev/exec, which exe.dev documents as a command-style HTTPS API with a 30-second request timeout. Typical new calls are expected to fit inside that limit; command execution itself does not use /exec.
  • Probes still create and delete a real exe.dev VM through /exec, and so do the new/rm calls inside the normal acquire/release lifecycle. Treat all of those as real provisioning cost, not just probes.
  • Set sourceVm ("Source VM" in the form) to the name of an existing exe.dev VM to copy it for each run with exe.dev cp, disk and config included, instead of creating a fresh VM with exe.dev new. This lets you prepare one VM with your toolchain and caches and start every run from it. cp accepts only the VM name, cpu, memory, and disk, so config validation rejects sourceVm together with image, command, comment, env, integrations, tags, setupScript, or prompt. The default setup script does not run either, so the source VM must already have Node 24.11+ and accept the configured SSH key. Do not keep secrets on the source VM: every copy inherits its disk. cp also goes through /exec, so a large disk copy must finish inside the same 30-second limit.
  • exe.dev runs --setup-script as the unprivileged exedev user, not as root. That user has passwordless sudo, so any system-level steps in a custom setupScript must invoke sudo explicitly (for example sudo apt-get install -y …). When you omit setupScript, the plugin supplies a default that installs Node 24 via the official nodesource script — Paperclip's sandbox callback bridge is a Node program, so the VM needs node on PATH before the bridge can launch.

Local development

cd packages/plugins/sandbox-providers/exe-dev
pnpm install --ignore-workspace --no-lockfile
pnpm build
pnpm test
pnpm typecheck

These commands assume the repo root has already been installed once so the local @paperclipai/plugin-sdk workspace package is available to the compiler during development.

Package layout

  • src/manifest.ts declares the sandbox-provider driver metadata
  • src/plugin.ts implements the environment lifecycle hooks
  • paperclipPlugin.manifest and paperclipPlugin.worker point the host at the built plugin entrypoints in dist/