# Panels A panel is a small HTML app that Offsider shows in a window beside your work: a checklist to get through while you work, a queue of pull requests to test, anything a web page can show. Claude Code opens it, follows what you do in it, and hands it new data as things change. Offsider hosts the interface and its declared tools. It has no recording or drawing engine. This section covers: - [panel.json](/docs/panels/manifest.md): the window's size and style, what the app may load, and its tools. - [The JavaScript API](/docs/panels/api.md): how the app talks to Offsider, and the MCP Apps messages underneath. - [Tools](/docs/panels/tools.md): how a panel gets live data. - [Headers and backgrounds](/docs/panels/titlebar.md): drawing behind the titlebar. - [What a panel can't do](/docs/panels/security.md): the sandbox. ## Make one ```sh offsider init my-panel offsider open my-panel ``` `init` writes a folder with two files: - `index.html` — the app. One file is plenty; add scripts, styles and images next to it if you like. - `panel.json` — the window's size and style, and the commands the app may run. Optional: without it, you get a 380×560 window. `open` asks you to approve all declared tools before loading a panel that has tools. After approval, it shows the window and streams panel events. Press Ctrl-C to detach while leaving the panel open; `offsider attach my-panel` resumes the feed and replays recent missed events. New panels come to the front. Open Panels in Offsider's menu bar or Window menu brings any panel forward. Command-W minimizes a panel to the Dock without stopping it; `offsider show my-panel` restores it. Close the panel with its close button or `offsider close my-panel`. ## What `offsider open` prints Everything that happens in the panel comes out on stdout, one JSON object a line, so Claude Code can run it in the background and read along: ```json {"type":"opened","panel":"my-panel"} {"type":"event","panel":"my-panel","name":"checked","data":{"id":"login"},"note":"Ticked: Log in works"} {"type":"message","panel":"my-panel","text":"Done with this one."} {"type":"log","panel":"my-panel","level":"error","data":["TypeError: …"]} {"type":"closed","panel":"my-panel"} ``` | Type | When | | --- | --- | | `opened` | The window is up. | | `event` | The app called `offsider.emit(name, data, note)`. | | `message` | The app called `offsider.message(text)`: something meant for whoever opened it. | | `context` | The app called `offsider.modelContext(text, data)`. | | `log` | The app logged with `console.error`, `console.warn` or `console.info`, or hit an uncaught error. | | `closed` | The window closed. The command exits 0 right after. | The command exits 1 if Offsider quits underneath it. ## Commands Run `offsider` for a welcome banner and command list. Use `offsider COMMAND --help` for command-specific usage. ``` offsider init DIR write a starter panel offsider open DIR [--name NAME] [--input JSON|@FILE] offsider attach NAME [--after SEQUENCE] resume panel events offsider send NAME JSON|@FILE hand the open panel new data offsider show NAME show a hidden panel offsider close NAME offsider list offsider docs print these docs offsider --help show help (-h) offsider --version show the installed version (-V) ``` - `--name` defaults to the folder's name. Only one panel can have a given name at a time. - `--input` is the app's starting data. `@FILE` reads it from a file, and `@-` from stdin. - `send` delivers new data to an open panel. The app decides what to do with it: replace everything, or merge. ## With an AI agent Keep `offsider open` running in a background terminal. Read its JSON lines, act on events, and send new data with `offsider send`. Tool commands are explicit capabilities declared in `panel.json`; only open folders whose HTML and commands you trust. See [AI agent workflows](../../integration.md) for orchestrating panels and tools.