Panel Control
UnreviewedThe Adom web app displays a set of interactive panels such as the 3D layout editor and schematic designer. Panels provide live views, controls, and data for the workcell and its hardware. Manipulate t
name: adom-panel-control
description: Use when the user wants to open, close, add, or remove a panel; change the workspace layout; resize a split; show or hide a sensor view, camera, log, control panel, or any Adom editor panel; or asks "what panels are available". Examples: "open the 3D viewer", "add a web view tab", "close the robot log", "resize the split to 70/30", "show me the motor control panel", "what panels can I open?".
user-invokable: true
Adom Panel Control
The Adom web app displays a set of interactive panels such as the 3D layout editor and schematic designer. Panels provide live views, controls, and data for the workcell and its hardware. Manipulate the Adom editor workspace: add/remove tabs, resize splits, and query the layout.
Environment
All API calls require:
- Base URL:
https://hydrogen.adom.inc/api/workspaces/editor/{owner}/{repo}/current - JSON parsing:
jqis not available in the container. Usepython3 -m json.toolto pretty-print JSON output instead. - Auth:
X-Api-Keyheader. Obtain the key by reading/var/run/adom/api-key— this file is always present in the container, is read-only, and contains the token with no leading or trailing whitespace:
Fall back to env vars (API_KEY=$(cat /var/run/adom/api-key)ADOM_API_KEY,API_KEY,X-Api-Key) only if that file is missing. Ask the user only as a last resort.
Critical Rules — Read Before Doing Anything
- NEVER use PUT to replace the full layout. It wipes the entire workspace and breaks node IDs. Always use granular
POST /tabs,DELETE /tabs, andPATCH /splitscalls — even for complex multi-step changes. Build up the desired layout one operation at a time. - NEVER echo or display the API key in tool output. Store it in a shell variable — never
catit on its own or log it. - Add before removing when swapping tabs in a leaf — the API returns 400 if you try to remove the last tab, so always add the new tab first, then remove old ones.
- Remove tabs from highest index first when removing multiple tabs from a leaf, to avoid index shifting.
- Re-fetch the layout before each batch of operations — state can change between calls. Always confirm current node IDs and tab indices are still valid.
Workflow
Always follow this order when making changes:
- Setup — resolve credentials, repo, and target user (ask once, remember for the session)
- GET the current layout to find leaf node IDs
- Identify the correct leaf
idfor where the user wants the tab placed - Look up the
panelTypefull ID from the catalog below - POST/DELETE/PATCH to make the change
- Confirm success to the user
Step 0 — Setup: resolve credentials, repo, and target user
At the start of the session, if OWNER, REPO (THIS IS AN ADOM REPO NOT A GITHUB REPO), or API_KEY are not yet known, ask the user:
"What is the Adom owner (username or org) and repository name for this project?"
Remember the answers for the rest of the conversation — do not ask again.
Then read the API key and set up the base URL:
API_KEY=$(cat /var/run/adom/api-key)
BASE="https://hydrogen.adom.inc/api/workspaces/editor/$OWNER/$REPO/current"
Discover the target user. Workspaces are scoped per-user. You must discover who has an open editor:
curl -s -H "X-Api-Key: $API_KEY" "$BASE/users" | python3 -m json.tool
# → { "users": [{ "username": "kcknox" }] }
- One user (most common): auto-detected by the server — no extra header needed. Set
TARGET_HEADER="". - Multiple users: ask the user which person's workspace to modify. Remember the choice and set:
TARGET_HEADER='-H "X-Target-Username: <chosen-username>"' - Zero users: the editor is not open in any browser. Tell the user to open the editor first.
Save OWNER, REPO, API_KEY, BASE, and TARGET_HEADER (if needed) in your memory file so you don't repeat this setup.
Step 1 — GET current layout
curl -s -H "X-Api-Key: $API_KEY" $TARGET_HEADER "$BASE" | python3 -m json.tool
Parse the response to find:
- All
leafnodes and theiridvalues (needed for adding/removing tabs) - All
splitnodes and theiridvalues (needed for resizing) - The
tabsarray on each leaf andactiveTabIndex
Step 2 — POST: Add a tab
curl -s -X POST \
-H "X-Api-Key: $API_KEY" $TARGET_HEADER \
-H "Content-Type: application/json" \
-d '{"panelId":"<leaf-id>","panelType":"<full-panel-id>"}' \
"$BASE/tabs"
Returns { "tabId": "<uuid>" } on success.
If the user doesn't specify which panel (leaf) to add to and there is more than one leaf, ask them where they want it placed, or place it in the largest/most relevant leaf.
Step 3 — DELETE: Remove a tab
curl -s -X DELETE \
-H "X-Api-Key: $API_KEY" $TARGET_HEADER \
-H "Content-Type: application/json" \
-d '{"panelId":"<leaf-id>","tabIndex":<number>}' \
"$BASE/tabs"
tabIndex is 0-based. GET the layout first to confirm the correct index.
Finding a tab by name: When the user says "close the Robot Log", GET the layout, walk every leaf node, find the tab whose panelType matches the catalog ID (e.g. adom/a1b2c3d4-bbbb-4000-a000-00000000000b), then DELETE using that leaf's id and the tab's array index.
Cannot remove the last tab in a leaf — the API returns 400. Inform the user if this happens.
Step 4 — PATCH: Resize a split
curl -s -X PATCH \
-H "X-Api-Key: $API_KEY" $TARGET_HEADER \
-H "Content-Type: application/json" \
-d '{"ratio":0.3}' \
"$BASE/splits/<split-id>"
ratio is the fraction given to the first child (0.1–0.9). So "70/30" → ratio: 0.7.
Step 5 — PUT: PROHIBITED
DO NOT use PUT. It wipes the entire workspace. There is no valid use case for an AI agent. Use
POST /tabs,DELETE /tabs, andPATCH /splitsinstead.
Step 6 — GET /events: SSE event stream (optional, for real-time sync)
curl -s -H "X-Api-Key: $API_KEY" "$BASE/events"
Emits { "type": "connected" } once, then { "type": "workspace_updated" } on every mutation. The container is typically the mutator, not the listener — this is mainly useful if you need to wait for another actor's change before proceeding.
Layout Structure Reference
The workspace is a binary tree:
- SplitNode —
{ type: "split", id, direction: "horizontal"|"vertical", ratio: 0.1–0.9, first: PanelNode, second: PanelNode } - LeafNode —
{ type: "leaf", id, tabs: PanelTab[], activeTabIndex: number } - PanelTab —
{ id, panelType: "<full-panel-id>", panelState?: { ... } }
Singleton Panels
These may only appear once in the entire workspace. Check the current layout before adding — if already present, tell the user rather than adding a duplicate.
| Full ID | Name |
|---|---|
adom/a1b2c3d4-1111-4000-a000-000000000001 |
3D Viewer |
adom/a1b2c3d4-0012-4000-a000-000000000012 |
Schematic Editor |
Panel Catalog
Development
| Full ID | Name | Description |
|---|---|---|
adom/a1b2c3d4-eeee-4000-a000-00000000000e |
Visual Studio Code | Embedded VS Code editor |
adom/a1b2c3d4-0012-4000-a000-000000000012 |
Schematic Editor | Circuit schematic editor (singleton) |
adom/a1b2c3d4-0014-4000-a000-000000000014 |
Script Runner | Execute automation scripts |
Control
| Full ID | Name | Description |
|---|---|---|
adom/a1b2c3d4-3333-4000-a000-000000000003 |
Motor Control | XRP robot motor speed/direction |
adom/a1b2c3d4-4444-4000-a000-000000000004 |
LED Control | XRP robot LED color/brightness |
adom/a1b2c3d4-5555-4000-a000-000000000005 |
Servo Control | XRP robot servo angle |
adom/a1b2c3d4-001b-4000-a000-00000000001b |
Drone Control | Drone flight control and telemetry |
adom/a1b2c3d4-001c-4000-a000-00000000001c |
ESC Control | Electronic Speed Controller |
adom/a1b2c3d4-0010-4000-a000-000000000010 |
Lights Control | RGB/white LED strip with color wheel |
adom/a1b2c3d4-0022-4000-a000-000000000022 |
Workcell Power | Power supply voltage/current limits |
adom/a1b2c3d4-0023-4000-a000-000000000023 |
Basic Control Panel | GPIO pin modes and digital write |
Visualization
| Full ID | Name | Description |
|---|---|---|
adom/a1b2c3d4-1111-4000-a000-000000000001 |
3D Viewer | Workcell/robot 3D view (singleton) |
adom/a1b2c3d4-001a-4000-a000-00000000001a |
Babylon OTB | Babylon.js 3D viewer with OTB support |
adom/a1b2c3d4-6666-4000-a000-000000000006 |
IMU Sensor | Accelerometer, gyroscope, orientation |
adom/a1b2c3d4-8888-4000-a000-000000000008 |
Time of Flight Sensor | ToF distance readings |
adom/a1b2c3d4-9999-4000-a000-000000000009 |
Ultrasonic Sensor | Ultrasonic distance / obstacle detection |
adom/a1b2c3d4-aaaa-4000-a000-00000000000a |
Line Follower | Line following sensor array |
adom/a1b2c3d4-0015-4000-a000-000000000015 |
Temperature Graph | Real-time temperature graphing |
adom/a1b2c3d4-0016-4000-a000-000000000016 |
Chip Data | Microchip data monitoring |
adom/a1b2c3d4-0017-4000-a000-000000000017 |
Chip Statistics | Microchip performance metrics |
adom/a1b2c3d4-0018-4000-a000-000000000018 |
Oven Data | Oven temperature/control monitoring |
adom/a1b2c3d4-0019-4000-a000-000000000019 |
ToF Sensor | Time-of-Flight data visualization |
adom/a1b2c3d4-001d-4000-a000-00000000001d |
Bosch Sensors | Bosch sensor suite monitoring |
adom/a1b2c3d4-001e-4000-a000-00000000001e |
BMP Sensor | Bosch BMP pressure/temperature |
adom/a1b2c3d4-0020-4000-a000-000000000020 |
BMV Sensor | Bosch BMV sensor visualization |
adom/a1b2c3d4-0021-4000-a000-000000000021 |
UWB Sensor | Ultra-Wideband positioning |
Media
| Full ID | Name | Description |
|---|---|---|
adom/a1b2c3d4-ffff-4000-a000-00000000000f |
Live Stream | Live camera: static/free-moving or XY zoom |
adom/a1b2c3d4-ffff-4000-a000-000000000100 |
WebRTC Player | Single WebRTC video stream |
adom/a1b2c3d4-2660-4a00-a000-000000000266 |
XY Zoom Camera | Dual WebRTC streams with minimap |
Utility
| Full ID | Name | Description |
|---|---|---|
adom/a1b2c3d4-0011-4000-a000-000000000011 |
System Log | Real-time system log with filtering |
adom/a1b2c3d4-bbbb-4000-a000-00000000000b |
Robot Log | XRP robot console output |
adom/a1b2c3d4-7777-4000-a000-000000000007 |
Battery Charger | Battery charging status and power |
adom/a1b2c3d4-cccc-4000-a000-00000000000c |
Curriculum | XRP robot educational content |
adom/a1b2c3d4-0031-4000-a000-000000000031 |
Web View | Embedded browser — load any URL |
Panel Details
XY Zoom Camera
Available on all workcells (included with the base $500/mo subscription).
Shows two simultaneous live video feeds:
- Wide view — A 120° FOV camera providing a constant birds-eye view of the entire workcell. This feed always shows the full workcell regardless of where the camera gantry is positioned. Use it for spatial awareness and general monitoring.
- Zoom view — A zoomable camera that can magnify down to a 10 mm x 10 mm area filling the entire feed. Use it for close-up inspection of components, solder joints, traces, wire connections, and fine details.
Controls: X/Y click-to-move or drag, zoom slider/scroll, preset position save/recall.
Upgrade — xyPanTiltZoom (+$100/mo): Adds pan (horizontal rotation), tilt (90° straight-down to angled perspectives), and 3D viewer linking — locks the physical camera to the user's 3D layout editor viewpoint so the real camera moves as they orbit/pan/zoom.
3D Viewer
Interactive 3D view of the workcell. Shows all molecules, scaffolds, wires, and the base scaffold in physical positions. Users can orbit, pan, and zoom. When xyPanTiltZoom 3D linking is enabled, navigating this viewer controls the physical camera.
Schematic Editor
Displays the project's scaffold schematic pages. Users can browse pages, inspect component pins, trace nets, and see how molecules are electrically connected.
User Plugins (Custom Panels)
Users can create custom panels via plugins in plugin-content/. Each plugin subfolder contains code and an HTML interface that appears as a panel in the web app. The front-end panel communicates with a mini web server on the Docker container, which can interact with hardware via USB, Ethernet, GPIO, or the Adom API.
Examples: motor control, sensor dashboard, firmware manager, test runner.
Relationship to Docker API
Panels and the Docker API are bidirectional:
- Panels → API: Panel actions (e.g. camera moves) update the Docker container via WebSocket.
- API → Panels: REST commands (e.g. scripted camera moves) update panels in real time.
- Messaging: Scripts can send notifications via
POST /message/send. - Viewer count:
GET /viewers/countreturns how many users are viewing the project.
See the adom-api guide for the full API reference.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
409 Conflict |
Editor is not open in the browser, or multiple users and no X-Target-Username |
Check GET .../current/users first. If zero users, ask user to open the editor. If multiple, specify the target username. |
404 on panelId |
The leaf ID is stale or wrong | Re-GET the layout and use fresh IDs |
400 on tab remove |
Tried to remove the last tab in a leaf | Tell the user — a leaf must always have at least one tab |
400 on add tab |
Missing panelId or panelType |
Verify both fields are present and non-empty |
401 Unauthorized |
Missing or invalid API key | Read /var/run/adom/api-key; if missing, check env vars or ask the user |
| Singleton already present | Adding a panel that only allows one instance | Inform the user it's already open; offer to navigate to it instead |