Panel
A new glass panel on any screen: your GPU as rings, your next three events, anything a page can draw from live data.
01 // Plugins
Holo Intelligence UI changes when you ask. Describe a panel, a theme or a routine and your assistant builds it. Or write a plugin yourself: one folder, one page.
02 // What a plugin can be
A plugin is a folder with a manifest that says what it is and what it may see. Settings plugins never run code. Code plugins run in a sandbox.
A new glass panel on any screen: your GPU as rings, your next three events, anything a page can draw from live data.
A new body style for your assistant. It’s code, so like a panel it’s one page with an entry file, run in the sandbox.
Colours, glow, motion and font. Settings only, never code, so any capable model can make one.
Something it does on its own, in plain words: “every weekday at 8am give me a briefing.” Settings only.
Level 1 · settings
Themes, colours, text size, motion, its name, personality and voice, screen layouts and routines from templates. Applied straight away, and Ctrl+Shift+Z takes any of it back. Any model rated “can customize” can do it, and the common requests work with no model at all.
Level 2 · code
New panels and features, written as a plugin by a model rated “can build plugins” or by Claude Code. You see it running in a live preview first, then pick the screen it goes on. Every install keeps the version before it.
03 // Ask the builder
“Build me a panel that shows my GPU temperature as rings.” Your assistant writes the plugin, checks it, and shows it to you running. Nothing is installed until you say so.
fetch, XMLHttpRequest, WebSocket and import are rejected, and the manifest has to pass.An illustration of the studio’s Build tab. The preview is a real plugin running on this page, fed made-up readings.
Press Check intelligence on any model you connect: five small coding tasks with hidden tests, run in a separate process. Answers that try to touch your PC fail. The score decides what that model may change.
The tasks Roman numerals · reading durations · merging intervals · fitting a panel on a grid · shading a colour
In local-AI mode only models on your PC build. Ask out loud and it builds in the background, then the studio holds it until you’ve tried it.
04 // In the box
It comes with all of this, and every piece follows the theme you pick. The plugin guide adds a working example to learn from.
Pick one of the first six and this website changes too. In the app: custom colours, glow, motion, four fonts, and a theme made from any picture.
A small team takes turns on one job. Each member sees the goal and what the others wrote.
Make your own with up to six members. The code review crew reads a project folder and changes nothing.
Small cues for notifications, approvals, focus, listening and undo, made on the spot with no sound files. Press one to hear the real notes.
How busy each computer’s processor is, as glowing rings. A complete panel plugin in one short page, and the best place to start reading.
05 // Live demo
This is the example plugin from the plugin guide, unchanged, in the same kind of sandboxed frame the app uses. This page plays the part of the screen: it sends the theme, then made-up readings every second.
sandbox="allow-scripts"telemetry.*Play the screen
Change the theme: the plugin gets a new theme message
The readings are made up. In the app they come from your computers, and this is the name the app gives the PC it’s installed on. The plugin draws a ring for each computer it hears about.
The files manifest.json panel.html
06 // Make your own
Most people never write a plugin by hand: they ask, and the builder writes it. This is for anyone who wants to, or wants to know what the builder makes.
A plugin is a folder holding a manifest.json and its files. For a panel, that’s one page:
cpu-ring/
manifest.json
panel.html
{
"id": "cpu-ring",
"name": "CPU Ring",
"version": "1.0.0",
"kind": "panel",
"level": 2,
"entry": "panel.html",
"reads": ["telemetry.*"],
"description": "How busy each computer's processor is, as glowing rings.",
"author": "you"
}
| Field | Needed | What it means |
|---|---|---|
id | Yes | 2 to 41 lower-case letters, digits or dashes. Unique: installing the same id again updates it, and keeps the version before. |
name | Yes | What the studio calls it. |
version | Shown in the Plugins tab, for example 1.0.0. | |
kind | Yes | panel or body (code, level 2), theme or routine (settings only, level 1). |
level | 1 is settings only, 2 is code. Themes and routines must be level 1. A level 2 plugin built by a model needs a model that passed the intelligence check. | |
entry | Panels, bodies | The page that’s shown: an .html file in the folder. |
reads | The live topics the plugin is given. This is its whole permission list: it receives nothing else. * matches one part, as in telemetry.*. | |
description | One sentence, shown before anyone installs it. | |
author | Who made it. |
A plugin may never read config.settings, approvals or pair.code. The manifest check refuses it, and the clipboard, meeting, Holo Link and developer topics are off limits too.
The plugin runs in a sandboxed frame with scripts allowed and nothing else. It can’t reach the interface’s page, its key, cookies or storage. The screen sends it messages instead:
window.addEventListener('message', (e) => {
const {topic, data} = e.data || {};
if (topic === 'theme') { /* the interface's colours */ }
if (topic && topic.startsWith('telemetry.')) { /* a computer's live readings */ }
});
First comes a theme message with the current theme’s colours and font. Use them and your plugin follows every theme the user picks. Then each topic in reads arrives whenever it changes.
// first: the theme
{topic: 'theme', data: {'--void': '#050102', '--ember': '#ff2b2b', '--glow': '#ffb0a4',
'--hot': '#ffe0d8', '--muted': '#c4473f', '--font-ui': '"Rajdhani", …'}}
// then each topic it reads, whenever it changes
{topic: 'telemetry.this', data: {cpu: {pct: 37, count: 16}, mem: {used: …, total: …, pct: 41},
gpu: [{name: …, util: 22, temp: 58, …}], net: {down: …, up: …}}}
| Topic | What’s in it |
|---|---|
telemetry.<machine> | cpu {pct, count}, mem {used, total, pct}, gpu [{name, util, temp, mem_used, mem_total}], net {down, up} (bytes a second), disk {drives [{mount, pct}]}, battery |
music.now | track, artist, playing, device {name} |
weather.now | temp, unit, text, high, low, tomorrow |
calendar.upcoming | events [{title, start, end, all_day}] |
claude.<machine> | sessions [{title, state, doing, tokens {in, out}, context {used, window, pct}}] |
ai.models | models [{title, where, plain, badges}] |
presence | state: present, away or asleep |
fetch, XMLHttpRequest, WebSocket or import. The builder rejects them.A whole panel in about fifty lines: each graphics card’s temperature as a ring. It’s the one running in the builder preview above. Copy it, or download the folder’s two files, and change it into yours.
<!doctype html>
<!-- A starter panel plugin for Holo Intelligence UI: each graphics card's temperature as a ring.
One self-contained page. The screen sends it a "theme" message, then each topic its manifest reads. -->
<meta charset="utf-8">
<style>
html, body { margin: 0; height: 100%; background: transparent; overflow: hidden; }
body {
box-sizing: border-box; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4% 8%;
padding: 4%; font-family: var(--font-ui, sans-serif); color: var(--glow, #ffb0a4);
}
.gpu { position: relative; width: min(40%, 78vh); aspect-ratio: 1; }
.gpu svg { width: 100%; height: 100%; transform: rotate(135deg); }
.gpu circle { fill: none; stroke: var(--ember, #ff2b2b); stroke-width: 7; }
.gpu .track { stroke-opacity: 0.18; }
.gpu .arc { transition: stroke-dasharray 0.6s ease; }
.read { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.read b { font-size: min(9vw, 16vh); line-height: 1; color: var(--hot, #ffe0d8); }
.read small { margin-top: 0.4em; font-size: min(2.8vw, 5vh); letter-spacing: 0.12em; text-transform: uppercase; }
.wait { opacity: 0.8; }
@media (prefers-reduced-motion: reduce) { .gpu .arc { transition: none; } }
</style>
<div class="wait">Waiting for data…</div>
<script>
// A 270° gauge from 20 °C to 100 °C, on a circle of radius 42.
const LOW = 20, HIGH = 100, ARC = 0.75 * 2 * Math.PI * 42;
const rings = {};
function ring(key, label) {
if (rings[key]) return rings[key];
document.querySelector('.wait')?.remove();
const el = document.createElement('div');
el.className = 'gpu';
el.innerHTML = `<svg viewBox="0 0 100 100"><circle class="track" cx="50" cy="50" r="42" stroke-dasharray="${ARC} 999"/>
<circle class="arc" cx="50" cy="50" r="42" stroke-dasharray="0 999"/></svg>
<div class="read"><b>–</b><small></small></div>`;
el.querySelector('small').textContent = label;
document.body.append(el);
return (rings[key] = el);
}
window.addEventListener('message', (e) => {
const {topic, data} = e.data || {};
if (topic === 'theme') { // the interface's colours: use them, and the plugin follows every theme
for (const [k, v] of Object.entries(data || {})) document.documentElement.style.setProperty(k, v);
return;
}
if (!topic || !topic.startsWith('telemetry.') || !data || !Array.isArray(data.gpu)) return;
const machine = topic.split('.')[1];
data.gpu.forEach((gpu, i) => {
if (gpu.temp == null) return; // not every card reports its temperature
const el = ring(`${machine}.${i}`, `${machine} · ${gpu.name || 'GPU ' + (i + 1)}`);
const t = Math.max(LOW, Math.min(HIGH, gpu.temp));
el.querySelector('.arc').setAttribute('stroke-dasharray', `${((t - LOW) / (HIGH - LOW)) * ARC} 999`);
el.querySelector('b').textContent = `${Math.round(gpu.temp)}°`;
});
const wait = document.querySelector('.wait');
if (wait && data.gpu.length && data.gpu.every((g) => g.temp == null)) wait.textContent = 'This graphics card doesn’t report its temperature.';
});
</script>
Download manifest.json panel.html
Test it in a browser first. Open your panel.html, press F12, and play the screen from the console:
postMessage({topic: 'theme', data: {'--ember': '#2bd4ff', '--hot': '#e2f8ff'}}, '*');
postMessage({topic: 'telemetry.this', data: {gpu: [{name: 'GPU', temp: 64}]}}, '*');
%USERPROFILE%\.sarch\plugins\.Every install keeps the previous version, so “Go back a version” in the Plugins tab undoes an update. Safe mode turns every plugin off at once if something misbehaves.
07 // The safety model
Every plugin runs under the same rules, whether your assistant built it or a friend sent it.
config.settings), approvals and pairing codes (pair.code) can’t be read by any plugin. The manifest check refuses it.Install it, connect a model that can build, and ask. The setup guide walks you through connecting one.