Files
paperclip/doc/plugins/LOCAL_PLUGIN_DEVELOPMENT.md
Dotta b947a7d76c [codex] Improve local plugin development workflow (#5821)
## Thinking Path

> - Paperclip is the control plane for autonomous AI-agent companies.
> - Plugins are the extension point for adding capabilities without
expanding the core product surface.
> - Local plugin development needed a tighter CLI-first loop so plugin
authors can scaffold, run, install, inspect, and reload plugins without
reaching into internal package paths.
> - The server plugin install path also needed local-path handling that
keeps plugin identity, dashboard routes, and development watchers
coherent.
> - This pull request adds the CLI scaffold/install workflow, fixes the
server and SDK edge cases that blocked that loop, and updates the
agent-facing plugin creation skill and docs.
> - The benefit is that contributors can develop plugins from local
folders with a documented, repeatable happy path.

## What Changed

- Added `paperclipai plugin init` coverage and CLI wiring for local
plugin scaffolding.
- Improved local plugin install handling, plugin key route resolution,
dashboard capability behavior, and dev watcher startup/reload behavior.
- Fixed plugin SDK worker entrypoint validation for symlinked package
layouts.
- Added targeted tests for plugin init, server plugin authz/watcher
behavior, SDK worker host validation, and the authoring smoke example.
- Added a short local plugin development guide and refreshed the plugin
authoring guide plus `paperclip-create-plugin` skill instructions.

## Verification

- `pnpm run preflight:workspace-links && pnpm --filter
@paperclipai/plugin-sdk build && pnpm --filter
@paperclipai/create-paperclip-plugin typecheck && pnpm --filter
paperclipai typecheck && pnpm --filter @paperclipai/plugin-sdk typecheck
&& pnpm --filter @paperclipai/server typecheck`
- `pnpm exec vitest run --project paperclipai
cli/src/__tests__/plugin-init.test.ts`
- `pnpm exec vitest run --project @paperclipai/plugin-sdk
packages/plugins/sdk/tests/worker-rpc-host.test.ts`
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/plugin-dev-watcher.test.ts --pool=forks
--poolOptions.forks.isolate=true`
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/plugin-routes-authz.test.ts --pool=forks
--poolOptions.forks.isolate=true`
- `pnpm --dir packages/plugins/examples/plugin-authoring-smoke-example
test`
- Confirmed `pnpm-lock.yaml` is not included in the PR diff.

## Risks

- Medium risk: this touches plugin install routing, CLI command
behavior, and the local development watcher.
- Local path plugin installs execute trusted local code by design; the
new docs call out that trust boundary.
- No database migrations are included.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, GPT-5 coding agent, tool-enabled local shell and git
workflow, medium reasoning effort. Context window details were not
exposed in this runtime.

## 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

UI screenshots: not applicable; this PR changes CLI/server/plugin docs
and tests, not board UI rendering.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-12 17:38:24 -05:00

8.3 KiB

Local Plugin Development

This is the short happy-path guide for developing a Paperclip plugin from a folder on your machine. You will scaffold a plugin, run it in watch mode, install it into a running Paperclip instance from an absolute local path, and edit code with the plugin worker reloading after each rebuild.

For the full alpha surface — manifest fields, capabilities, managed agents/projects/routines, UI slots, scoped API routes — see PLUGIN_AUTHORING_GUIDE.md.

Prerequisites

  • Node.js 22+ and pnpm.
  • A local Paperclip checkout you can run from source. Local plugin installs read source from disk, so the running server must be able to see the path you give it.

The five steps

# 1. Start Paperclip locally
pnpm paperclipai run

# 2. Scaffold a plugin outside the Paperclip repo
paperclipai plugin init @acme/hello-plugin --output ~/dev/paperclip-plugins

# 3. Install dependencies and start the watch build
cd ~/dev/paperclip-plugins/hello-plugin
pnpm install
pnpm dev

# 4. In another terminal, install the plugin from its absolute path
paperclipai plugin install ~/dev/paperclip-plugins/hello-plugin

# 5. Confirm it loaded
paperclipai plugin list
paperclipai plugin inspect acme.hello-plugin

That's the loop. The rest of this page explains what each step does and what to expect when you edit code.

1. Start Paperclip

pnpm paperclipai run

Paperclip listens on http://127.0.0.1:3100 by default. The CLI talks to that server, so leave it running.

2. Scaffold the plugin

paperclipai plugin init @acme/hello-plugin --output ~/dev/paperclip-plugins

This creates ~/dev/paperclip-plugins/hello-plugin/ with src/manifest.ts, src/worker.ts, src/ui/index.tsx, an esbuild watch config, a Vitest config, and a snapshot of @paperclipai/plugin-sdk from your local Paperclip checkout. You can run the package and tests without publishing anything to npm.

Useful flags:

  • --template <default|connector|workspace|environment> — starter shape.
  • --category <connector|workspace|automation|ui|environment> — manifest category.
  • --display-name, --description, --author — manifest metadata.
  • --sdk-path <absolute-path> — point at a specific packages/plugins/sdk checkout if you have more than one.

When plugin init finishes, it prints the next four commands literally. You can copy them.

3. Install dependencies and run the watch build

cd ~/dev/paperclip-plugins/hello-plugin
pnpm install
pnpm dev

pnpm dev runs esbuild --watch against the plugin source and emits dist/manifest.js, dist/worker.js, and dist/ui/. Leave it running. Every time you save, esbuild rebuilds the affected output file.

If your plugin has UI and you want a browser-side dev server with hot module replacement during local UI iteration, run pnpm dev:ui in a second terminal. It serves dist/ui/ on http://127.0.0.1:4177. This is optional; Paperclip can load the built UI directly from dist/ui/ without it.

4. Install from the absolute path

paperclipai plugin install ~/dev/paperclip-plugins/hello-plugin

The CLI auto-detects local paths (anything that looks absolute, starts with ./, ../, or ~, or resolves to an existing folder relative to the current directory) and sends { isLocalPath: true } to POST /api/plugins/install with the resolved absolute path. If you want to be explicit, pass --local.

You will see a confirmation like:

Installing plugin from local path: /Users/you/dev/paperclip-plugins/hello-plugin
✓ Installed acme.hello-plugin v0.1.0 (ready)
Local plugin installs run trusted local code from your machine.
Keep `pnpm dev` running in /Users/you/dev/paperclip-plugins/hello-plugin;
Paperclip watches rebuilt dist output and reloads the plugin worker.

Relative paths are resolved against the current working directory, so paperclipai plugin install . from inside the plugin folder works too.

5. Inspect

paperclipai plugin list
paperclipai plugin inspect acme.hello-plugin

list shows plugin key, status, version, and short error. inspect prints the same record with the full last error if there is one. Both accept --json if you want to script against them.

Reload semantics, honestly

Paperclip watches the on-disk plugin package after a local install. The watcher targets the runtime entrypoints declared in the package's paperclipPlugin field (dist/manifest.js, dist/worker.js, dist/ui/).

What that means in practice:

  • Worker code: save a .ts file → esbuild rewrites dist/worker.js → Paperclip debounces ~500ms and restarts the plugin worker. The next worker call uses the new code. There is no in-process hot module replacement for worker code; it is a worker restart.
  • Manifest: save src/manifest.tsdist/manifest.js rewrites → the worker restarts and the host re-reads the manifest.
  • Plugin UI: save a .tsx file → esbuild rewrites dist/ui/ → Paperclip reloads the UI bundle on its next mount. To get HMR during UI iteration, run pnpm dev:ui and point at the dev server with devUiUrl in your manifest while developing.
  • Without pnpm dev: the watcher only fires on dist/* changes. If you stop the watch build, source edits do not reach Paperclip. Restart pnpm dev (or run pnpm build once) before expecting changes.
  • node_modules, .git, .paperclip-sdk, and other dotfolders are ignored. Adding a dependency requires the new code to actually be imported and rebuilt before the worker sees it.

The server never compiles plugin source for you. The package's own build scripts own that step.

Local path plugins vs npm packages

Both go through the same install endpoint, but they mean different things:

  • Local path plugins are trusted local code. Paperclip executes worker code from disk under the same trust boundary as the rest of the running instance. This is meant for developing or operating a plugin against a checkout you control. There is no signature check, no sandboxing of worker code, and no provenance metadata beyond the path. Do not install local-path plugins you did not write.
  • npm packages are the deployable artifact. paperclipai plugin install @acme/plugin-foo (optionally --version 1.2.3) installs from your configured npm registry, version-pins, and produces an install record that other operators can reproduce. Ship plugins this way.

When you are done iterating locally, publish the package and reinstall the npm-package form so the install reflects what you will ship.

Common things to do next

  • Restart cleanly: paperclipai plugin disable <key> pauses the plugin without removing it. paperclipai plugin enable <key> brings it back. paperclipai plugin uninstall <key> removes the install record; add --force to also purge plugin state and settings.
  • Browse examples: paperclipai plugin examples lists the bundled example plugins that ship with the repo, each with a ready-to-run paperclipai plugin install <path> line.
  • Go deeper: PLUGIN_AUTHORING_GUIDE.md covers worker capabilities, managed agents/projects/routines, plugin database namespaces, scoped API routes, and the shared UI components in @paperclipai/plugin-sdk/ui. PLUGIN_SPEC.md is the longer-form specification, including future ideas that are not yet implemented.

Troubleshooting

  • Plugin install returned no plugin record or error status. Run paperclipai plugin inspect <key> for the last error. The most common causes are (1) the plugin has not built yet — run pnpm dev or pnpm build first, (2) the paperclipPlugin entries in package.json point at files that do not exist on disk, or (3) the manifest failed validation. The Paperclip server log has the full validation error.
  • Edits do not seem to reload. Confirm pnpm dev is still running and writing to dist/. If you renamed entry files, update the paperclipPlugin.manifest / paperclipPlugin.worker / paperclipPlugin.ui fields in package.json so the watcher targets them.
  • Worker restarts but UI is stale. Hard-reload the page. If you want HMR, run pnpm dev:ui and set devUiUrl in your manifest to http://127.0.0.1:4177 during development.
  • Path arguments fail on Windows. Quote paths that contain spaces, and prefer absolute paths over ~-prefixed paths in non-bash shells.