Blocks and references
The page editor (PageEditor) is built on TipTap with a custom set of extensions. This page lists every block type you can insert, plus the full reference syntax for embedding live links to other workspace entities.
Block types
Open the slash-command menu by typing / at the start of a line. The menu groups blocks into four categories.
Text
| Block | How to insert | Description |
|---|---|---|
| Heading 1 | /h1 | Large section heading (#). |
| Heading 2 | /h2 | Medium section heading (##). |
| Heading 3 | /h3 | Small section heading (###). |
| Paragraph | Default | Plain text. Supports bold (**), italic (*), inline code (`), and hyperlinks. |
| Link | /link | Wraps selected text in a hyperlink. Also auto-links URLs as you type. |
The editor supports heading levels 1–3 only. Heading levels 4–6 are not available in the slash menu.
Lists
| Block | How to insert | Description |
|---|---|---|
| Bullet List | /bullet | Unordered list. Each item is a listItem node. |
| Numbered List | /ordered | Ordered list. Items are numbered sequentially. |
| Task List | /task | Checkbox list. Each item has a checked/unchecked state. Task list items are taskItem nodes. |
Blocks
| Block | How to insert | Description |
|---|---|---|
| Info Callout | /callout-info | Blue-tinted callout for informational notes. |
| Warning Callout | /callout-warning | Amber-tinted callout for cautions. |
| Success Callout | /callout-success | Green-tinted callout for confirmations. |
| Error Callout | /callout-error | Red-tinted callout for errors or blockers. |
| Code Block | /code | Syntax-highlighted code block powered by the OnnieCodeBlock extension (lowlight). Supports Tab indentation inside the block. |
Callout blocks (calloutBlock) can contain any block content — paragraphs, lists, even nested callouts.
Media and layout
| Block | How to insert | Description |
|---|---|---|
| Image | /image | Embeds an image by URL. No file upload from the editor yet — you paste a URL when prompted. |
| Two Columns | /columns | Side-by-side TwoColumnLayout with two ColumnBlock children. Each column accepts block content. |
| Divider | /divider | Horizontal rule (---). |
Image insertion from the editor currently accepts only external URLs. File upload will be wired to the storage module in a future release.
Inline references
Any text surface in a page body accepts inline references. Type @ at a word boundary — a search picker opens. Select any entity from your workspace and a reference pill is inserted.
The serialized wire format is:
[Display Name](ref:entity_type:uuid)
[Display Name](ref:entity_type:uuid/alias_id)
The alias_id tail is included when the entity has one (most workspace entities do). It is a 12-char base64 token auto-generated from the UUID by the set_alias_id() Postgres trigger — for example NWY5YjJhMDE_. It is not a human-readable slug; never write references like (ref:table:uuid/contacts).
Examples of valid reference syntax:
[Contacts](ref:table:5f9b2a01-9c4d-4b78-9e7f-3a8c1d6b0e2a/NWY5YjJhMDE_)
[Superagent](ref:engine_bot:00000000-0000-0000-0000-000000000001/TXkgQm90XzA_)
[Q2 Planning](ref:page:7a1c3d4e-2b6f-4a8c-9d1e-0c5b7f3a2e1d/N2ExYzNkNGU_)
[Sprint tasks](ref:task:9c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f)
Supported entity types
The reference picker searches across all of these entity types:
entity_type | What it points to |
|---|---|
table | A workspace table (Tables module). |
page | A page or subpage. |
folder | An organisational folder in the page tree. |
routine | A scheduled automation. |
function | A workspace-defined TypeScript function (Function Routines). |
task | A task from the Tasks module (engine_tasks). |
record | A single row inside a table. |
project | A project. |
user | A workspace member. |
team | A workspace team. |
engine_bot | A custom or built-in bot (Superagent or any Onnie AI bot). |
skill | A saved skill document. |
variable | A workspace-scoped variable. |
The entity type for bots is engine_bot, not bot. Using (ref:bot:...) produces a broken reference — the parser accepts it but the renderer has no icon mapping for bot and the pill shows a fallback icon with no navigation target.
Reference rendering
At read time, each [label](ref:entity_type:uuid/alias_id) token is parsed back into a TipTap reference inline node and rendered by ReferenceNodeView as a ReferenceBadge.
The badge is an inline pill: a small icon on the left, the entity name truncated to 14 characters, styled with a type-specific background tint. Example colors by type:
engine_bot— emerald tint with a Bot icon.table— indigo tint with a Table icon.page— green tint with a FileText icon.skill— sky tint with a BookOpen icon.routine— violet tint with a Workflow icon.function— amber tint with a FunctionSquare icon.user/team— slate tint with a User / Users icon.
For entity types that have panels (skill, routine, engine_bot, table, page, folder), the pill is clickable. Clicking opens the entity's workspace panel via openPanel. For entity types without panels (user, team, task, project, variable, record), the pill is display-only.
The display_name in the pill is the label stored at insert time. It is not automatically updated if you rename the entity after inserting the reference. The UUID in the link target (id) always points at the correct row.
Broken references
If the entity a reference points to is deleted, the pill still renders using the last-known display_name and entity_type from the stored JSON. The badge will show the stored label with the type-specific styling, but clicking it will open a panel that shows "Not found."
There is no automatic cleanup of stale references when an entity is deleted. If you need to remove or update stale pills, edit the page and delete or re-insert the reference.