Skip to content

[stories] Allow vibe coded plugins inside nao stories (first draft) - #1465

Draft
Bl3f wants to merge 2 commits into
mainfrom
cursor/story-vibe-coded-plugins-c806
Draft

[stories] Allow vibe coded plugins inside nao stories (first draft)#1465
Bl3f wants to merge 2 commits into
mainfrom
cursor/story-vibe-coded-plugins-c806

Conversation

@Bl3f

@Bl3f Bl3f commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Closes #1464

First draft of vibe coded plugin blocks inside nao stories.

What this adds

New <plugin> story block. Stories can now embed <plugin title="...">…JavaScript ES module code…</plugin> blocks. The code must be a self-contained vanilla JS module with export default function render(element) that renders into the provided DOM element (no imports, no external network calls). Parsing lives in apps/shared/src/story-segments.ts as a new plugin segment variant, with validation (closing tag, non-empty code) in story-validation.ts.

Admin toggle, off by default. New storyPlugins.enabled key in project AgentSettings, editable only by admins via project.updateAgentSettings. A "Vibe coded plugins" card is added to Settings → Project → Agent, plus a settings search index entry.

Agent gating. The story tool description only teaches the agent the plugin tag, module contract, and usage restrictions when the setting is enabled; when disabled the description never mentions plugins. The live-story refresh prompt preserves <plugin> blocks verbatim.

Movable but not editable. In the story TipTap editor, plugin blocks are atom nodes with the standard drag grip and drop zones: they can be reordered, grouped into <grid> columns, and moved within/out of grids, and the raw markup round-trips losslessly. There is no edit affordance anywhere (no pencil, no edit dialog); the editor shows a labeled placeholder card. All other blocks keep their existing edit behavior.

Rendering. In read/preview mode the plugin module is loaded via a blob URL import() (same pattern as custom chart plugins) and rendered into a framed card with loading/error states and cleanup on unmount. Backend static HTML export (story-html.tsx) deliberately skips plugin execution.

Testing

  • npm run lint (tsc + eslint across backend/frontend/shared): passes
  • npm run format:check: passes
  • New shared tests for plugin parsing (mixed stories, missing title, JS containing </>, plugins as grid columns) and validation: pass
  • New backend test verifying the tool description is gated by the setting: passes
  • Pre-existing unrelated failures (also fail on a clean tree): chart-builder.test.tsx width assertion in shared, and backend tests importing bun:sqlite under the Node vitest runner

Notes for review

  • This is a first draft: plugin code currently executes unsandboxed in the viewer (same trust model as existing custom chart plugins loaded via blob import). An iframe/sandbox hardening pass could follow.
  • Rendering is not gated by the setting — the toggle gates generation (the agent tool). Existing stories containing plugin blocks still render if the toggle is later disabled; happy to change that if you'd rather hard-gate rendering.
Open in Web Open in Cursor 

Review in cubic

cursoragent and others added 2 commits August 25, 2026 08:51
…ins agent setting

Co-authored-by: Christophe Blefari <christophe.blefari@gmail.com>
Co-authored-by: Christophe Blefari <christophe.blefari@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

URL https://pr-1465-c096368.preview.getnao.io
Commit c096368

⚠️ No LLM API keys configured - you'll see the API key setup flow when trying to chat.


Preview will be automatically removed when this PR is closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants