Documentation

User guide and developer references.

Developer Guide

Build API v7 extensions

An extension is one JavaScript module that runs inside the app in the browser. It can give the model tools, react to each chat turn, keep its own state, and render UI in the app's own surfaces.

What an extension is

The app loads your file as an ES module and reads its exports. The only required export is manifest. Everything else is optional: tools, prompt contributions, lifecycle hooks, and React components for the app's UI surfaces.

Module rules

One file. No import statements, no bundler, no npm packages.

No JSX. Build UI with globalThis.React.createElement.

Plain browser APIs are fine: fetch, WebSocket, Web Bluetooth, Web Serial, Audio.

Where it runs

Same page and same privileges as the app itself. Nothing is sandboxed.

Tools execute in the browser, not on the server.

State that should persist goes through the variables API, not localStorage.

Build flow

  1. 1Create a folder named after your key with manifest.json and one .js module.
  2. 2Turn on Developer Mode in the app, point Dev Extensions at the folder, and install it.
  3. 3Edit, then press Reload on the Dev Extensions card. No restart.
  4. 4Submit the same manifest and source as a marketplace draft when it works.

The Workflow page covers each step in detail.

Start here

The smallest useful extension: a manifest, one tool, and the handler that runs it. The manifest exists twice, once as JSON for the loader and once as the module export.

json
{
  "apiVersion": 7,
  "version": "1.0.0",
  "key": "hello-extension",
  "name": "Hello Extension",
  "category": "integration",
  "icon": "Sparkles",
  "description": "Adds one browser-side tool."
}
js
export const manifest = {
  apiVersion: 7,
  version: '1.0.0',
  key: 'hello-extension',
  name: 'Hello Extension',
  category: 'integration',
  icon: 'Sparkles',
  description: 'Adds one browser-side tool.',
};

export function getTools() {
  return [
    {
      type: 'function',
      function: {
        name: 'say_hello',
        description: 'Return a short greeting for the given name.',
        parameters: {
          type: 'object',
          properties: {
            name: { type: 'string', description: 'Who to greet.' },
          },
          required: ['name'],
        },
      },
    },
  ];
}

export async function executeTool(name, args, ctx) {
  if (name !== 'say_hello') {
    throw new Error(`Unknown tool: ${name}`);
  }
  ctx.runtime.ui.toast({ message: `Greeted ${args.name}`, level: 'success' });
  return { message: `Hello, ${args.name}.` };
}
✦
Get the tool path working before adding hooks, variables, or UI. Each addition has its own reference page below, and the full example shows them working together.

Guide map