NevoFlux SDK
The JavaScript API available inside Canvas apps — agent, storage, events, tools, sharing.
Every Canvas artifact runs with a global window.NevofluxSDK injected. Through it
your app can talk to the agent, persist data, exchange events, run whitelisted tools,
and share itself — all over a safe message bridge to the host.
API surface
| Namespace | Methods |
|---|---|
| (root) | callTool(action, params) |
agent | chat(message, options), cancel(sessionId), sendCommand(command, params) |
sidebar | open(), send(message), notify(type, data) |
storage | get(key), set(key, value), delete(key), query(prefix) |
system | getInfo() |
events | subscribe(patterns, handler, options), publish(topic, data, options), history(topic, options), waitFor(pattern, options), recover() |
tool | list(options), invoke(toolName, params, options) |
share | share(artifactId, options), import(shareId, password), extend(shareId, secs), delete(shareId), list() |
agent.chat(message, options)
Streams a reply from the agent. options may include sessionId, attachments, and
callbacks onStream, onToolResult, onState. Resolves to
{ text, toolResults, sessionId }.
Example
// 1) Ask the agent and stream the answer into the UI
const result = await NevofluxSDK.agent.chat("summarize the current tab", {
onStream: (c) => { output.textContent += c.delta; },
onState: (s) => { status.textContent = s.status; },
});
console.log(result.text);
// 2) Persist a little state for this artifact
await NevofluxSDK.storage.set("count", "1");
const count = await NevofluxSDK.storage.get("count");
// 3) Discover and run a whitelisted tool, streaming its events
const { tools } = await NevofluxSDK.tool.list();
const { callId } = await NevofluxSDK.tool.invoke(
"ffmpeg.probe",
{ input: "/clip.mp4" },
{ timeoutMs: 10000, onEvent: (e) => console.log(e.event_type, e) }
);
// 4) React to events from elsewhere in NevoFlux
const sub = NevofluxSDK.events.subscribe(["ui:*"], (evt) => {
console.log("event", evt);
});
// sub.unsubscribe() when doneWhich tools
tool.invokecan run is controlled by the tool whitelist. Calls to disabled or unlisted tools are rejected.
What a canvas may do
A canvas runs in an isolated iframe, so the Canvas bridge — the host side of
NevofluxSDK — is its only way to reach anything privileged. Since NevoFlux 0.3.16
the bridge keeps each canvas to what is its own. Code that relied on the looser
behaviour of earlier versions may need changes:
| Area | Rule |
|---|---|
storage | Private to the canvas: keys live in that canvas's own namespace, so two canvases never see each other's data and query('') lists only this canvas's keys. A key written before 0.3.16 is moved into the namespace the first time it is read, unless it starts with config:, canvas:, session: or app:. |
agent.chat / agent.cancel | A canvas can only continue or cancel sessions it started. Only image attachments ({ name, mime_type, data }) are attached; a { path } attachment is named in the message instead, and the agent decides whether to read it with its file tools — under your Agent execution tier. |
agent.sendCommand | A canvas you or the agent made may send only daemon.info, skill.list, and artifact.get for its own artifact. A pack dashboard may send exactly the commands its manifest declares. Settings, pairing, account, raw-storage, MCP-server and pack-install commands are never available to a canvas. |
callTool | Actions that change a page (click, type, …) work only in tabs the canvas opened itself — open one with navigate and new_tab: true. Read actions work on any tab. |
sidebar.send | Text only, up to 4,000 characters, shown in the chat labelled with the canvas id. |
sidebar.notify | A system notification titled with the canvas's name, at most three per 30 seconds per canvas. |
events.publish | Topics starting with ui:notification, ui:soul, ui:render or ui:tab belong to the browser and are refused. |
share | share() always shares the calling canvas; list() shows only its shares, and extend / delete work only on them. |
A refused call rejects its promise with an error whose message starts with a code
such as FORBIDDEN_COMMAND:, COMMAND_NOT_AVAILABLE: or NOT_OWN_SESSION:, so
your code can tell a policy refusal from a failure.
Policy checks on callTool
Before a canvas's callTool runs, the browser asks the agent's policy
(canvas.policy_check) whether it may, using the same
pack site rules the
agent's own calls go through:
- A rule that would ask refuses instead — a canvas cannot host a confirmation dialog mid-call.
- A pack dashboard built for
pack-protocol/0.2may only use the actions it declared in its manifest. - If the agent cannot be reached, reads still work and anything else is refused, so stopping the agent is not a way around a pack's rules.
The check and the tab-ownership rule are enforced by the browser before the action runs, not by the canvas, so canvas code cannot skip them.