Addons
Sandboxed React mini-apps that extend your workspace — concept and security model.
An addon is a small React app that you write and that runs inside your
workspace — full-screen at /addons/{id}, or embedded as a block in any
document. It's how you add custom UI and workflows to Dalea without shipping a
separate application or waiting on the platform team: a bespoke sample-intake
form, a specialised visualiser, a one-off calculator that reads your tables and
writes back a result.
Where the SDK and MCP
let code run outside Dalea and reach in, an addon runs inside the
product UI — sharing the host's theme, session and data. It carries no
credential of its own. Its only line to the platform is a capability proxy
called dalea, and every call it makes is checked, host-side, against the
permissions you granted.
Why addons exist
Every lab eventually wants a screen the platform doesn't ship: a plate-layout designer, a dosing calculator, a "register these ten samples the way we do it" form. The choices used to be a spreadsheet macro nobody trusts, or a feature request that waits a quarter. An addon is the third option — a focused mini-app, authored in-workspace, that lives right next to the data it works on and is governed by the same permission model as everything else.
Where an addon appears
An addon declares one or both surfaces in its manifest:
- page
- A full-screen app at
/addons/{id}. Good for tools people open and work in — designers, dashboards, bulk-entry forms. - block
- An embeddable block inside a document. Good for a live widget that lives alongside written protocol — a calculator, a small chart, a status panel. Each embed gets its own configuration.
The security model
Addons are untrusted code by default, and the runtime is built around that assumption. Four properties do the work:
- Sandboxed iframe
- Every addon renders in a cross-origin iframe. Its Content-Security-Policy blocks all external network access — no
fetchorXHRto any origin. If an addon needs data it goes throughdalea; if it wants an external resource, it can't have one. - No credentials
- The iframe holds no session and no token. It cannot see your cookies, call the REST API directly, or act as you outside the capability proxy.
- Scope-checked calls
- Every
dalea.*call is validated on the host against the scopes the addon declared and you consented to. A call outside the granted set is rejected — the addon never touches anything you didn't approve. - Workspace-pinned
- The target workspace is fixed host-side. An addon can never reach into another workspace, whatever it asks for.
An addon requests a subset of nine coarse scopes, and you see exactly which before it runs:
- Data
data.read,data.write— environments, tables, columns, objects, queries, results.- Documents
documents.read,documents.write— read and edit documents and their markdown blocks.- Inventory
inventory.read,inventory.write— lots, containers, placements, consumption (operational only — no type/schema management).- Search
search.read— the unified workspace search.- Storage
storage.read,storage.write— list, fetch and upload files.
Two more guarantees are baked into the capability surface itself. There are
no hard deletes anywhere — the destructive path is archive, reversed by
restore — and calls are rate-limited per instance, so a runaway loop
can't hammer the platform.
An addon that only declares data.read physically cannot write,
delete, upload, or reach the network — not because it promises not to, but
because the host rejects anything else. That's what makes it safe to run a
mini-app a colleague (or an AI assistant) wrote without auditing every line.
The human enablement gate
An addon created in the browser is self-enabled — the person authoring it
is the review. But an addon created programmatically — over the REST API, or
by an AI assistant through MCP — starts disabled. It can be edited and
built, but it will not run anywhere until a person opens /addons/{id}, reads
the permissions it requests, and clicks Enable. That step provisions the
addon's workspace app and generates its permission-ceiling role. If a later
change widens the scopes it asks for, enablement is revoked and a human must
approve again. Machines can write an addon; only a person can turn it on.
Lifecycle at a glance
- 1 · Create
- Make an addon in the app or over the API. Programmatic ones start disabled.
- 2 · Author
- Write the scripts, declare a manifest, map the workspace entities it references. See Authoring an addon.
- 3 · Enable
- A person reviews the requested permissions and turns it on (automatic for browser-authored addons).
- 4 · Build
- The source compiles to a runnable bundle with your entity mappings substituted in.
- 5 · Publish
- Optionally share it to the community marketplace as a bundle. See Publishing & installing addons.
- 6 · Install
- Another workspace installs it, re-maps it to their own entities, and runs it.
Addons vs. the SDK vs. MCP
All three are ways to build on Dalea; they sit at different places.
| Runs | Talks to Dalea via | Best for | |
|---|---|---|---|
| Addon | Inside the app UI (sandboxed iframe) | The scoped dalea proxy | Custom in-product screens and document widgets |
| SDK | Your own code, anywhere | REST + your API key / OAuth | Scripts, backends, integrations that reach into Dalea |
| MCP | An AI client (Claude, a custom agent) | Bearer-authed MCP tools | Letting an LLM read and act on a workspace |
The addon surface is a deliberately narrower subset than the full public API — no destructive operations, no cross-workspace reach — because addon code is the least trusted of the three.