# Plugin authoring flow plan **Parent:** [`spec.md`](../../docs/spec.md) · **Related:** [`plugin-driven-flow-plan.md`](plugin-driven-flow-plan.md) · [`plugins-implementation.md`](../../docs/plans/plugins-implementation.md) ## Purpose Make "create my own plugin" a first-class product flow instead of a disconnected future tab. A user should be able to start from the Plugins area, land on the Home prompt with an authoring query already prepared, run an agent task that produces an OpenDesign plugin folder, inspect that folder as project output, and add it to `My plugins` with one click. This plan is intentionally focused on the authoring loop. Marketplace publishing, enterprise private catalogs, and team review policies stay out of scope. ## Requirements - R1. Plugins tab exposes a create entry that starts a guided plugin authoring task instead of only offering import options. - R2. The create entry navigates to Home, focuses `HomeHero`'s textarea, and pre-fills a prompt grounded in the OpenDesign plugin spec. - R3. The task should create a real plugin folder containing at minimum `SKILL.md` and `open-design.json`, with optional examples/assets when the user asks for them. - R4. Project output must support selecting or viewing the generated plugin folder as a folder, not only as flat single files. - R5. A generated plugin folder can be installed into the user plugin registry and then appears in `My plugins` and Home `@` search. - R6. Home's intent rail exposes a "Create plugin" chip that reuses the same authoring handoff, prompt contract, and `od-plugin-authoring` scenario as the Plugins entry. ## Scope boundaries - No marketplace publishing in this pass. Installing to `My plugins` is enough. - No enterprise/team catalog permissions in this pass. - No new plugin spec dialect. The generated folder must validate against the existing OpenDesign plugin shape in `docs/plugins-spec.md` and `docs/schemas/open-design.plugin.v1.json`. - No requirement to build a full visual plugin IDE. The first version is an agent-guided task plus a one-click install action. ### Deferred to follow-up work - Marketplace publishing and team review workflows belong after local authoring and `My plugins` install are reliable. ## Current code context - `apps/web/src/components/PluginsView.tsx` already owns the Plugins tab, `Create / Import` button, import modal, `My plugins` tab, and refresh-after-install behavior. - `apps/web/src/components/HomeView.tsx` owns prompt state, plugin apply lifecycle, and `HomeHero` focus via `inputRef`. - `apps/web/src/components/HomeHero.tsx` renders the textarea, `@` picker, and intent rail. - `apps/web/src/components/home-hero/chips.ts` defines the declarative `create-plugin` rail chip; `HomeView` dispatches it through the same authoring handoff used by the Plugins entry. - `apps/web/src/components/EntryShell.tsx` owns view switching and the Home submit path that creates a project with `pendingPrompt` and `autoSendFirstMessage`. - `apps/web/src/state/projects.ts` already exposes `installPluginSource`, `uploadPluginFolder`, and `uploadPluginZip` for user plugin installation. - `apps/daemon/src/routes/plugins/index.ts` registers `/api/plugins/install`, `/api/plugins/upload-folder`, `/api/plugins/upload-zip`, `/api/applied-plugins/export`, and the project-relative `/api/projects/:id/plugins/install-folder` route. The route handlers are composed from `apps/daemon/src/server.ts`. - `apps/daemon/src/plugins/scaffold.ts`, `apps/daemon/src/plugins/export.ts`, and `apps/daemon/src/plugins/validate.ts` already encode scaffold/export/validate behavior that the authoring flow should reuse. ## Key decisions - The product entry is "Create plugin", not "Create from template" alone. Template scaffolding is one possible implementation detail, but the user intent is to describe a workflow and let the agent produce a plugin. - Plugins tab and the Home rail are now equivalent supported entries: both prepare the same editable Home prompt and bind the same authoring scenario. - Use the shipped dedicated bundled scenario `od-plugin-authoring`. The `od-new-generation` fallback remains only a compatibility bridge when an older registry does not contain the authoring scenario. - The generated plugin folder should live inside the project work directory so it can be inspected, edited, and installed without forcing a browser folder upload. - One-click "Add to My plugins" should install from a daemon-visible project output path through the same local install path used by `/api/plugins/install`, then refresh web plugin state. ## High-level flow > This illustrates the intended approach and is directional guidance for review, not implementation specification. ```mermaid sequenceDiagram participant Plugins as Plugins tab participant Home as Home prompt participant Daemon as Daemon/project run participant Files as Project files participant Registry as User plugin registry Plugins->>Home: Navigate home with plugin-authoring prefill Home->>Home: Focus textarea and show editable prompt Home->>Daemon: Submit project with authoring prompt and scenario Daemon->>Files: Agent writes generated-plugin/ Files->>Plugins: Surface folder with Add to My plugins action Plugins->>Daemon: Install generated-plugin/ as local user plugin Daemon->>Registry: Register InstalledPluginRecord(sourceKind=user/local) Registry->>Home: listPlugins includes new plugin for @ search ``` ## Proposed implementation units - [x] U1. **Home prefill and focus contract** **Goal:** Add a reusable way to navigate to Home with a prefilled prompt and focus the textarea. **Files:** - Modify: `apps/web/src/router.ts` - Modify: `apps/web/src/components/EntryShell.tsx` - Modify: `apps/web/src/components/HomeView.tsx` - Test: `apps/web/tests/router-marketplace.test.ts` - Test: `apps/web/tests/components/HomeHero.plugin-picker.test.tsx` or a new `apps/web/tests/components/HomeView.prefill.test.tsx` **Approach:** - Prefer a small route/session handoff rather than global singleton state. The handoff should carry `{ prompt, focus: true, source: 'plugin-authoring' }`. - `HomeView` should consume the handoff once, set `prompt`, and call the existing textarea ref focus path. - Keep the prompt user-editable before submit. **Test scenarios:** - Happy path: navigating from Plugins with an authoring handoff renders Home, fills the textarea, and focuses it. - Edge case: refreshing Home after the handoff does not repeatedly overwrite a user's edited prompt. - Integration: submitting the prefilled prompt still creates a project through the existing `PluginLoopSubmit` path. - [x] U2. **Plugins create entry** **Goal:** Turn the Plugins tab `Create / Import` surface into two clear actions: guided create and import. **Files:** - Modify: `apps/web/src/components/PluginsView.tsx` - Modify: `apps/web/src/styles/home/plugins-view.css` - Test: `apps/web/tests/components/PluginsView.test.tsx` **Approach:** - Keep GitHub/zip/folder import in the existing modal. - Add a primary `Create plugin` action that uses U1 to navigate to Home with a spec-grounded authoring prompt. - Keep "Create from template" in the import modal only if it launches the same authoring path or explicitly remains marked as coming soon. **Test scenarios:** - Happy path: clicking `Create plugin` triggers Home navigation with the expected prefill payload. - Regression: GitHub/zip/folder import still installs and lands in `My plugins`. - Accessibility: the create action has a clear button label and does not masquerade as a disabled tab. - [x] U3. **Plugin authoring scenario** **Goal:** Give the agent a purpose-built plugin authoring context that asks for the right files and validation behavior. **Files:** - Create: `plugins/_official/scenarios/od-plugin-authoring/open-design.json` - Create: `plugins/_official/scenarios/od-plugin-authoring/SKILL.md` - Modify: `apps/web/src/components/home-hero/chips.ts` - Test: `apps/daemon/tests/plugins-bundled-scenarios-roster.test.ts` - Test: `apps/daemon/tests/plugins-local-skill.test.ts` **Approach:** - The scenario should instruct the agent to output a folder such as `generated-plugin/` with `SKILL.md`, `open-design.json`, and optional `examples/` or `assets/`. - The prompt should cite the OpenDesign plugin spec and require validation-ready output, not a prose-only explanation. - If the scenario includes GenUI, it should present checklist/progress and final "Add to My plugins" affordance, but the install action itself should call a daemon API rather than relying on copy/paste. **Test scenarios:** - Happy path: bundled scenario appears in plugin list and can be applied. - Integration: applying the scenario injects its local `SKILL.md` body into the run snapshot. - Regression: regular `od-new-generation` and migration scenarios are unaffected. - [x] U4. **Generated folder visibility in project output** **Goal:** Let users inspect and select a generated plugin folder from the project workspace. **Files:** - Modify: `apps/web/src/components/DesignFilesPanel.tsx` - Modify: `apps/web/src/components/FileWorkspace.tsx` - Modify: `apps/web/src/components/FileOpsSummary.tsx` if folder outputs are surfaced from tool/file ops - Modify: daemon project file listing endpoints in `apps/daemon/src/server.ts` if they currently flatten directories too aggressively - Test: `apps/web/tests/components/FileWorkspace.test.tsx` - Test: daemon project file listing tests near the existing project/file tests **Approach:** - Preserve relative paths so `generated-plugin/open-design.json` and `generated-plugin/SKILL.md` remain visibly grouped. - A minimal v1 can show a folder row in `DesignFilesPanel` and expand to its files; it does not need a full IDE tree. - The folder row should expose the install action only when it contains a plugin marker file. **Test scenarios:** - Happy path: a project with `generated-plugin/open-design.json` and `generated-plugin/SKILL.md` renders a folder group. - Edge case: nested files remain selectable without losing their relative path. - Error path: malformed or partial plugin folders do not show a misleading install success action. - [x] U5. **Install generated folder as My plugin** **Goal:** Add a one-click action that installs a daemon-visible generated folder into the user plugin registry. **Files:** - Modify: `apps/web/src/state/projects.ts` - Modify: `apps/web/src/components/DesignFilesPanel.tsx` or the GenUI surface that owns the final action - Modify: `apps/daemon/src/server.ts` - Reuse: `apps/daemon/src/plugins/installer.ts` - Reuse: `apps/daemon/src/plugins/validate.ts` - Test: `apps/web/tests/state/projects.test.ts` - Test: `apps/web/tests/components/FileWorkspace.test.tsx` - Test: `apps/daemon/tests/plugins-installer.test.ts` - Test: `apps/daemon/tests/plugins-validate.test.ts` **Approach:** - Add a web helper such as `installGeneratedPluginFolder(projectId, relativePath)` rather than forcing a browser upload. - The daemon endpoint should resolve the folder under the project work directory, validate traversal safety, validate plugin shape, install through the existing installer, and return a `PluginInstallOutcome`-compatible response. - On success, web should refresh `listPlugins()`, switch/open `My plugins`, and make the plugin available to Home `@` search. **Test scenarios:** - Happy path: project output folder installs and appears as a user/local plugin. - Error path: invalid folder returns diagnostics and does not mutate installed plugins. - Security: `../` traversal or absolute paths outside the project root are rejected. - Integration: after install, `GET /api/plugins` includes the new record with non-`bundled` source kind. - [x] U6. **Home rail create-plugin chip parity** **Goal:** Let the Home rail entry use the same authoring flow without duplicating behavior. **Files:** - Modify: `apps/web/src/components/home-hero/chips.ts` - Modify: `apps/web/src/components/HomeView.tsx` - Modify: `apps/web/src/components/HomeHero.tsx` - Test: `apps/web/tests/components/HomeHero.rail.test.tsx` **Approach:** - Add a `create-plugin` chip action that invokes the U1 prefill/focus contract. - Keep the payload shape identical so Plugins tab and rail remain interchangeable entrypoints. **Test scenarios:** - Happy path: clicking the chip fills the same prompt as Plugins tab create. - Regression: existing Prototype/Image/Figma/Template chips continue dispatching their current actions. Folder linking is owned by the composer Tools → Import path, not the Home rail. ## Prompt contract The authoring prompt should be stable enough for tests and user trust. A first version can be: ```text Create an OpenDesign plugin for: . Follow docs/plugins-spec.md and produce a folder named generated-plugin with: - SKILL.md describing the agent behavior and workflow - open-design.json with valid metadata, mode, task kind, inputs, and any pipeline/context references - optional examples/ and assets/ when useful When finished, summarize the files created and whether the folder is ready to add to My plugins. ``` Implementation can enrich this with the current locale and UI-provided goal, but the required output folder and marker files should stay stable. ## Risks - **Generated output is prose-only:** Use a dedicated authoring scenario and prompt contract that explicitly requires files. - **Folder paths become unsafe:** Resolve generated-folder installs relative to the project root only; reject traversal and absolute external paths. - **Validation errors feel like failure:** Return validation diagnostics in the UI so users can ask the agent to fix the plugin instead of starting over. - **Duplicate plugins:** Installer should use existing plugin id/version collision behavior and surface clear messages before overwriting or upgrading. - **Two entrypoints diverge:** Plugins tab and Home rail must share the same prefill payload and prompt contract. ## Verification plan - Web component coverage for Plugins create entry, Home prefill/focus, and rail parity. - Web state coverage for installing a generated project folder. - Daemon tests for project-root path resolution, validation failure, and successful install. - The daemon-backed Playwright smoke in `e2e/ui/real-daemon-run.test.ts` covers Home rail → Create plugin → bound `od-plugin-authoring` run → generated `generated-plugin/` files → action cards in chat and Design Files. Keep the remaining install-to-Home-`@` assertion covered at the web state/API layers until the browser smoke is extended. ## Open questions - Resolved: generated output defaults to `generated-plugin/` for predictable UI detection; final install still uses the manifest id. - Resolved: "Add to My plugins" is exposed both on the assistant action card and in `DesignFilesPanel`, backed by the same project-relative install handler. - Should the daemon expose a scaffold API now, or should the authoring scenario ask the agent to create files directly? Direct file creation is simpler for v1; scaffold API becomes useful for template-first creation.