Files
nettee 6b90486c97 docs: reconcile stale documentation with current code (#5829)
* fix(docs): align question guidance with form flow

* docs: reconcile stale documentation with current code

* fix(docs): remove retired template metadata from guides

Generated-By: looper 0.10.6 (runner=fixer, agent=codex)

* fix(e2e): stabilize visual workspace helper

Generated-By: looper 0.10.6 (runner=fixer, agent=codex)

* fix(docs): align localized template guide metadata

Generated-By: looper 0.10.6 (runner=fixer, agent=codex)
2026-07-18 03:41:08 +00:00

13 KiB

Plugin-driven flow plan

Parent: spec.md · Siblings: architecture-boundaries.md · maintainability-roadmap.md · run.md

Purpose

Make plugins 1:1 drive a complete run, give bare query input a deterministic fallback, and align Home entry with the NewProject taxonomy plus migration shortcuts. The shipped baseline now injects plugin-local SKILL.md, binds unselected Home submissions through a shared default-scenario resolver, and runs pipeline stages through the atom registry by default. The remaining orchestration gap is narrower: only critique-theater has a daemon-observable worker today, while the other built-in atoms still use permissive signals.

Goals / non-goals

  • Goals
    • Every plugin reaches the agent prompt with its own SKILL.md body and pipeline contract intact, so the same Use plugin action yields the same artifact across runs.
    • "Naked" Home query input gets auto-bound to a default scenario plugin keyed off the project kind so there is no zero-plugin path.
    • Home input card surfaces an intent rail for the main creation kinds plus Figma, template, and plugin-authoring shortcuts. Folder linking lives in the composer Tools → Import surface, and the generic Other path remains the free-form prompt.
  • Non-goals
    • Marketplace / third-party plugin distribution changes.
    • Transport changes between web and daemon.
    • Replacing the agent CLI loop. We keep the LLM as the primary worker; we only formalise stage orchestration around it.

Shipped baseline and remaining gaps (referenced to code)

# Status Where Current state
G1 partial apps/daemon/src/server.ts#firePipelineForRun and apps/daemon/src/plugins/atoms/{registry,built-ins}.ts The registry runner is the default and OD_PIPELINE_RUNNER=stub is only a diagnostic fallback. critique-theater has the sole daemon-observable worker; other first-party atoms still return permissive signals.
G2 resolved apps/daemon/src/plugins/apply.ts Local ./SKILL.md bindings are read into the applied snapshot and reach composeDaemonSystemPrompt.
G3 resolved apps/daemon/src/routes/project/index.ts, apps/daemon/src/routes/runs.ts, and apps/web/src/components/HomeView.tsx A submission without an explicit plugin resolves and applies the shared default scenario instead of taking a zero-plugin path.
G4 resolved packages/contracts/src/plugins/scenario-defaults.ts Web and daemon share one kind/task-kind/intent resolver, including specialised prototype, deck, media, migration, live-artifact, and web-clone defaults.
G5 partial apps/web/src/components/home-hero/chips.ts and apps/web/src/components/HomeHero.tsx The primary intent rail shipped and has since expanded. Dedicated secondary rail rows and an inline Figma URL field remain follow-ups; folder linking moved to composer Tools → Import.

Target architecture

plugin manifest (od.pipeline.stages[])
  └─ daemon stage runner          (registry by default; stub is diagnostic only)
       └─ atom executor registry  (per-atom handler)
            └─ agent CLI process  (LLM + tool calls, prompt carries plugin skill + active stage)
  • The agent stays the primary "worker"; the new layer is the daemon-side enforcement of stage order, atom-prompt fragments, and exit signals.
  • Plugin-local SKILL.md flows into the same ## Active skill slot as global skills, just sourced from plugin.fsPath/<path> instead of SKILLS_DIR.
  • The default-scenario binding moves to a single resolver shared by /api/projects, /api/runs, and EntryShell so the client and daemon never disagree.

Kind → default scenario plugin

metadata.kind / taskKind Bundled scenario
prototype example-web-prototype
deck example-simple-deck
template, brand, other od-new-generation
image, video, audio od-media-generation
metadata.intent: live-artifact example-live-artifact
metadata.intent: web-clone example-web-clone
figma-migration taskKind od-figma-migration
code-migration taskKind od-code-migration
tune-collab taskKind od-tune-collab

Stages

Stage Status Notes
A shipped Plugin-local SKILL.md reaches ## Active skill; Home query auto-binds default scenario per kind.
B shipped (MVP) Chip rail mirrors the creation taxonomy and adds Figma / template / plugin-authoring shortcuts. Folder linking subsequently moved to composer Tools → Import. Dedicated secondary rail rows and an inline figmaUrl input remain deferred.
C shipped (MVP) Bundled od-media-generation scenario for image/video/audio; uses existing media-image / media-video / media-audio atoms rather than a new wrapper atom.
D shipped (MVP) apps/daemon/src/plugins/atoms/registry.ts + built-ins.ts introduce an atom worker registry; firePipelineForRun now drives stages through runStageWithRegistry. Set OD_PIPELINE_RUNNER=stub to fall back to the v1 canned-signal runner. Real workers only ship for critique-theater today (reads run_devloop_iterations.critique_summary for the latest parseable score); every other FIRST_PARTY_ATOM registers a permissive worker so happy-path convergence matches v1.
E shipped (MVP) The original package gates landed. The repository now has tools-dev-backed Playwright coverage for the Home rail and a real-daemon authoring run; focused event-level assertions for every fallback/chip path remain a follow-up rather than a limitation of the harness.

Stage A — Plugin actually injects, Home never runs naked

Smallest change with the largest stability win.

# File Change
A1 apps/daemon/src/plugins/apply.ts Replace pickFirstSkillId with pickFirstSkillBinding returning `{ kind: 'global', id }
A2 apps/daemon/src/plugins/snapshots.ts + contracts AppliedPluginSnapshot Add optional pluginSkillBody. Persist alongside other JSON fields.
A3 apps/daemon/src/server.ts#composeDaemonSystemPrompt When snapshot carries pluginSkillBody, prefer it over the global skill body for the ## Active skill block.
A4 packages/contracts/src/plugins/scenario-defaults.ts plus web/daemon consumers Keep DEFAULT_SCENARIO_PLUGIN_BY_KIND and task/intent resolution in one shared mapping.
A5 apps/daemon/src/routes/project/index.ts and apps/daemon/src/routes/runs.ts When the body carries no pluginId/appliedPluginSnapshotId and no project pin exists, look up the bundled scenario for the project metadata/task kind and apply it.
A6 apps/daemon/tests New tests cover local skill injection + default-by-kind binding.

Exit criteria

  • Picking a plugin → run logs show ## Active skill — <plugin> block with the plugin's SKILL.md contents.
  • Submitting a Home query with no plugin → snapshot row exists and pluginId matches the kind mapping.
  • Existing plugin / non-plugin tests still pass.

Stage B — Home intent rail (Lovart-style)

  • HomeHero adds a home-hero__rail row.
  • The original primary slice shipped Prototype · Slide deck · Image · Video · Audio plus From template and From Figma; the rail has since expanded with more creation intents and plugin authoring.
  • Other remains the free-form fallback. Folder linking is available from composer Tools → Import instead of a rail chip.
  • Dedicated secondary rail rows remain a follow-up. Selecting a creation chip records the matching scenario and applies it on submit so Enter follows the same plugin-bound run path as explicit Use plugin.

Stage C — Media + migration scenario fill-in

  • Add bundled scenario od-media-generation. The pipeline reuses the already-shipped media-image / media-video / media-audio atoms; no dedicated media-generate wrapper is needed and the original plan's mention of a separate atom is superseded by this note.
  • The scenario shares taskKind: 'new-generation' with od-new-generation. The daemon's collectBundledScenarios dedupes by taskKind, preferring the canonical od-<taskKind> id so the pipeline-fallback stays deterministic.
  • Surface "From Figma" on the Home rail and keep folder linking in the composer import tools.
    • "From Figma" applies the od-figma-migration plugin (which carries the figmaUrl input). A dedicated inline figmaUrl field is deferred to a follow-up; the chip's prompt-template substitution still surfaces {{figmaUrl}} so the user can edit before submit.
    • "Link code folder" opens the existing folder picker from composer Tools → Import and persists the selected path in project linkedDirs; it is no longer represented as a Home rail scenario.

Stage D — Real stage / atom workers (replaces the stub)

As shipped (MVP):

  • apps/daemon/src/plugins/atoms/registry.ts owns the atom worker registry: registerAtomWorker, runStageWithRegistry, and the frozen PERMISSIVE_DEFAULT_SIGNALS table. Real-worker outputs replace permissive defaults wholesale so a real score of 5 never gets clipped to 4; cross-worker conflicts inside a single stage still pessimistically merge (false-wins / lowest-number-wins).
  • apps/daemon/src/plugins/atoms/built-ins.ts registers a worker for every FIRST_PARTY_ATOMS entry on first use. Only critique-theater ships a real watcher today — it reads run_devloop_iterations.critique_summary for the latest parseable score=N token. Every other atom registers a permissive worker that returns no signals (so the defaults flow through) — that keeps backwards-compat with the v1 stub while documenting the worker surface for future migrations.
  • apps/daemon/src/server.ts#firePipelineForRun now branches on OD_PIPELINE_RUNNER: default (registry) drives stages through runStageWithRegistry; OD_PIPELINE_RUNNER=stub falls back to the canned signal pump for diagnostic bisection.

Deferred to a follow-up:

  • Real watchers for file-write, live-artifact, direction-picker, discovery-question-form, todo-write, etc. These require either an agent-write protocol that touches DB rows the daemon can observe, or a side-channel (artifacts table / genui surface responses) wired into worker reads. The registry shape is ready; only the workers themselves remain.
  • Strengthen ## Active stage block so the agent has to acknowledge each atom's outputs. (Today the contracts-side renderActiveStageBlock already exists; we still need to gate stage progression on the agent's structured acknowledgement.)

Stage E — Verification gate

  • pnpm guard + pnpm typecheck green.
  • Daemon + web package tests green.
  • e2e/ui/home-hero-rail.test.ts covers the rail interactions, and e2e/ui/real-daemon-run.test.ts covers a daemon-backed plugin-authoring run that produces the expected folder and action cards.
  • Remaining event-level follow-up: assert that a bare query, explicit plugin pick, and Figma chip each end with pipeline_stage_completed. There is no folder-chip case after folder linking moved out of the rail.

File map

Added by the shipped stages

  • plugins/_official/scenarios/od-media-generation/{open-design.json,SKILL.md}
  • apps/daemon/src/plugins/atoms/registry.ts
  • apps/web/src/components/home-hero/chips.ts
  • packages/contracts/src/plugins/scenario-defaults.ts
  • apps/web/tests/components/HomeHero.rail.test.tsx
  • packages/contracts/tests/scenario-defaults.test.ts
  • apps/daemon/tests/plugins-scenario-fallback.test.ts
  • apps/daemon/tests/plugins-local-skill.test.ts

Modified

  • apps/daemon/src/plugins/apply.ts
  • apps/daemon/src/plugins/snapshots.ts
  • apps/daemon/src/server.ts
  • apps/daemon/src/plugins/pipeline.ts
  • apps/daemon/src/prompts/system.ts
  • apps/web/src/components/EntryShell.tsx
  • apps/web/src/components/HomeHero.tsx
  • apps/web/src/components/HomeView.tsx
  • apps/web/src/styles/home/index.css
  • packages/contracts/src/plugins/apply.ts (AppliedPluginSnapshot adds optional pluginSkillBody)

Risks

  • R1 — Plugin SKILL.md may conflict with a project-pinned skill. Resolution order: plugin > project skill > kind default.
  • R2 — Media surface already drives prompts through the media generate CLI; od-media-generation must not double-inject.
  • R3 — Stage D changes runtime behaviour. Retain OD_BUNDLED_ATOM_PROMPTS=0 and OD_PIPELINE_RUNNER=stub as explicit diagnostic escape hatches while the remaining workers gain observable contracts.

Open questions

  • Q1 — Persist the Home secondary chip selection (model picker) to user config or keep session-only? Session-only for v1.
  • Q2 — Resolved after the first release: folder linking moved out of the rail and now lives under composer Tools → Import.

Verification commands

pnpm guard
pnpm typecheck
pnpm --filter @open-design/daemon test
pnpm --filter @open-design/web test