---
title: "Integrate the editor"
description: "Agent playbook for adding @skaile/forge-editor to an app: choose the surface, then the entry to import, then follow the matching setup page."
canonical_url: "https://skaile-ai.github.io/forge-editor/ai-agents/integrate"
---
# Integrate the editor

> Agent playbook for adding @skaile/forge-editor to an app: choose the surface, then the entry to import, then follow the matching setup page.

## Choose the surface

Decide first which host the editor lands in. Each row links to the page that holds the ordered setup steps and the code; do not retype them from memory.

<table>
<thead>
  <tr>
    <th>
      Host
    </th>
    
    <th>
      Surface and entry
    </th>
    
    <th>
      Setup
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Nuxt app (editor plus backend)
    </td>
    
    <td>
      <code>
        AdvancedEditor
      </code>
      
       from <code>
        @skaile/forge-editor/vue/advanced
      </code>
      
      , module <code>
        @skaile/forge-editor/nuxt
      </code>
      
      , <code>
        EditorPorts
      </code>
      
       in a Nitro plugin
    </td>
    
    <td>
      <a href="https://skaile-ai.github.io/forge-editor/getting-started/quick-start-nuxt">
        Quick start: Nuxt
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      Plain Vue 3 app (Vite), no backend
    </td>
    
    <td>
      <code>
        SimpleEditor
      </code>
      
       from <code>
        @skaile/forge-editor/vue/simple
      </code>
      
      , <code>
        createEditor()
      </code>
    </td>
    
    <td>
      <a href="https://skaile-ai.github.io/forge-editor/getting-started/quick-start-vue">
        Quick start: Vue
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      React 19 app
    </td>
    
    <td>
      <code>
        SimpleEditor
      </code>
      
       from <code>
        @skaile/forge-editor/react/simple
      </code>
      
       inside <code>
        EditorContextProvider
      </code>
      
      ; <code>
        AdvancedEditor
      </code>
      
       from <code>
        @skaile/forge-editor/react/advanced
      </code>
    </td>
    
    <td>
      <a href="https://skaile-ai.github.io/forge-editor/getting-started/quick-start-react">
        Quick start: React
      </a>
      
      , <a href="https://skaile-ai.github.io/forge-editor/guides/advanced-react">
        Advanced editor in React
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      Framework-free (headless, server, validator)
    </td>
    
    <td>
      <code>
        /core
      </code>
      
      , the <code>
        <x>
      </code>
      
       entries without <code>
        /vue
      </code>
      
       or <code>
        /react
      </code>
      
      , <code>
        schema/*
      </code>
      
      , <code>
        /server
      </code>
    </td>
    
    <td>
      <a href="https://skaile-ai.github.io/forge-editor/reference/exports">
        Public exports
      </a>
    </td>
  </tr>
</tbody>
</table>

The Nuxt path in order: install the package and its peers ([Installation](https://skaile-ai.github.io/forge-editor/getting-started/installation)); register the module **after** `@nuxt/ui`; register `EditorPorts` in a Nitro plugin ([EditorPorts guide](https://skaile-ai.github.io/forge-editor/guides/editor-ports)); mount the editor inside `<UApp>` with the toolbar as a sibling that receives the editor from `ready`. The Nuxt module installs the client plugin with `createEditor`; plain Vue and React hosts create the context themselves.

`AdvancedEditor` pulls in every feature. For a smaller bundle use `SimpleEditor` or compose a list yourself.

## Choose a preset or features

Which preset or feature list fits the goal, and what each feature needs from the backend: [Composing an editor](https://skaile-ai.github.io/forge-editor/guides/composition) (decision table) and [Presets and features](https://skaile-ai.github.io/forge-editor/reference/presets-and-features) (every feature with `requires` and backend). Own features: [Add a block or feature](https://skaile-ai.github.io/forge-editor/ai-agents/extend).

## Which entry to import

Every entry is an explicit subpath of `package.json#exports`; a path that is not listed there does not resolve. Full inventory with every exported name: [Public exports](https://skaile-ai.github.io/forge-editor/reference/exports).

<table>
<thead>
  <tr>
    <th>
      You need
    </th>
    
    <th>
      Import
    </th>
    
    <th>
      Side
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      A ready simple editor component
    </td>
    
    <td>
      <code>
        SimpleEditor
      </code>
      
       from <code>
        @skaile/forge-editor/vue/simple
      </code>
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      A ready advanced editor component
    </td>
    
    <td>
      <code>
        AdvancedEditor
      </code>
      
       from <code>
        @skaile/forge-editor/vue/advanced
      </code>
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      A preset to pass to <code>
        EditorSurface
      </code>
      
      , <code>
        EditorToolbar
      </code>
      
      , <code>
        EditorSettingsPanel
      </code>
    </td>
    
    <td>
      <code>
        simpleEditor
      </code>
      
       from <code>
        .../presets/compose
      </code>
      
       (framework-free, no ⌘K palette), <code>
        advancedEditor
      </code>
      
       / <code>
        composeEditor
      </code>
      
       from <code>
        .../vue/advanced
      </code>
      
       or <code>
        .../react/advanced
      </code>
      
       (the framework-free assembly behind them is <code>
        .../presets/compose
      </code>
      
      : <code>
        composeEditor(ui, options)
      </code>
      
      , <code>
        CONTENT
      </code>
      
      , <code>
        INTERACTION
      </code>
      
      , <code>
        AI
      </code>
      
      )
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      Vue chrome: <code>
        createEditor
      </code>
      
       (mandatory Vue app context), <code>
        EditorSurface
      </code>
      
      , <code>
        EditorToolbar
      </code>
      
      , <code>
        EditorSettingsPanel
      </code>
      
      , <code>
        EditorSettingsModal
      </code>
      
      , <code>
        EditorCommandPalette
      </code>
      
       (⌘K palette, the <code>
        core-ui
      </code>
      
       overlay), <code>
        SettingsSection
      </code>
      
      , <code>
        useEditorSettings
      </code>
      
      , <code>
        useEditorUi
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/vue
      </code>
    </td>
    
    <td>
      browser (Vue)
    </td>
  </tr>
  
  <tr>
    <td>
      React chrome: <code>
        EditorContextProvider
      </code>
      
       (mandatory React context from <code>
        createEditorContext()
      </code>
      
      ), <code>
        EditorSurface
      </code>
      
      , <code>
        EditorToolbar
      </code>
      
      , <code>
        EditorSettingsPanel
      </code>
      
      , <code>
        EditorSettingsModal
      </code>
      
      , <code>
        EditorCommandPalette
      </code>
      
       (⌘K palette, the <code>
        core-ui
      </code>
      
       overlay), <code>
        SettingsSection
      </code>
      
      , <code>
        useEditorSettings
      </code>
      
      , <code>
        useEditorUi
      </code>
      
      , <code>
        Toaster
      </code>
      
      , <code>
        reactNotifier
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/react
      </code>
    </td>
    
    <td>
      browser (React)
    </td>
  </tr>
  
  <tr>
    <td>
      A ready simple editor component for React
    </td>
    
    <td>
      <code>
        SimpleEditor
      </code>
      
       from <code>
        @skaile/forge-editor/react/simple
      </code>
    </td>
    
    <td>
      browser (React)
    </td>
  </tr>
  
  <tr>
    <td>
      A ready advanced editor component for React
    </td>
    
    <td>
      <code>
        AdvancedEditor
      </code>
      
      , <code>
        advancedEditor
      </code>
      
       from <code>
        @skaile/forge-editor/react/advanced
      </code>
      
       (needs <code>
        EditorContextProvider
      </code>
      
       and <code>
        Toaster
      </code>
      
      )
    </td>
    
    <td>
      browser (React)
    </td>
  </tr>
  
  <tr>
    <td>
      shadcn token mapping for the feature CSS (React hosts)
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/react/styles/ui-vars.css
      </code>
      
      ; for the advanced editor <code>
        @skaile/forge-editor/react/styles/advanced.css
      </code>
      
       (token mapping, <code>
        core.css
      </code>
      
      , every feature sheet, <code>
        themes.css
      </code>
      
       and the theme bridge in one import)
    </td>
    
    <td>
      browser (React)
    </td>
  </tr>
  
  <tr>
    <td>
      Framework-free core: <code>
        defineEditor
      </code>
      
      , <code>
        coreContentFeature
      </code>
      
      , <code>
        coreUiFeature
      </code>
      
      , <code>
        createEditorContext
      </code>
      
      , <code>
        command
      </code>
      
      , <code>
        commandState
      </code>
      
      , <code>
        parseBlocks
      </code>
      
      , <code>
        createStore
      </code>
      
      , <code>
        Notifier
      </code>
      
      , extension-point types (<code>
        MenuItem
      </code>
      
      , <code>
        EditorFeature<C>
      </code>
      
      )
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
    </td>
    
    <td>
      browser (no UI framework)
    </td>
  </tr>
  
  <tr>
    <td>
      One feature
    </td>
    
    <td>
      <code>
        <x>FeatureCore(ui)
      </code>
      
      , models and types from <code>
        .../<x>
      </code>
      
      ; the Vue binding <code>
        <x>Feature()
      </code>
      
       and components from <code>
        .../<x>/vue
      </code>
      
      ; the React binding and components from <code>
        .../<x>/react
      </code>
      
      ; <code>
        <x>
      </code>
      
       is <code>
        media
      </code>
      
      , <code>
        mentions
      </code>
      
       (framework-free only), <code>
        transcript
      </code>
      
      , <code>
        authors
      </code>
      
      , <code>
        comments
      </code>
      
      , <code>
        composites
      </code>
      
      , <code>
        ai
      </code>
      
      , <code>
        collab
      </code>
      
      , <code>
        block-ui
      </code>
      
      , <code>
        themes
      </code>
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      Markdown string as the document
    </td>
    
    <td>
      <code>
        splitFrontmatter
      </code>
      
      , <code>
        joinFrontmatter
      </code>
      
      , <code>
        markdownToContent(editor, body, { policy })
      </code>
      
       → <code>
        { content, diagnostics }
      </code>
      
       (raw HTML, unsafe URLs, unknown fences reported; <code>
        OpaqueFence
      </code>
      
       keeps unknown <code>
        ::: kind
      </code>
      
       fences byte for byte), <code>
        contentToMarkdown(editor)
      </code>
      
      , <code>
        MarkdownClipboard
      </code>
      
       (paste/copy as Markdown), <code>
        createSourceMode({ getEditor })
      </code>
      
       (<code>
        state
      </code>
      
      , <code>
        enter
      </code>
      
      , <code>
        edit
      </code>
      
      , <code>
        commit
      </code>
      
       → false and editor untouched on a fatal diagnostic, <code>
        cancel
      </code>
      
      ) from <code>
        .../markdown
      </code>
      
      ; <code>
        MarkdownSurface
      </code>
      
       (<code>
        v-model
      </code>
      
       string, YAML frontmatter kept verbatim, props <code>
        policy
      </code>
      
       and <code>
        sourceMode
      </code>
      
      ) from <code>
        .../markdown/vue
      </code>
      
       (React: <code>
        value
      </code>
      
      /<code>
        onChange
      </code>
      
      /<code>
        onDiagnostics
      </code>
      
      , prop <code>
        policy
      </code>
      
      , no source view, from <code>
        .../markdown/react
      </code>
      
      ); GFM tables and task lists: <code>
        tablesFeature()
      </code>
      
       from <code>
        .../tables
      </code>
      
       (schema <code>
        .../tables/schema
      </code>
      
      , CSS <code>
        .../styles/tables.css
      </code>
      
      )
    </td>
    
    <td>
      browser (<code>
        .../markdown
      </code>
      
      , <code>
        .../tables
      </code>
      
       also headless)
    </td>
  </tr>
  
  <tr>
    <td>
      Edit a code, YAML, JSON or text file
    </td>
    
    <td>
      <code>
        CodeSurface
      </code>
      
       from <code>
        .../code/vue
      </code>
      
       (<code>
        v-model
      </code>
      
      , <code>
        editable
      </code>
      
      , <code>
        language
      </code>
      
      , <code>
        wordWrap
      </code>
      
      , emits <code>
        save
      </code>
      
      , <code>
        ready
      </code>
      
      ) or <code>
        .../code/react
      </code>
      
       (<code>
        value
      </code>
      
      , <code>
        onChange
      </code>
      
      , <code>
        onSave
      </code>
      
      , <code>
        onReady
      </code>
      
      ); framework-free <code>
        createCodeEditor
      </code>
      
      , <code>
        setReadOnly
      </code>
      
      , <code>
        setWordWrap
      </code>
      
      , <code>
        setLanguage
      </code>
      
      , <code>
        loadLanguage
      </code>
      
      , <code>
        setDocument
      </code>
      
      , <code>
        formatJsonInEditor
      </code>
      
      , <code>
        kindOf(path, mime?)
      </code>
      
      , <code>
        languageOf(path)
      </code>
      
       from <code>
        .../code
      </code>
      
      . Language packs are yours: <code>
        registerLanguage('yaml', async () => (await import('@codemirror/lang-yaml')).yaml())
      </code>
      
       once at startup, id from <code>
        languageOf(path)
      </code>
      
      . Theme = <code>
        --sk-*
      </code>
      
       tokens (<code>
        .../styles/tokens.css
      </code>
      
      ). Needs <code>
        @codemirror/{state,view,language,commands,search}
      </code>
      
       and <code>
        @lezer/highlight
      </code>
      
       installed (optional peers); no ProseMirror/TipTap in the bundle
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      One surface for Markdown and code files
    </td>
    
    <td>
      <code>
        DocumentSurface
      </code>
      
       from <code>
        .../document/vue
      </code>
      
       (<code>
        path
      </code>
      
      , <code>
        v-model
      </code>
      
      , <code>
        markdown
      </code>
      
       = props of <code>
        MarkdownSurface
      </code>
      
       incl. <code>
        preset
      </code>
      
      , <code>
        binary
      </code>
      
       slot) or <code>
        .../document/react
      </code>
      
       (<code>
        path
      </code>
      
      , <code>
        value
      </code>
      
      , <code>
        onChange
      </code>
      
      , <code>
        markdown
      </code>
      
      , <code>
        binary(path)
      </code>
      
      ); chooses by <code>
        kindOf(path, mime)
      </code>
      
      ; remount (<code>
        :key
      </code>
      
      /<code>
        key
      </code>
      
       = path) when the path changes. Reaches ProseMirror and CodeMirror both
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      An integration (framework-free, works on both surfaces)
    </td>
    
    <td>
      <code>
        compositeMediaFeature
      </code>
      
      , <code>
        compositeAiFeature
      </code>
      
      , <code>
        transcriptAiFeature
      </code>
      
       from <code>
        .../integrations/composite-media
      </code>
      
      , <code>
        /composite-ai
      </code>
      
      , <code>
        /transcript-ai
      </code>
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      Heading outline, Document tree
    </td>
    
    <td>
      <code>
        EditorOutline
      </code>
      
       from <code>
        .../outline/vue
      </code>
      
       or <code>
        .../outline/react
      </code>
      
       (<code>
        headingOutline
      </code>
      
      , <code>
        revealBlockInEditor
      </code>
      
       from <code>
        .../outline
      </code>
      
      ); <code>
        DocumentTree
      </code>
      
      , <code>
        useTreeView
      </code>
      
       from <code>
        .../tree/vue
      </code>
      
       or <code>
        .../tree/react
      </code>
      
      ; <code>
        DocumentStore
      </code>
      
      , <code>
        createTreeView
      </code>
      
       from <code>
        .../tree
      </code>
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      Settings type, defaults, validation
    </td>
    
    <td>
      <code>
        EditorSettings
      </code>
      
      , <code>
        EDITOR_SETTINGS_DEFAULTS
      </code>
      
      , <code>
        parseEditorSettings
      </code>
      
      , <code>
        editorSettingsSchema
      </code>
      
       from <code>
        .../settings
      </code>
    </td>
    
    <td>
      anywhere
    </td>
  </tr>
  
  <tr>
    <td>
      ProseMirror schema for a server, validator or migration
    </td>
    
    <td>
      <code>
        simpleSchemaExtensions
      </code>
      
       from <code>
        .../schema/simple
      </code>
      
      ; <code>
        advancedSchemaExtensions
      </code>
      
       from <code>
        .../schema/advanced
      </code>
      
      ; per-feature <code>
        .../<name>/schema
      </code>
      
      ; base <code>
        coreSchemaExtensions
      </code>
      
      , <code>
        ROOT_ABILITIES
      </code>
      
      , <code>
        BlockId
      </code>
      
       helpers from <code>
        .../core/schema
      </code>
    </td>
    
    <td>
      framework-free, Node-safe
    </td>
  </tr>
  
  <tr>
    <td>
      Nitro side: register the ports, forget a deleted document
    </td>
    
    <td>
      <code>
        provideEditorServer
      </code>
      
      , <code>
        useEditorServer
      </code>
      
       (<code>
        .forgetDocument
      </code>
      
      , <code>
        .liveContent
      </code>
      
      , <code>
        .enforceRateLimit
      </code>
      
      , <code>
        .resolveModel
      </code>
      
      ) from <code>
        .../server/nitro
      </code>
      
      , <code>
        EditorPorts
      </code>
      
       from <code>
        .../server
      </code>
    </td>
    
    <td>
      Nitro only
    </td>
  </tr>
  
  <tr>
    <td>
      Server without Nitro: collab server, AI models, rate limiter, route handlers, websocket listener
    </td>
    
    <td>
      <code>
        createCollabServer
      </code>
      
      , <code>
        createAiModels
      </code>
      
      , <code>
        createRateLimiter
      </code>
      
       from <code>
        .../server
      </code>
      
      ; <code>
        chatPost
      </code>
      
      , <code>
        usersGet
      </code>
      
      , … and their body schemas from <code>
        .../server/handlers
      </code>
      
      ; <code>
        listenCollab
      </code>
      
       from <code>
        .../server/node
      </code>
    </td>
    
    <td>
      any Node process
    </td>
  </tr>
  
  <tr>
    <td>
      Store documents as JSON files
    </td>
    
    <td>
      <code>
        createJsonAdapter({ dir, authenticate?, authorize?, users? })
      </code>
      
       (an <code>
        EditorPorts
      </code>
      
       bundle) from <code>
        @skaile/forge-editor/adapters/json
      </code>
    </td>
    
    <td>
      Node
    </td>
  </tr>
  
  <tr>
    <td>
      Store documents in SQLite via drizzle (optional peer <code>
        drizzle-orm
      </code>
      
      )
    </td>
    
    <td>
      <code>
        bootstrapEditorTables(db)
      </code>
      
      , <code>
        createDrizzleAdapter({ db, tables: editorTables() })
      </code>
      
       from <code>
        @skaile/forge-editor/adapters/drizzle
      </code>
    </td>
    
    <td>
      Node
    </td>
  </tr>
  
  <tr>
    <td>
      Edit a host's Markdown files
    </td>
    
    <td>
      <code>
        createForgeAdapter({ content, state, schema, authenticate, … })
      </code>
      
       from <code>
        @skaile/forge-editor/adapters/forge
      </code>
    </td>
    
    <td>
      Node
    </td>
  </tr>
  
  <tr>
    <td>
      Mount the editor backend on Nitro (no Nuxt module)
    </td>
    
    <td>
      <code>
        installEditorServer(nitroApp, { ports, collab: {} | false, ai?, rateLimit? })
      </code>
      
       from <code>
        @skaile/forge-editor/server/nitro
      </code>
      
       (comments: <code>
        ports.comments
      </code>
      
      ), called from one Nitro plugin; needs <code>
        experimental: { websocket: true }
      </code>
      
       for <code>
        collab
      </code>
      
      ; peer <code>
        h3
      </code>
    </td>
    
    <td>
      Nitro only
    </td>
  </tr>
  
  <tr>
    <td>
      Bind an editor surface to a document
    </td>
    
    <td>
      <code>
        useEditorDocument(id, { backend?, collaboration?: boolean | { token? }, user?, canComment? })
      </code>
      
       → Vue: <code>
        { modelValue, ready, dirty, save, reload, error, collaboration, comments, editor, bind, dispose }
      </code>
      
       refs from <code>
        @skaile/forge-editor/adapters/vue
      </code>
      
      ; React: the same as plain values plus <code>
        onChange
      </code>
      
       from <code>
        @skaile/forge-editor/adapters/react
      </code>
      
      ; backend defaults to the editor context's (needs <code>
        createHttpBackend()
      </code>
      
       for collaboration and comments)
    </td>
    
    <td>
      browser
    </td>
  </tr>
  
  <tr>
    <td>
      Comment threads that survive edits
    </td>
    
    <td>
      <code>
        captureAnchor
      </code>
      
      /<code>
        resolveAnchor
      </code>
      
      /<code>
        mapAnchor
      </code>
      
       from <code>
        .../anchors
      </code>
      
      ; <code>
        createJsonCommentStore({ file })
      </code>
      
       from <code>
        .../comments/json
      </code>
      
      ; <code>
        createDrizzleCommentStore({ db, tables: commentTables() })
      </code>
      
       from <code>
        .../comments/drizzle
      </code>
      
      ; <code>
        handleCommentsRequest(store, { method, documentId, body })
      </code>
      
       from <code>
        .../comments/server
      </code>
      
      ; the browser side is <code>
        backend.comments(documentId, …)
      </code>
      
       of <code>
        createHttpBackend()
      </code>
      
       from <code>
        .../adapters/http
      </code>
    </td>
    
    <td>
      <code>
        anchors
      </code>
      
      : browser (no UI framework); the others: Node
    </td>
  </tr>
  
  <tr>
    <td>
      Nuxt module (config key <code>
        tiptapEditor
      </code>
      
      )
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/nuxt
      </code>
      
       in <code>
        modules
      </code>
    </td>
    
    <td>
      build
    </td>
  </tr>
  
  <tr>
    <td>
      One config for module, server and client
    </td>
    
    <td>
      <code>
        defineEditorConfig(input)
      </code>
      
      , <code>
        serverConfig(config)
      </code>
      
      , <code>
        publicConfig(config)
      </code>
      
       from <code>
        .../config
      </code>
      
       (defaults once; <code>
        installEditorServer(nitroApp, { ports, ...serverConfig(config) })
      </code>
      
      , <code>
        createEditor({ ...publicConfig(config) })
      </code>
      
      ; the Nuxt module options are its input)
    </td>
    
    <td>
      anywhere
    </td>
  </tr>
  
  <tr>
    <td>
      CSS
    </td>
    
    <td>
      <code>
        .../styles/core.css
      </code>
      
       (required) plus <code>
        /media.css
      </code>
      
      , <code>
        /mentions.css
      </code>
      
      , <code>
        /tables.css
      </code>
      
      , <code>
        /authors.css
      </code>
      
      , <code>
        /comments.css
      </code>
      
      , <code>
        /transcript.css
      </code>
      
      , <code>
        /composites.css
      </code>
      
      , <code>
        /ai.css
      </code>
      
      , <code>
        /collab.css
      </code>
      
      , <code>
        /block-ui.css
      </code>
      
      , <code>
        /themes.css
      </code>
      
       for the features you use
    </td>
    
    <td>
      browser
    </td>
  </tr>
</tbody>
</table>

Rules that follow from this table:

- Import values from the subpath that owns them. The root entry `@skaile/forge-editor` exports types only (`export type`), so `import { createEditor } from '@skaile/forge-editor'` does not compile; use `@skaile/forge-editor/vue` (Vue) or `@skaile/forge-editor/react` (React). `/core` contains no `vue`, `@tiptap/vue-3`, `@nuxt/ui` or React module and no longer exports `createEditor`, `EditorSurface`, `EditorToolbar`, `EditorSettingsPanel`, `EditorSettingsModal`, `SettingsSection`, `useEditorSettings`, `useEditorUi`, `useEditorContext`: those come from `/vue` or `/react`. Feature entries follow the same rule: `/<x>` is framework-free, the components and the `<x>Feature()` binding live in `/<x>/vue` and `/<x>/react`. A React preset is `defineEditor({ features: [coreContentFeature(), coreUiFeature(), mentionsFeature(), ...] })` with factories from `/<x>/react`; features with Vue components are not assignable to it.
- Never import a browser entry from server code, and never import `/server` or `/nuxt` from browser code. Servers use the framework-free `schema`/`protocol`/`types` entries (`/ai/protocol`, `/integrations/transcript-ai/protocol`, `/tree/types`, `/settings`).

## After the change

Check the [invariants](https://skaile-ai.github.io/forge-editor/ai-agents/invariants) and run the [verification commands](https://skaile-ai.github.io/forge-editor/ai-agents/verify).


## Sitemap

See the full [sitemap](https://skaile-ai.github.io/forge-editor/sitemap.md) for all pages.
