Plota docs

9. The AI copilot

The right rail → Copilot tab, the toolbar AI button, Ctrl/⌘ I for the inline command bar, or any AI: command in the palette.

The Copilot tab: Ask the copilot, Explain this layout, Improve this diagram and Model settings
The Copilot tab: Ask the copilot, Explain this layout, Improve this diagram and Model settings

What works with no model at all#

Most of it. Every one of these is a pure function over the document with no network call and no download:

ActionWhat it does
AI: check this diagram for problemsFourteen rule-based checks. Each finding carries the op plan that fixes it
AI: preview every mechanical fixTurns all the fixable findings into one plan
AI: build a diagram from clipboard textAn outline, prose with arrows, meeting notes or code → a laid-out diagram
AI: connect the selection to a related shapeRanks candidates by topology and label meaning
AI: group semantically related shapesFinds a cluster and wraps it in a container
AI: merge duplicate shapesNear-identical labels
AI labels: …Consistent case, Title Case, Sentence case, strip punctuation, shorten, shorten-to-fit, unify terminology
AI: actions for the selected shapeThe two or three contextual actions worth offering
Tidy layoutRearranges the whole diagram for readability, as one undo step

The fourteen are: dangling-edge, overlap, inconsistent-size, near-miss-alignment, crossing-connectors, missing-branch, unlabelled-branch, shape-contradicts-text, label-punctuation, inconsistent-case, inconsistent-terminology, duplicate-label, low-contrast (WCAG below 4.5:1) and orphan. A fifteenth, model-wording, appears only when a model is connected. duplicate-label and orphan are advisory — they carry no automatic fix, because a human has to decide.

Nothing is applied behind your back. Everything produces a proposal: the canvas shows a ghost preview of the diff, the panel lists one line per operation, and you press Apply. An applied plan is a single undo entry, and AI: undo the last applied plan reverses it.

Explain this layout, and improve it#

Explain this layout (a section of the Copilot tab, or ask the copilot “explain this layout”) scores how readable the current page is — lower is better — and says in words what costs the most: connectors crossing or running against the reading direction, connectors riding along a frame's border, frames out of reading order, empty space, and so on.

Under the explanation are the actions that can lower the score:

  • Tidy — rearranges the page;
  • Apply critique fixes — the mechanical fixes from the diagram check;
  • Split into overview + details — offered for a large sectioned chart (see Large charts).

Ask “improve the layout” and the copilot proposes the best of these as a plan; its note gives the score before and after. As with everything here, nothing changes until you press Apply, and the change is one undo step. The same score is what plota critique and the MCP server's review_diagram report.

The AI panel#

The left panel's AI tab holds the optional in-browser models — the small embedding model used for search by meaning, and a local language model — plus semantic search, connection suggestions, the diagram check, Tidy and text-to-diagram.

The AI panel: model loading, semantic search, suggestions, diagram check, Tidy layout and Generate
The AI panel: model loading, semantic search, suggestions, diagram check, Tidy layout and Generate

Providers#

AI: model settings (or the panel's settings section) offers four:

ProviderWhat it is
noneNo model. The deterministic router runs alone — the default
ollamaThe Ollama daemon on this machine. Nothing leaves the device
openai-compatibleAny /v1/chat/completions server: LM Studio, llama.cpp, vLLM, LiteLLM
webllmIn-browser WebGPU. Needs a one-off ~1.5 GB download; stubbed out in the single-file build

Settings live in localStorage under plota.ai.provider and are swappable at runtime — the next request uses the new provider, with no reload.

Whatever the model returns is validated against the op schema before it is shown to you. An invalid plan is fed back to the model with its errors; if that fails too, the deterministic router answers instead. A model can therefore produce a wrong-but-valid diagram, but never a corrupt one.

Setting up Ollama#

ollama serve                 # start the daemon
ollama pull llama3.2         # get a model
curl http://localhost:11434/api/tags   # confirm it answers

Then open the editor at https://editor.plota.live and use AI: detect a local Ollama daemon (or the Detect button in the panel). The Ollama API remains local at http://localhost:11434 when the daemon runs on your computer; the browser origin that must be allowed is the editor's URL.

The CORS problem — read this one#

Symptom: curl http://localhost:11434/api/tags works perfectly, but the editor says it cannot reach Ollama.

Cause: Ollama only sends an Access-Control-Allow-Origin header for origins listed in OLLAMA_ORIGINS. A browser page served from https://editor.plota.live is not on that list by default, so the browser blocks the response. curl does not enforce CORS, which is exactly why it looks like the daemon is fine.

Fix — restart Ollama with your editor's origin allowed:

macOS (menu-bar app):

  launchctl setenv OLLAMA_ORIGINS "https://editor.plota.live"
# then quit Ollama from the menu bar and start it again

macOS / Linux, running it yourself:

OLLAMA_ORIGINS="https://editor.plota.live" ollama serve

Linux (systemd):

sudo systemctl edit ollama.service
# add:
#   [Service]
#   Environment="OLLAMA_ORIGINS=https://editor.plota.live"
sudo systemctl daemon-reload && sudo systemctl restart ollama

Windows (PowerShell):

setx OLLAMA_ORIGINS "https://editor.plota.live"
# then quit Ollama from the system tray and start it again

OLLAMA_ORIGINS="*" allows every origin. Convenient while you try this out, but it lets any page you visit talk to your models — prefer the exact origin.

Use whatever origin the browser address bar shows. For the hosted editor that is https://editor.plota.live; the panel prints the exact line to copy, so you should not have to work it out.

The app does not make you diagnose this yourself. A browser reports "refused the connection" and "answered, but CORS blocked me" as the same opaque TypeError: Failed to fetch, so the panel re-probes with mode: 'no-cors': an opaque response proves the daemon is up and the real problem is OLLAMA_ORIGINS. Failures are classified as cors, offline, mixed-content, timeout, not-found, unauthorized or http, and each one prints copy-pasteable remediation for the platform you are on.

Other Ollama notes#

  • The base URL is host and port only — http://localhost:11434, no /api, no /v1.
  • An HTTPS page can call http://localhost:11434. Loopback addresses are "potentially trustworthy" origins, so this is not mixed content and the browser does not block it — which is why OLLAMA_ORIGINS above is the whole fix. Mixed content only bites when the daemon is on another host over plain HTTP, such as http://192.168.1.5:11434; put TLS in front of that one.
  • Since Chrome 142 a public site needs permission before it may reach your local network. If the origin is allowed and it still will not connect, look for that prompt — dismissing it fails the request silently.
  • Daemons at 0.5.0 and newer are sent a JSON schema for the op plan, so the plan is validated server-side as well; older builds get format: 'json'.

Embeddings#

Semantic search, connection suggestions and duplicate detection use transformers.js with Xenova/all-MiniLM-L6-v2 (~23 MB, cached after the first load, CPU/WASM, no GPU needed). Offline, or with the CDN blocked, they fall back to lexical similarity and say so — search, suggestions and lint all still work, just less semantically. The single-file build always runs the lexical path.

The command contract#

Every AI action is a command in the palette (Ctrl/⌘ K, type AI). The same actions are available to AI agents through the Plota MCP server — see Plota in Claude and other AI agents.

Everything in Plota runs in your browser — no account, no server, no telemetry.