Files
paperclip/packages/plugins/sandbox-providers/exe-dev
Devin Foley 93291df5c8 fix(plugins): move dev SDK linking out of plugin postinstall scripts (#8255)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox-provider plugins (cloudflare, daytona, e2b, exe-dev,
kubernetes, modal, novita) and `plugin-workspace-diff` are published as
standalone npm packages, but during local dev they need the in-repo
`@paperclipai/plugin-sdk` symlinked in
> - Each of these plugins shipped a `postinstall` lifecycle script that
traversed *out* of its own package directory (`node
../../../../scripts/link-plugin-dev-sdk.mjs`) to do that linking
> - The publishable manifest is built by a `prepack` whitelist that
drops the `scripts` field, so npm consumers don't see the postinstall
today — but that safety property depends entirely on `prepack` running
on every publish. A publish that skips lifecycle scripts would ship a
tarball whose postinstall escapes its package directory at consumer
install time
> - This pull request removes the escape-the-package-dir lifecycle
script from every plugin source manifest and moves the dev linking to a
single root-level postinstall that iterates the excluded plugin
directories itself
> - The benefit is that plugin tarballs can no longer carry an
install-time script that reaches outside their own directory, regardless
of whether `prepack` runs

## Linked Issues or Issue Description

This is a follow-up hardening change flagged during review of the Novita
sandbox provider PR (#7595).

**Problem (security):** Excluded plugin packages each carried
`"postinstall": "node ../../../../scripts/link-plugin-dev-sdk.mjs"`. The
relative path traverses outside the package root. Today the published
manifest is sanitized by a `prepack` whitelist that drops `scripts`, so
consumers are unaffected in the normal publish path. The risk is that
this is a defense-in-depth gap: if a publish ever skips lifecycle
scripts (e.g. `npm publish --ignore-scripts` is *not* used, or a tool
publishes the raw manifest), the tarball would ship a postinstall that
runs out-of-tree code at the consumer's install time.

## What Changed

- Added a single root `package.json` `postinstall`: `node
scripts/link-plugin-dev-sdk.mjs`.
- Rewrote `scripts/link-plugin-dev-sdk.mjs` to iterate the excluded
plugin directories itself (`packages/plugins/sandbox-providers/*` + the
orchestration smoke example) instead of relying on each plugin to invoke
it from its own cwd. Preserves both prior behaviors: leave a real
installed SDK dir alone, and skip when already correctly symlinked
(idempotent).
- Removed `scripts.postinstall` from all 7 sandbox-provider plugins
(cloudflare, daytona, e2b, exe-dev, kubernetes, modal, novita).
- Removed `scripts.postinstall` from `plugin-workspace-diff` (a pnpm
workspace member — pnpm already links the SDK, so the script was a no-op
there).

## Verification

- `node scripts/link-plugin-dev-sdk.mjs` from repo root: links the SDK
into the excluded plugins and reports skipped (already-linked) dirs;
re-running is idempotent.
- `grep -r "link-plugin-dev-sdk" packages/plugins/*/package.json
packages/plugins/sandbox-providers/*/package.json` returns no matches —
no plugin source manifest references the linker any longer.
- All affected `package.json` files re-validated as parseable JSON.

## Risks

Low risk. Dev-only tooling: the linker only runs at the repo root during
local install and only touches `node_modules/@paperclipai/plugin-sdk`
symlinks inside excluded plugin dirs. No change to published plugin
behavior or runtime code. Worst case if the root postinstall failed to
run, local dev of an excluded plugin would not find the SDK symlink —
easily re-run manually.

## Model Used

Claude Opus (claude-opus-4-8), extended reasoning, with tool use / code
execution in an agentic coding harness.

## 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 OR (b) described the
issue in-PR following the relevant issue template
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable (added
`scripts/link-plugin-dev-sdk.test.js`, wired into
`test:release-registry`)
- [ ] If this change affects the UI, I have included before/after
screenshots (N/A — no UI change)
- [ ] I have updated relevant documentation to reflect my changes (N/A)
- [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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-18 07:45:53 -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 Company Settings -> Environments, not from the plugin's instance settings 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. 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.
  • 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 20 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/