---
title: Whiteboard (bundled plugin)
---

# Whiteboard (bundled plugin)

## What it is

> **Status: bundled plugin, off by default.** Whiteboard ships inside Omniscio but
> starts switched off. Turn it on at **Settings → Plugins → Whiteboard**. It used to be
> an in-development core feature behind Settings → Features; that toggle
> (`whiteboardEnabled`) and the `AMC_SHOW_WHITEBOARD` env var are gone.

A freeform **whiteboard** — an infinite sketch-and-diagram canvas powered by
[Excalidraw](https://excalidraw.com) (the hand-drawn-style drawing tool). It is a
standalone tool, separate from your coding sessions: you create a library of boards,
draw on them, and they autosave.

The headline is the **AI glue**: an Omniscio agent can **read a board and draw on it for
you** through Omniscio's local control server, and your open canvas **updates live** as
the agent draws.

Excalidraw is **MIT-licensed and fully self-hosted** in Omniscio — no watermark, no
license key, no per-seat cost, and it works completely offline.

## Where to find it

- **Enable it once** at Settings → Plugins → Whiteboard. It then appears as its own
  sidebar row.
- Open it from that **sidebar row**. The canvas fills the main panel with the usual
  Sessions pane beside it. Unlike the old core version there is no separate full-screen
  mode and no shared dock with Mind Map: it is a plugin panel like any other, so opening
  it no longer closes anything else.
- **On a phone** the same panel opens through the plugin's row — the island's own layout
  is responsive, so the boards library is a drawer at the top of the canvas on both form
  factors instead of diverging between them.
- **Opening Whiteboard drops you straight onto a canvas** — it reopens your most-recent
  board, or starts a fresh blank one if you have none yet, so you never land on an empty
  "pick a board" screen.
- Every board **autosaves** a moment after you stop drawing — there is no Save button.
- Create a board with **New** in the boards drawer; delete from the same list.
- **Rename a board.** The open board's name is shown at the top of the canvas. Click or
  double-click the name (or press **Rename** beside it), type the new name, and press
  **Enter** — or just click away — to save; **Escape** cancels. In the boards drawer you can
  also double-click a board's name, or use its **Rename** button. An empty name, or the same
  name, saves nothing, and one edit is only ever saved once.
- **The new name shows immediately.** If saving it fails (or the board was deleted
  meanwhile), the old name comes back and a short message explains what happened, with a
  **Dismiss** button. Renaming never discards a stroke that was still being saved.

## How it behaves

### Drawing

The canvas **is** Excalidraw, so everything Excalidraw does works here: rectangles,
ellipses, arrows, lines, freehand draw, text, images, selection, grouping, pan/zoom,
copy-paste, undo/redo, and its own right-click menu and shortcuts. Fonts are bundled
locally so text renders identically offline (CJK glyphs fall back to a system font).

### Linking a board to a task

A strip above the canvas shows which of your tasks this board is linked to, and lets you
attach it to another. Search a task by name and pick it; the chip that appears links back
to that item on your Mission Control board, and its **×** unlinks.

Two things follow from Whiteboard being a plugin rather than core code:

- **You choose which boards it can see.** Task boards are default-deny — the first search
  finds nothing until you share a board with the plugin, and the empty state offers a
  **Share a board** button that does exactly that.
- **It can only ever attach itself.** The plugin cannot create a link that claims to be
  one of your notes or sessions, and it cannot detach a link some other surface made,
  because Omniscio decides what kind of thing the plugin is writing rather than taking
  the plugin's word for it.

If you decline the plugin's board permission, the whole strip is hidden rather than
shown-and-broken.

### AI sessions

The Sessions pane beside the canvas is the full Omniscio session experience for agents
working on the open board. A new session there is seeded with the board's id and the
read/draw protocol, so you can just say what you want drawn. These sessions live in the
plugin's own project.

### Letting an AI agent draw on a board

This is the point of the feature. Any Omniscio-spawned agent that can reach the local
**control server** can list your boards, read the full contents of one (every shape, as
data), create a board, draw on one (replace its scene), rename, or delete it.

When the agent draws, your **open canvas reloads live** so the drawing appears in front
of you — you can watch the agent work.

For agents doing read-modify-write, the write carries an **expected version**; if someone
(usually you) changed the board in between, the write is rejected with a **version
conflict** so the agent re-reads instead of clobbering your change.

### Your existing boards

If you used the whiteboard before it became a plugin, your boards are **copied** into the
plugin the first time Omniscio starts after the update, and the plugin is switched on for
you. The copy is verified board-by-board before it counts as done, and the original data
is never written to or deleted — it stays as a safety net. A failed copy simply retries
on the next launch.

### Limitations / known issues

- **Off by default** — the plugin ships with the app but must be switched on.
- **The AI draws by sending shapes** — a Mermaid-diagram shortcut is a planned
  fast-follow.
- **No CJK fonts bundled** — Chinese/Japanese/Korean text falls back to a system font.
- **One board reloads live; a non-open board only refreshes in the list.**
- **No global keyboard shortcut** — the old `newWhiteboard` action is gone with the core
  feature.

## For agents

### How it works (internals)

- **Plugin folder:** `src/plugins/whiteboard/` — the manifest, a worker `backend/`, and a
  Vite/React island under `web/` whose committed build output is `ui/`. The island owns
  Excalidraw; the backend owns storage and the CLI actions.
- **Data model:** a `plugin_whiteboard_boards` collection (title, a JSON `elements` blob =
  exactly Excalidraw's `getSceneElements()`, an optional `app_state` blob, a monotonic
  `version` counter, timestamps). Plugin collections are real SQLite tables created at
  enable time, so this one does not exist on an install that never switched the plugin on.
- **Concurrency:** `expectedVersion` is enforced in the backend as read-check-write, with
  writes serialised per board. Plugin storage has no compare-and-swap update, so without
  the serialisation two saves could both read the same version and the second would
  silently destroy the first.
- **Backup, restore and erasure:** the plugin's table is registered in the data-transfer
  table list, the all-table merge strategy, and the privacy erasure registry alongside the
  legacy `whiteboards` table. Plugin storage is not covered by any of those by default, so
  omitting it would have silently dropped every board drawn since the migration out of
  backups.
- **CLI (the AI glue):** six actions under `/plugins/whiteboard/cli/` — `boards`
  (GET/POST) and `board` (GET/PUT/PATCH/DELETE). Plugin CLI paths are matched **exactly**,
  so a board id travels as `?id=` or in the body, never as a path segment. They answer only
  while the plugin is enabled and its worker is running (`409` otherwise).
- **Task links:** the island calls the host's `boardLinks` bridge namespace, gated by the
  `boards.link` permission (which requires a `boards.read` sibling in the same manifest).
  The entity type is derived from the calling plugin's id rather than sent, and the target
  item must sit on a board the user granted.
- **Self-hosted Excalidraw:** fonts ship inside the island's own bundle and
  `excalidraw-asset-path.ts` points Excalidraw at them, so the canvas works offline and
  inside the plugin content-security policy. The island's Vite config emits the font
  worker as a same-origin module chunk (`worker.format: 'iife'`, `assetsInlineLimit: 0`)
  rather than a `blob:` worker — the plugin CSP has no `worker-src`, so a blob worker
  would be blocked. This is why the plugin needs no CSP widening even though the old core
  renderer did.

## Related

- [plugin-marketplace.md](plugin-marketplace.md) — how bundled and installed plugins work.
- [plugin-bridge-capabilities.md](plugin-bridge-capabilities.md) — what a plugin can ask
  the host to do, including the board and board-link brokers.
- [session-provenance.md](session-provenance.md) — how an agent's actions through the
  control server trace back to the session that made them.
- Developer reference (invariants + the tests that lock them):
  `.claude/memory/contracts/whiteboard-contract.md`.
