# Reading these docs as an agent > Machine entry points of this site (llms.txt, markdown twins, sitemap, installable Agent Skill) and where an agent starts. This site is written for people and for coding agents. Every page has a plain Markdown twin, the whole site is available as one file, and an Agent Skill packages the workflow for tools that support skills. ## Machine entry points
| What | URL |
|---|---|
| Index of every page with a one-line description |
/llms.txt
|
| Every page in one Markdown file |
/llms-full.txt
|
| Markdown twin of a page |
append
.md
to the page URL, or
GET /raw/
, for example
/raw/ai-agents/invariants.md
|
| Sitemap as Markdown |
/sitemap.md
|
| Agent Skill index |
/.well-known/skills/index.json
|
| The skill itself |
/.well-known/skills/ecsplico-editor/SKILL.md
|
| Task | Page |
|---|---|
| Add the editor to an app: pick the entry, the preset, the surface | Integrate the editor |
| Add an own block or an own feature | Add a block or feature |
| Check what must stay true (CSS order, mandatory context, SSR, bundle isolation, entries) | Pitfalls and invariants |
| Prove the change works | Verify |
| Look up an exported name | Public exports |
Look up a feature, its
requires
and its backend
|
Presets and features |
Contribute a custom feature (
EditorFeature
members)
|
Feature contract |
| Host | Surface and entry | Setup |
|---|---|---|
| Nuxt app (editor plus backend) |
AdvancedEditor
from
@skaile/forge-editor/vue/advanced
, module
@skaile/forge-editor/nuxt
,
EditorPorts
in a Nitro plugin
|
Quick start: Nuxt |
| Plain Vue 3 app (Vite), no backend |
SimpleEditor
from
@skaile/forge-editor/vue/simple
,
createEditor()
|
Quick start: Vue |
| React 19 app |
SimpleEditor
from
@skaile/forge-editor/react/simple
inside
EditorContextProvider
;
AdvancedEditor
from
@skaile/forge-editor/react/advanced
|
Quick start: React , Advanced editor in React |
| Framework-free (headless, server, validator) |
/core
, the
entries without
/vue
or
/react
,
schema/*
,
/server
|
Public exports |
| You need | Import | Side |
|---|---|---|
| A ready simple editor component |
SimpleEditor
from
@skaile/forge-editor/vue/simple
|
browser |
| A ready advanced editor component |
AdvancedEditor
from
@skaile/forge-editor/vue/advanced
|
browser |
A preset to pass to
EditorSurface
,
EditorToolbar
,
EditorSettingsPanel
|
simpleEditor
from
.../presets/compose
(framework-free, no ⌘K palette),
advancedEditor
/
composeEditor
from
.../vue/advanced
or
.../react/advanced
(the framework-free assembly behind them is
.../presets/compose
:
composeEditor(ui, options)
,
CONTENT
,
INTERACTION
,
AI
)
|
browser |
Vue chrome:
createEditor
(mandatory Vue app context),
EditorSurface
,
EditorToolbar
,
EditorSettingsPanel
,
EditorSettingsModal
,
EditorCommandPalette
(⌘K palette, the
core-ui
overlay),
SettingsSection
,
useEditorSettings
,
useEditorUi
|
@skaile/forge-editor/vue
|
browser (Vue) |
React chrome:
EditorContextProvider
(mandatory React context from
createEditorContext()
),
EditorSurface
,
EditorToolbar
,
EditorSettingsPanel
,
EditorSettingsModal
,
EditorCommandPalette
(⌘K palette, the
core-ui
overlay),
SettingsSection
,
useEditorSettings
,
useEditorUi
,
Toaster
,
reactNotifier
|
@skaile/forge-editor/react
|
browser (React) |
| A ready simple editor component for React |
SimpleEditor
from
@skaile/forge-editor/react/simple
|
browser (React) |
| A ready advanced editor component for React |
AdvancedEditor
,
advancedEditor
from
@skaile/forge-editor/react/advanced
(needs
EditorContextProvider
and
Toaster
)
|
browser (React) |
| shadcn token mapping for the feature CSS (React hosts) |
@skaile/forge-editor/react/styles/ui-vars.css
; for the advanced editor
@skaile/forge-editor/react/styles/advanced.css
(token mapping,
core.css
, every feature sheet,
themes.css
and the theme bridge in one import)
|
browser (React) |
Framework-free core:
defineEditor
,
coreContentFeature
,
coreUiFeature
,
createEditorContext
,
command
,
commandState
,
parseBlocks
,
createStore
,
Notifier
, extension-point types (
MenuItem
,
EditorFeature
)
|
@skaile/forge-editor/core
|
browser (no UI framework) |
| One feature |
, models and types from
.../
; the Vue binding
and components from
.../
; the React binding and components from
.../
;
is
media
,
mentions
(framework-free only),
transcript
,
authors
,
comments
,
composites
,
ai
,
collab
,
block-ui
,
themes
|
browser |
| Markdown string as the document |
splitFrontmatter
,
joinFrontmatter
,
markdownToContent(editor, body, { policy })
→
{ content, diagnostics }
(raw HTML, unsafe URLs, unknown fences reported;
OpaqueFence
keeps unknown
::: kind
fences byte for byte),
contentToMarkdown(editor)
,
MarkdownClipboard
(paste/copy as Markdown),
createSourceMode({ getEditor })
(
state
,
enter
,
edit
,
commit
→ false and editor untouched on a fatal diagnostic,
cancel
) from
.../markdown
;
MarkdownSurface
(
v-model
string, YAML frontmatter kept verbatim, props
policy
and
sourceMode
) from
.../markdown/vue
(React:
value
/
onChange
/
onDiagnostics
, prop
policy
, no source view, from
.../markdown/react
); GFM tables and task lists:
tablesFeature()
from
.../tables
(schema
.../tables/schema
, CSS
.../styles/tables.css
)
|
browser (
.../markdown
,
.../tables
also headless)
|
| Edit a code, YAML, JSON or text file |
CodeSurface
from
.../code/vue
(
v-model
,
editable
,
language
,
wordWrap
, emits
save
,
ready
) or
.../code/react
(
value
,
onChange
,
onSave
,
onReady
); framework-free
createCodeEditor
,
setReadOnly
,
setWordWrap
,
setLanguage
,
loadLanguage
,
setDocument
,
formatJsonInEditor
,
kindOf(path, mime?)
,
languageOf(path)
from
.../code
. Language packs are yours:
registerLanguage('yaml', async () => (await import('@codemirror/lang-yaml')).yaml())
once at startup, id from
languageOf(path)
. Theme =
--sk-*
tokens (
.../styles/tokens.css
). Needs
@codemirror/{state,view,language,commands,search}
and
@lezer/highlight
installed (optional peers); no ProseMirror/TipTap in the bundle
|
browser |
| One surface for Markdown and code files |
DocumentSurface
from
.../document/vue
(
path
,
v-model
,
markdown
= props of
MarkdownSurface
incl.
preset
,
binary
slot) or
.../document/react
(
path
,
value
,
onChange
,
markdown
,
binary(path)
); chooses by
kindOf(path, mime)
; remount (
:key
/
key
= path) when the path changes. Reaches ProseMirror and CodeMirror both
|
browser |
| An integration (framework-free, works on both surfaces) |
compositeMediaFeature
,
compositeAiFeature
,
transcriptAiFeature
from
.../integrations/composite-media
,
/composite-ai
,
/transcript-ai
|
browser |
| Heading outline, Document tree |
EditorOutline
from
.../outline/vue
or
.../outline/react
(
headingOutline
,
revealBlockInEditor
from
.../outline
);
DocumentTree
,
useTreeView
from
.../tree/vue
or
.../tree/react
;
DocumentStore
,
createTreeView
from
.../tree
|
browser |
| Settings type, defaults, validation |
EditorSettings
,
EDITOR_SETTINGS_DEFAULTS
,
parseEditorSettings
,
editorSettingsSchema
from
.../settings
|
anywhere |
| ProseMirror schema for a server, validator or migration |
simpleSchemaExtensions
from
.../schema/simple
;
advancedSchemaExtensions
from
.../schema/advanced
; per-feature
.../
; base
coreSchemaExtensions
,
ROOT_ABILITIES
,
BlockId
helpers from
.../core/schema
|
framework-free, Node-safe |
| Nitro side: register the ports, forget a deleted document |
provideEditorServer
,
useEditorServer
(
.forgetDocument
,
.liveContent
,
.enforceRateLimit
,
.resolveModel
) from
.../server/nitro
,
EditorPorts
from
.../server
|
Nitro only |
| Server without Nitro: collab server, AI models, rate limiter, route handlers, websocket listener |
createCollabServer
,
createAiModels
,
createRateLimiter
from
.../server
;
chatPost
,
usersGet
, … and their body schemas from
.../server/handlers
;
listenCollab
from
.../server/node
|
any Node process |
| Store documents as JSON files |
createJsonAdapter({ dir, authenticate?, authorize?, users? })
(an
EditorPorts
bundle) from
@skaile/forge-editor/adapters/json
|
Node |
Store documents in SQLite via drizzle (optional peer
drizzle-orm
)
|
bootstrapEditorTables(db)
,
createDrizzleAdapter({ db, tables: editorTables() })
from
@skaile/forge-editor/adapters/drizzle
|
Node |
| Edit a host's Markdown files |
createForgeAdapter({ content, state, schema, authenticate, … })
from
@skaile/forge-editor/adapters/forge
|
Node |
| Mount the editor backend on Nitro (no Nuxt module) |
installEditorServer(nitroApp, { ports, collab: {} | false, ai?, rateLimit? })
from
@skaile/forge-editor/server/nitro
(comments:
ports.comments
), called from one Nitro plugin; needs
experimental: { websocket: true }
for
collab
; peer
h3
|
Nitro only |
| Bind an editor surface to a document |
useEditorDocument(id, { backend?, collaboration?: boolean | { token? }, user?, canComment? })
→ Vue:
{ modelValue, ready, dirty, save, reload, error, collaboration, comments, editor, bind, dispose }
refs from
@skaile/forge-editor/adapters/vue
; React: the same as plain values plus
onChange
from
@skaile/forge-editor/adapters/react
; backend defaults to the editor context's (needs
createHttpBackend()
for collaboration and comments)
|
browser |
| Comment threads that survive edits |
captureAnchor
/
resolveAnchor
/
mapAnchor
from
.../anchors
;
createJsonCommentStore({ file })
from
.../comments/json
;
createDrizzleCommentStore({ db, tables: commentTables() })
from
.../comments/drizzle
;
handleCommentsRequest(store, { method, documentId, body })
from
.../comments/server
; the browser side is
backend.comments(documentId, …)
of
createHttpBackend()
from
.../adapters/http
|
anchors
: browser (no UI framework); the others: Node
|
Nuxt module (config key
tiptapEditor
)
|
@skaile/forge-editor/nuxt
in
modules
|
build |
| One config for module, server and client |
defineEditorConfig(input)
,
serverConfig(config)
,
publicConfig(config)
from
.../config
(defaults once;
installEditorServer(nitroApp, { ports, ...serverConfig(config) })
,
createEditor({ ...publicConfig(config) })
; the Nuxt module options are its input)
|
anywhere |
| CSS |
.../styles/core.css
(required) plus
/media.css
,
/mentions.css
,
/tables.css
,
/authors.css
,
/comments.css
,
/transcript.css
,
/composites.css
,
/ai.css
,
/collab.css
,
/block-ui.css
,
/themes.css
for the features you use
|
browser |
| Track | Pages |
|---|---|
| Basics: what a document is made of, how it is structured, stored and acted on | Flat & Structure , Content blocks , JSON & Markdown , Acting on blocks , Editor settings |
| Building blocks: one API of the library, shown on its own | Simple , Advanced , Surface |
| Use cases: a planned application, built from the framework | Minutes , Slides , Databases , Science , Podcast , PKM , Epikrise |
| Feature | Where to see it |
|---|---|
Collaboration (
collaboration
prop, Hocuspocus session)
|
app/pages/documents/[id].vue
,
Collaboration
|
Comments and authors (
CommentsMargin
,
v-model:comments-open
)
|
the same document page, Authors and comments |
Explore and search (
explore
,
ExplorePanel
,
SearchPanel
)
|
app/layouts/default.vue
,
Explore
|
Templates (
templatesOf
,
TEMPLATES_FOLDER
)
|
app/pages/documents/index.vue
,
Templates
|
Themes (
appearance.theme
, the Theme tab)
|
the settings popup of any page, Themes |
The editor-owned settings modal (
settings-ui="internal"
, the default; the kitchen sink places its settings itself with
settings-ui="external"
)
|
the document page,
Settings
; the settings object itself (
useEditorSettings
,
EDITOR_SETTINGS_DEFAULTS
,
EditorSettingsPanel
) has its own page,
Editor settings
|
UI kit (
createEditor({ kit })
) and the module options
|
Nuxt module |
| Export check | Export check |
| Obsidian vaults, image studio, graph, Typst | Obsidian , Image studio , Graph , Typst |
| Part | File |
|---|---|
Collaborative page:
AdvancedEditor
with a
HocuspocusProvider
session, toolbar and
AiSidebar
placed by the page, editor-owned settings modal (
settingsUi
default
'internal'
), a „Text | Tabelle“ switch to
CompositeTable
(a row returns to the text and reveals its Typed block) and a docked
CompositeInspector
with the page's own Document facts in its
document
slot (
DocumentProperties.vue
)
|
app/pages/documents/[id].vue
|
The fifteen pages: one Vue file each with its own editor,
v-model
content, panel and the source its „How it's built“ drawer shows
|
app/pages/kitchen-sink/
:
structure.vue
,
blocks.vue
,
json-markdown.vue
,
actions.vue
,
settings.vue
,
simple.vue
,
advanced.vue
,
surface.vue
,
minutes.vue
,
slides.vue
,
databases.vue
,
science.vue
,
podcast.vue
,
pkm.vue
,
epikrise.vue
;
index.vue
is the gallery
|
| Page registry: slug, track, title, tagline, icon, accent, lessons and docs anchor of every page, read by the gallery, the layout's navigation and each page |
app/editor/kitchen-sink/pages.ts
|
Shared page shell: header (sample select, toolbar, switches, settings, AI), the
panel
,
actions
and
sidebar
slots, the settings popup and the „How it's built“ drawer
|
app/components/kitchen-sink/KitchenSinkPage.vue
|
| Card for a capability that needs a server port or add-on flag this run lacks |
app/components/kitchen-sink/ServerHint.vue
|
Pane state (
createPane
,
loadSample
,
showSettings
,
refreshMarkdown
) and the editor callbacks the pages share (
paneReady
,
paneUpdated
)
|
app/editor/kitchen-sink/pane.ts
|
Demo documents, one file per page, with the builders they share (
typed
,
heading
,
bullets
,
withId
for fixed block ids, …) and the Markdown for „Insert Markdown“ and „Load Markdown“
|
app/editor/kitchen-sink/samples/
:
helpers.ts
(with
quote
and
codeBlock
for the block tour) and
, among them
structure.ts
(one brief, flat and structured),
blocks.ts
(the block tour) and
json-markdown.ts
(a release note as JSON and as Markdown, a lossy and an invalid document); the round-trip comparison of the JSON & Markdown page is
app/editor/kitchen-sink/round-trip.ts
; assets
public/demo/diagramm.svg
and
protokoll.txt
|
The host's
decision
Block type, used by Content blocks, Minutes and Advanced
|
app/editor/kitchen-sink/decision.ts
|
| Layout of the kitchen sink: navigation built from the registry, back to „Dokumente“, links to the standalone examples, and the English copy of the editor context |
app/layouts/kitchen-sink.vue
|
| Accent colours, gallery and page-enter animations |
app/assets/css/kitchen-sink.css
|
The own block as a feature: node, node view, styles, feature (toolbar,
/
, hover menu, conversion) and conversion provider; walked through in the
tutorial
|
app/editor/callout/
:
node.ts
,
CalloutView.vue
,
index.ts
,
callout.css
,
feature.ts
,
convert.ts
|
| The Epikrise domain: Block types as data (properties, AI brief) and the host feature that supplies example paragraphs |
app/editor/epikrise/kinds.ts
,
feature.ts
|
Module registration (
@skaile/forge-editor/nuxt
)
|
nuxt.config.ts
|
Ports plugin:
provideEditorServer
with sessions, document store, Yjs state, assets and per-user settings
|
server/plugins/editor-adapter.ts
|
| Store adapter: documents, Yjs state, assets, settings, users on the file system |
server/utils/documents.ts
,
state.ts
,
assets.ts
,
settings.ts
,
users.ts
|
Showcase seeded into a fresh store: fixed document and block ids (so the documents can reference, embed and collect each other), one module per document, and the seeding step of
ensureStore
|
shared/showcase/
(
ids.ts
,
build.ts
,
index.ts
, one
per document),
server/utils/showcase.ts
,
server/utils/store-root.ts
|
File drawer:
DocumentTree
over the host's
DocumentStore
(routes,
$fetch
, toasts, delete-with-undo), selected folder held by the layout
|
app/layouts/default.vue
,
app/components/AppDocumentTree.vue
,
app/composables/useDocumentStore.ts
(the
.cdoc
export button comes in through the
document-actions
slot; the format stays in the host)
|
| Endpoint | Purpose |
|---|---|
GET /api/ai/models
|
{ presets: ModelProfile[], roles: Record
— the server Model presets as Model profiles (no keys) and the default Model preset per Model role (
complete
,
rewrite
,
generate
)
|
POST /api/ai/generate
|
SSE (
delta
/
done
/
error
) for selection tasks and block generation
|
POST /api/ai/chat
|
SSE for the sidebar's document chat with edit operations |
POST /api/ai/complete
|
{ text }
continuation for ghost autocomplete
|
Factory (
@skaile/forge-editor/integrations/…
)
|
requires
|
Contributes |
|---|---|---|
composite-ai
→
compositeAiFeature()
|
composites
,
ai
,
media
|
block actions „Block füllen (KI)“ (Block types with the
ai-brief
capability), „Zusammenfassung erzeugen (KI)“, “Create readable rendition” (English label), „Neu erzeugen (ersetzen)“, „Ableiten (KI)“, „Literaturangaben abrufen“, „Mit KI in Unterblöcke teilen“ / „Mit KI in Blöcke teilen“ and „Gliederung bereinigen (KI)“ (also a ⌘K command); the single
formatAiResult
|
transcript-ai
→
transcriptAiFeature()
|
transcript
,
ai
|
block action „Transkript bereinigen (KI)“ and the same row in the AI selection menu |