A Paperclip plugin that surfaces all issue documents in one place. Browse, search, edit, and archive documents across your entire workspace without digging through individual tickets.
- Unified document list — all documents across all projects, grouped by project name
- Full-text search — filter by document title, issue identifier, issue title, or project name
- Inline markdown viewer — rendered preview with full theme support (light/dark)
- Inline editing — edit documents directly and save back to the source issue
- Archive/unarchive — hide documents you no longer need; view and restore them anytime
- Download — export any document in its native format (.md, etc.)
- Issue detail tab — "Documents" tab on every issue links directly to the plugin viewer
- Sidebar navigation — quick access from the main nav
- Reindex on demand — pull the latest documents from all issues with one click
There is no separate UI step. The Paperclip host auto-discovers plugins from node_modules/ in the plugins directory. Installing the npm package is the full installation.
cd /path/to/.paperclip/plugins
npm install github:rwbaker/plugin-documentsAfter npm install completes, the host scans the plugins directory, reads each package's paperclipPlugin.manifest pointer from package.json, imports the manifest module, validates capabilities, and registers the plugin's UI slots (sidebar link, pages, detail tabs). No restart or additional command is needed — the plugin appears in the Paperclip UI automatically.
The Paperclip plugin host has specific expectations that differ from a normal npm package. Here's what tripped us up:
-
dist/must be committed to the repo. The plugin host runsnpm install --ignore-scripts, soprepack/postinstallhooks (including the build step) never execute. Ifdist/is in.gitignore, the installed package will be missing the compiled worker, manifest, and UI bundle. Keepdist/tracked in git. -
package-lock.jsonmust NOT be committed. Local path references in the lockfile can break installs on other machines. The.gitignorealready excludes it — don't override that. -
Package name must be unscoped. The plugin host resolves packages by dependency key as a directory under
node_modules/. A scoped name like@org/plugin-documentscreates a nested path (node_modules/@org/plugin-documents) that doesn't match how the host looks up plugins. Use an unscoped name:plugin-documents. -
Manifest file must not be named
manifest.mjs. Node.js cachesimport()results by file path. If a previous (broken) manifest was cached atdist/manifest.mjs, renaming it won't help unless the filename itself changes. We usedist/plugin-manifest.mjs— set that inpackage.jsonunderpaperclipPlugin.manifest. -
Manifest field values are validated strictly:
categoriesmust use a valid enum value (ui, notproductivity)routePathmust be a single-segment slug (documents, not/documents)
- Node.js >= 20
- Paperclip SDK
>=2026.416.0 - Capabilities (declared in manifest):
issues.read— list issues to find documentsissue.documents.read— read document contentissue.documents.write— save edits back to source issuesprojects.read— group documents by projectplugin.state.read/plugin.state.write— persist index and archive stateui.page.register— register the/documentspageui.sidebar.register— register the sidebar nav link
# Install dependencies
npm install
# Build worker, manifest, and UI bundles
npm run build
# Type-check without emitting
npm run typecheck
# Run tests (Node.js native test runner)
npm test
# Start dev server on port 4178
npm run devThe build (node build.mjs) produces three bundles via esbuild:
| Source | Output | Target |
|---|---|---|
src/worker.ts |
dist/worker.mjs |
Node 20 (ESM) |
src/manifest.ts |
dist/plugin-manifest.mjs |
Node 20 (ESM) |
src/ui/index.tsx |
dist/ui/index.js |
Browser (ES2022) |
The UI bundle externalizes react, react/jsx-runtime, and @paperclipai/plugin-sdk/ui — these are provided by the Paperclip host at runtime.
MIT