diff --git a/doc/plugins/LOCAL_PLUGIN_DEVELOPMENT.md b/doc/plugins/LOCAL_PLUGIN_DEVELOPMENT.md index 18b033e3..3bf7b009 100644 --- a/doc/plugins/LOCAL_PLUGIN_DEVELOPMENT.md +++ b/doc/plugins/LOCAL_PLUGIN_DEVELOPMENT.md @@ -2,7 +2,12 @@ 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`](./PLUGIN_AUTHORING_GUIDE.md). +For the full alpha surface — manifest fields, capabilities, managed agents/projects/routines/skills, UI slots, scoped API routes — see [`PLUGIN_AUTHORING_GUIDE.md`](./PLUGIN_AUTHORING_GUIDE.md). + +If your plugin has background-like recurring work, model it as managed resources: +declare managed routines plus managed agents/projects/skills, then reconcile those +resources in worker actions. This gives operators visible work items, budgets, +pause controls, and consistent audits instead of hidden daemon behavior. ## Prerequisites @@ -126,7 +131,8 @@ When you are done iterating locally, publish the package and reinstall the npm-p - **Restart cleanly:** `paperclipai plugin disable ` pauses the plugin without removing it. `paperclipai plugin enable ` brings it back. `paperclipai plugin uninstall ` 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 ` line. -- **Go deeper:** [`PLUGIN_AUTHORING_GUIDE.md`](./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`](./PLUGIN_SPEC.md) is the longer-form specification, including future ideas that are not yet implemented. +- **Go deeper:** [`PLUGIN_AUTHORING_GUIDE.md`](./PLUGIN_AUTHORING_GUIDE.md) covers worker capabilities, managed agents/projects/routines/skills, plugin database namespaces, scoped API routes, and the shared UI components in `@paperclipai/plugin-sdk/ui`. [`PLUGIN_SPEC.md`](./PLUGIN_SPEC.md) is the longer-form specification, including future ideas that are not yet implemented. +- **Routine-first automation:** If your plugin should produce periodic issue work, prefer managed routines and `ctx.routines.managed` reconciliation over custom process loops or unobserved cron code. ## Troubleshooting diff --git a/doc/plugins/PLUGIN_AUTHORING_GUIDE.md b/doc/plugins/PLUGIN_AUTHORING_GUIDE.md index eb20163b..dca3ec62 100644 --- a/doc/plugins/PLUGIN_AUTHORING_GUIDE.md +++ b/doc/plugins/PLUGIN_AUTHORING_GUIDE.md @@ -13,6 +13,8 @@ It is intentionally narrower than [PLUGIN_SPEC.md](./PLUGIN_SPEC.md). The spec i - Worker-side host APIs are capability-gated. - Plugin UI is not sandboxed by manifest capabilities. - Plugin database migrations are restricted to a host-derived plugin namespace. +- Plugin-managed surfaces are first-class records (agents, projects, routines, and + skills) rather than private plugin-only state. - Plugin-owned JSON API routes must be declared in the manifest and are mounted only under `/api/plugins/:pluginId/api/*`. - The host provides a small shared React component kit through @@ -74,6 +76,7 @@ Worker: - issues, comments, namespaced `plugin:` origins, blocker relations, checkout assertions, assignment wakeups, and orchestration summaries - agents, plugin-managed agents, and agent sessions - plugin-managed routines +- plugin-managed skills - goals - data/actions - streams @@ -134,11 +137,16 @@ paths; they always remain under `/api/plugins/:pluginId/api/*`. Plugins that provide durable Paperclip business objects should declare them in the manifest and let the host create or relink the actual records per company. -Do this for plugin-owned agents, plugin-owned projects, and recurring automation. +Do this for plugin-owned agents, projects, routines, and skills. Do not hide long-lived work behind private plugin state when it should be visible to the board, scoped to a company, audited, budgeted, and assigned like normal Paperclip work. +Content-oriented plugins, such as LLM Wiki-style ingestion or durable knowledge +systems, should use the same pattern: managed projects for operation issues, +managed agents plus managed skills for LLM work, and managed routines for +ingest, lint, refresh, or maintenance runs. + Use these surfaces: - Managed agents: declare top-level `agents[]` and require @@ -155,10 +163,14 @@ Use these surfaces: jobs that should create visible Paperclip issues. Prefer managed routines over plugin `jobs[]` for recurring business work; plugin jobs are for plugin runtime maintenance that does not need a board-visible task trail. +- Managed skills: declare top-level `skills[]` and require `skills.managed`. + Use this for reusable plugin capabilities that should be surfaced to operators and + synced into Paperclip managed agents. Managed resources are resolved by stable plugin keys, not hardcoded database ids. In a worker action or data handler, call `ctx.agents.managed.reconcile()`, -`ctx.projects.managed.reconcile()`, and `ctx.routines.managed.reconcile()` for +`ctx.projects.managed.reconcile()`, `ctx.routines.managed.reconcile()`, and +`ctx.skills.managed.reconcile()` for the current `companyId`. `reconcile()` creates the missing resource, relinks a recoverable binding, or returns the existing resource. `reset()` reapplies the manifest defaults when the operator wants to restore the plugin's suggested @@ -185,6 +197,7 @@ const manifest: PaperclipPluginManifestV1 = { "agents.managed", "projects.managed", "routines.managed", + "skills.managed", "instance.settings.register", ], entrypoints: { @@ -231,6 +244,13 @@ const manifest: PaperclipPluginManifestV1 = { ], }, ], + skills: [ + { + skillKey: "weekly-brief-skills", + displayName: "Weekly Briefer", + description: "Reusable skill for the managed research workflow.", + }, + ], ui: { slots: [ { @@ -261,8 +281,9 @@ export default definePlugin({ const project = await ctx.projects.managed.reconcile("research", companyId); const agent = await ctx.agents.managed.reconcile("researcher", companyId); const routine = await ctx.routines.managed.reconcile("weekly-brief", companyId); + const skill = await ctx.skills.managed.reconcile("weekly-brief-skills", companyId); - return { project, agent, routine }; + return { project, agent, routine, skill }; }); }, }); @@ -270,14 +291,18 @@ export default definePlugin({ Authoring rules: -- Keep keys stable once published. Renaming `agentKey`, `projectKey`, or - `routineKey` creates a new managed resource from the host's point of view. +- Keep keys stable once published. Renaming `agentKey`, `projectKey`, + `routineKey`, or `skillKey` creates a new managed resource from the host's + point of view. - Use managed agents for plugin-provided labor. Use `ctx.agents.invoke()` or `ctx.agents.sessions` only after you have a real agent id, either selected by the operator or resolved from `ctx.agents.managed`. - Use managed routines for recurring or externally triggered work that should produce tasks. Schedule, webhook, and API triggers are visible routine triggers, and each run has the normal Paperclip issue/audit trail. +- Use managed skills for reusable operator-visible capabilities that are shared + by managed agents. Reconcile skill declarations by `skillKey` and keep the + declared skill markdown and files in sync with agent behavior. - Use managed projects to keep plugin-generated work organized and to give project-scoped plugin UI a stable home. For filesystem access inside a project, still resolve project workspaces through `ctx.projects`. @@ -300,6 +325,7 @@ Mount surfaces currently wired in the host include: - `settingsPage` - `dashboardWidget` - `sidebar` +- `routeSidebar` - `sidebarPanel` - `detailTab` - `taskDetailView` @@ -317,6 +343,10 @@ Paperclip-native control. The host owns the implementation, so plugins inherit the board's current styling, ordering, recent selections, and dark-mode behavior without importing `ui/src` internals. +Prefer shared components for common Paperclip UX patterns to reduce drift and +deprecation risk, especially for task/assignment flows and routine or sidebar-like +plugin screens. + Currently exposed components include: - `MarkdownBlock` and `MarkdownEditor` for rendered and editable markdown. diff --git a/doc/plugins/PLUGIN_SPEC.md b/doc/plugins/PLUGIN_SPEC.md index 31b9c9d0..c8080e56 100644 --- a/doc/plugins/PLUGIN_SPEC.md +++ b/doc/plugins/PLUGIN_SPEC.md @@ -319,7 +319,10 @@ export interface PaperclipPluginManifestV1 { version: string; displayName: string; description: string; + author: string; categories: Array<"connector" | "workspace" | "automation" | "ui">; + minimumHostVersion?: string; + /** @deprecated Use `minimumHostVersion` instead. Retained for backwards compatibility. */ minimumPaperclipVersion?: string; capabilities: string[]; entrypoints: { @@ -335,9 +338,33 @@ export interface PaperclipPluginManifestV1 { description: string; parametersSchema: JsonSchema; }>; + database?: PluginDatabaseDeclaration; + apiRoutes?: PluginApiRouteDeclaration[]; + environmentDrivers?: PluginEnvironmentDriverDeclaration[]; + agents?: PluginManagedAgentDeclaration[]; + projects?: PluginManagedProjectDeclaration[]; + routines?: PluginManagedRoutineDeclaration[]; + skills?: PluginManagedSkillDeclaration[]; + localFolders?: PluginLocalFolderDeclaration[]; + /** Legacy top-level launcher declarations. Prefer `ui.launchers` for new manifests. */ + launchers?: PluginLauncherDeclaration[]; ui?: { + launchers?: PluginLauncherDeclaration[]; slots: Array<{ - type: "page" | "detailTab" | "dashboardWidget" | "sidebar" | "settingsPage"; + type: "page" + | "detailTab" + | "taskDetailView" + | "dashboardWidget" + | "sidebar" + | "routeSidebar" + | "sidebarPanel" + | "projectSidebarItem" + | "globalToolbarButton" + | "toolbarButton" + | "contextMenuItem" + | "commentAnnotation" + | "commentContextMenuItem" + | "settingsPage"; id: string; displayName: string; /** Which export name in the UI bundle provides this component */ @@ -354,10 +381,17 @@ Rules: - `id` must be globally unique - `id` should normally equal the npm package name - `apiVersion` must match the host-supported plugin API version +- `minimumHostVersion` is preferred, with `minimumPaperclipVersion` retained for + backwards compatibility - `capabilities` must be static and install-time visible - config schema must be JSON Schema compatible - `entrypoints.ui` points to the directory containing the built UI bundle - `ui.slots` declares which extension slots the plugin fills, so the host knows what to mount without loading the bundle eagerly; each slot references an `exportName` from the UI bundle +- declare managed declarations with the matching `*.managed` capability: + - `agents` → `agents.managed` + - `projects` → `projects.managed` + - `routines` → `routines.managed` + - `skills` → `skills.managed` ## 11. Agent Tools @@ -631,6 +665,22 @@ Plugins that need filesystem, git, terminal, or process operations handle those Trusted orchestration plugins can create and update Paperclip issues through `ctx.issues` instead of importing server internals. The public issue contract includes parent/project/goal links, board or agent assignees, blocker IDs, labels, billing code, request depth, execution workspace inheritance, and plugin origin metadata. +Plugins that perform durable work should declare managed Paperclip resources rather than using private plugin state: + +- `agents` + `ctx.agents.managed.*` for named, invokable operators (`agents.managed` required) +- `projects` + `ctx.projects.managed.*` for stable, scoped issue/workspace ownership (`projects.managed` required) +- `routines` + `ctx.routines.managed.*` for schedule/webhook/manual execution with issue trails (`routines.managed` required) +- `skills` + `ctx.skills.managed.*` for reusable agent capabilities (`skills.managed` required) + +The LLM Wiki plugin is the current reference for this pattern: it declares managed +agents, projects, routines, and skills in manifest, reconciles them per company, +and uses managed routines for periodic wiki maintenance and ingest operations. +Content-oriented plugins should follow the same model instead of running +unmanaged background loops: make the LLM-facing worker an operator-visible +managed agent, attach reusable prompt/tool guidance as managed skills, keep +operation issues in a managed project, and drive recurring work through managed +routines. + Origin rules: - Built-in core issues keep built-in origins such as `manual` and `routine_execution`. @@ -746,20 +796,38 @@ The host enforces capabilities in the SDK layer and refuses calls outside the gr - `activity.read` - `costs.read` - `issues.orchestration.read` +- `database.namespace.read` ### Data Write - `issues.create` - `issues.update` - `issue.comments.create` +- `issue.interactions.create` - `issue.documents.write` - `issue.relations.write` - `issues.checkout` - `issues.wakeup` -- `assets.write` -- `assets.read` - `activity.log.write` - `metrics.write` +- `telemetry.track` +- `assets.read` +- `assets.write` +- `database.namespace.migrate` +- `database.namespace.write` +- `goals.create` +- `goals.update` +- `projects.managed` +- `routines.managed` +- `skills.managed` +- `agents.managed` +- `agents.pause` +- `agents.resume` +- `agents.invoke` +- `agent.sessions.create` +- `agent.sessions.list` +- `agent.sessions.send` +- `agent.sessions.close` ### Plugin State @@ -772,8 +840,10 @@ The host enforces capabilities in the SDK layer and refuses calls outside the gr - `events.emit` - `jobs.schedule` - `webhooks.receive` +- `local.folders` - `http.outbound` - `secrets.read-ref` +- `environment.drivers.register` ### Agent Tools @@ -786,6 +856,7 @@ The host enforces capabilities in the SDK layer and refuses calls outside the gr - `ui.page.register` - `ui.detailTab.register` - `ui.dashboardWidget.register` +- `ui.commentAnnotation.register` - `ui.action.register` ## 15.2 Forbidden Capabilities @@ -894,6 +965,7 @@ Job rules: 3. The host prevents overlapping execution of the same plugin/job combination unless explicitly allowed later. 4. Every job run is recorded in Postgres. 5. Failed jobs are retryable. +6. For recurring business workflows that should create visible Paperclip work, prefer managed routines and managed resources over jobs. Jobs remain useful for private plugin-runtime maintenance tasks. ## 18. Webhooks