Frontend components (agency-ui)

agency-ui maps each schema type string to a Vue component via componentRegistry in src/renderer/registry.ts. UiRenderer looks up node.type and renders recursively.

Source of truth for the type list is that registry (and src/schema/ui.ts). This page summarises what each registration is for.

Self-rendering types

These nodes iterate children themselves (no default child slot from UiRenderer): page, split, desktop, window.

Layout

Schema type

Vue component

Role

page

AgencyPage

Top-level page chrome

panel

AgencyPanel

Generic panel container

pad

AgencyPad

Padded content region

split

AgencySplit

Splitpanes (see UI Schema for direction)

sidebar

AgencySidebar

Side navigation region

toolbar

AgencyToolbar

Toolbar strip

menu

AgencyMenu

Menu container

menu-item

AgencyMenuItem

Single menu entry

Primitives

Schema type

Vue component

Role

card

AgencyCard

Card surface with optional title

button / agency-button

AgencyButton

Button; optional action. Address: inherited prefix + name

agency-mission

AgencyMission

One mission instance (channel + uuid). Not the catalog explorer.

progress

AgencyProgress

Progress / indeterminate bar

text

AgencyText

Plain text

markdown

AgencyMarkdown

Markdown body

Desktop chrome

Schema type

Vue component

Role

desktop

AgencyDesktop

Root desktop surface (icons + floating windows)

desktop-icon

AgencyDesktopIcon

Desktop launcher icon

window

AgencyWindow

Registers window state; hosts child schema

dock

AgencyDock

Schema stub (no UI; kept for fixtures compatibility)

(chrome)

AgencyAgentFace

128×128 agent portrait + CSS overlay (eyes / mouth). Moods: idle, thinking, speaking (South Park jaw). First desktop icon (chrome, not schema) and Agents explorer. Not a schema node.

Window chrome (not schema types)

Native Vue MDI — no WinBox. State lives in Pinia windowsStore (agency-ui/src/stores/windows.ts). Chrome pose (z / rotation / scale) is on the store + desktop snapshot, not overlay. DSM desktop.projection flat | perspective is a thin 3D stage (drawer / deck / Options). In perspective the seat is an FPS helm: triple glass 2 · 1 · 3, world origin at the center pane’s bottom edge, identity camera { x: 0, y: -400, z: 72 }. WASD walks; Space is mouselook + pointer lock (no RMB look); wheel is head height; Ctrl crouches from the current Y. Sit / Home resets the camera and does not move windows. There is no desk, orbit gizmo, or pistol mode. Windows carry screen (left / center / right) and hop on release past a hinge. 2D minimize is a top-right quarter-width column (the stack scales if it does not fit); 3D minimize is a bottom carousel. Min / restore / maximize interpolate left / top / size / scale. Restore seeds minimized before openAddress so F5 does not dump shelved windows back onto the desktop. The body is transform-style: flat. Wheel on maximize changes chrome pose.scale (CSS 3D, origin center) 5%, anchored on the cursor so the window grows under the mouse, never larger than the viewport. On F5 a window under the app bar is pushed down; overflow on two sides pins to those edges. Scale is in the desktop snapshot. Mosaic (tileMosaic) lays out every open window in a CCTV grid; the active window gets the featured pane.

Component

File

Role

AgencyWindowFrame

components/desktop/AgencyWindowFrame.vue

Title bar, drag, resize, min / max / close

AgencyWindowsList

components/desktop/AgencyWindowsList.vue

Open-window list for the shell drawer (Windows tab)

ShellDrawerHeader

components/shell/ShellDrawerHeader.vue

Drawer profile (48px avatar + name) + Media preview

ShellDrawerTools

components/shell/ShellDrawerTools.vue

Theme, mosaic, 3D stage, labeled Install

ShellBarActivity

components/shell/ShellBarActivity.vue

App-bar System icon: channel glyph (two PCs) while idle; REST / telemetry glyphs during recent activity. Click opens System.

AgencyInboxList

components/shell/AgencyInboxList.vue

Drawer Inbox tab (pending HITL; opens reply dialog)

AgencySitesList

components/shell/AgencySitesList.vue

External links in user.me Sites tab

useWindowDrag

composables/useWindowDrag.ts

Pointer drag on the title bar

Lifecycle (persistent windows):

State

Meaning

closed

open=false — not listed in the drawer. Layout (x/y + chrome pose) is forgotten; the next open takes a cascade slot.

floating

open=true, minimized=false, maximized=false — x/y/w/h

maximized

Same chrome as mobile: fills below the app bar, no window title bar, title + min/close in the app bar (desktop also has restore). Flat app bar (no shadow). Only one maximized window.

minimized

2D: top-right shelf (¼ width). 3D: bottom carousel. Listed dimmed in the drawer.

Ephemeral windows (props.ephemeral) are removed from schema + store on close.

Typography — the Agency desktop uses a compact scale inside window bodies: 13px body, 12px labels/captions (styles/main.scss, styles/explorer.scss). System pane toolbars use icon-only actions with title tooltips.

Explorer form styling

Shared field chrome lives in agency-ui/src/styles/explorer.scss (imported from main.scss). Do not add per-component scoped CSS for Vuetify v-text-field / v-select / v-textarea sizing in explorers or admin windows — use the markup hooks below so every surface matches.

Hook class

Use

agency-explorer

Root on list+ficha explorers (Agents, Missions, Models, …). Layout: explorer-list + explorer-detail. Photos/Agents/Missions/Tools use agency-split (resizable); others keep a 260px list. Photos/Agents/Missions/Tools add agency-explorer--chrome: AgencyChromeBar header + list Filter + hideable detail + footer.

agency-chrome-bar

Shared 40px header / footer (AgencyChromeBar). Explorers, secretary chat, execution chat, and Media all use it. Buttons inside windows use --agency-btn-font-size (Image / Speak).

detail-form

Right-hand CRUD column. Flex column; children are full-width Vuetify fields with density="compact" and variant="outlined".

list-toolbar / list-toolbar--run

Sidebar toolbar, 40px (same as window tabs). --run = column stack. Selects keep native compact height (not the single-line crunch).

detail-header__run / agency-chrome-bar__end

Top-bar run cluster, right side, hide-detail last. Photos: Open in Media. Missions: Agent (plain) + play. Agents: Chat. Tools: Sync (icon). Selected title in the chrome-bar title slot.

list-toolbar__filter

Fixed-width filter select in a horizontal toolbar (Executions).

form-top

Two-column grid row inside detail-form (e.g. Name + Model).

form-fill-area

v-textarea that grows to fill space above the footer (Prompt, Instructions, Notes, Summary).

form-tools

Multi-select with chips (Tools); natural height, wraps chips.

agency-form-fields

Admin Options and similar preference forms (not inside agency-explorer).

CSS variables (on detail-form, agency-form-fields, list-toolbar):

  • --agency-field-input-size — 13px value text

  • --agency-field-label-size — 11px labels

  • --agency-field-min-height — 28px single-line input (detail-form only)

Domain-only layout (flags row, file upload row, etc.) may stay in component scoped CSS; field paint does not.

Workbench chrome (split tool windows)

Tool windows that pair a navigation tree with a detail pane — UI Schema, Help — share agency-ui/src/styles/workbench.scss (imported from main.scss). Explorers keep explorer.scss; the two are separate chromes for different shapes.

Hook class

Use

agency-split

Root <Splitpanes>. Styles the splitter; panes get the canvas background.

agency-pane / agency-pane--nav

Column inside a <Pane>. --nav is the canvas (same floor as explorer lists). The other pane’s body is surface — the raised sheet used under window tabs.

agency-pane__toolbar / __title

Pane header, 40px (same as window tabs), uppercase muted title. Use a plain div, not v-toolbar, so both panes align.

agency-pane__body / --flush

Scrolling region. --flush for children that scroll themselves (AG Grid, terminals).

agency-tree

On v-treeview. File-explorer density: 22px rows, 16px toggle gutter (leaves keep an empty v-treeview-item__level of the same width so icons line up), 12px indent, 12.5px labels.

agency-grid

On an AG Grid host (ag-theme-quartz / -dark). 22px rows, 24px header, same canvas/border tokens as the tree. Set rowHeight / headerHeight on the grid to match — CSS vars alone do not size rows.

Palette is the Vuetify theme in agency-ui/src/theme/agency.ts — background (canvas) and surface (raised sheet). Shared as --agency-wb-canvas / --agency-wb-subtle. Light/dark is the user toggle. Do not add a second hex palette.

Window title bars, AgencyChromeBar headers/footers, explorer list-toolbars, System pane toolbars, Help pane toolbars, and window tabs are all 40px (--agency-chrome-height). Buttons inside windows use --agency-btn-font-size (0.875rem — Image / Speak). Tab labels are 13px with a 2px primary underline. Explorer v-btn height rules must exclude .v-tab. Header UUID / agent face is 26px. The shell app bar is always flat (no drop shadow).

Vuetify 4 emits its component CSS inside @layer vuetify-components, so these unlayered rules win without !important.

Data display

Schema type

Vue component

Role

list

AgencyList

Simple list

table

AgencyTable

Table

tree

AgencyTree

Tree

ag-grid

AgencyAgGrid

AG Grid table

Agents & missions

Schema type

Vue component

Role

agent-explorer

AgencyAgentExplorer

Agent catalog: Filter + namespace list, hideable tabs (Properties, Tools, Executions). Top bar: selected name; Chat then hide-detail.

agent-chat

AgencyAgentChat

Alias of agent-interface (legacy type name)

agent-interface

AgencyAgentInterface

Persistent secretary conversation with the user’s active Agent. Hydrates from REST /api/thread/ and applies Messenger deltas on /channel/. New conversation archives the previous personal Thread. Image attach/drop like agent-test (compose, then Send). A retractable split pane (closed by default) hosts Display previews when Veronica open_window``s a screen. Address: ``secretary. Not agent-test.

agent-test

AgencyAgentTest

Multi-turn test chat on /channel/agent/; optional mic STT + TTS via /api/voice/; TTS uses the agent’s Voice (fallback: user system voice). Speaks forSpeech (no ** / emoji). Vision attach: base64 on the wire and a Photo row under /media/uploads/user-<id>/upload/

agent-status

AgencyAgentStatus

Agent status indicator

task-progress

AgencyTaskProgress

Task progress UI

log

AgencyLog

Simple log panel

mission-explorer

AgencyMissionExplorer

Mission catalog + dispatch; Filter + namespace list, hideable tabs Properties / Prompt / Loop / Executions. Top bar: title; Agent + play then hide-detail.

execution-explorer

AgencyExecutionExplorer

Execution list

execution-view

AgencyExecutionView

Mission Control execution window: chat + collapsible steps + continue turn; HITL via channel overlay

execution-result

AgencyExecutionResult

Stored execution result view

Models & providers

Schema type

Vue component

Role

model-explorer

AgencyModelExplorer

LLM Model catalog

provider-explorer

AgencyProviderExplorer

Provider catalog (kind, key env, sync)

tool-explorer

AgencyToolExplorer

Tool catalog; ids are tools.<module>.<name> grouped by namespace. Same chrome as Photos/Agents/Missions (Filter, hideable detail, footer). Top bar: selected id; Sync from code (icon). Tabs Properties / Help. Help is a read-only <pre> (Python docstring; Sync refreshes).

Corpus / RAG

Schema type

Vue component

Role

document-explorer

AgencyDocumentExplorer

Document catalog

knowledge-search

AgencyKnowledgeSearch

Workspace search / ask UI

document-extraction

AgencyDocumentExtraction

Extraction detail for a document

photo-explorer

AgencyPhotoExplorer

User photo library. Origin select (All / Uploads / Generated) in the chrome; list filter + hideable Image / Data split. Drag a row onto Veronica, Media, or the wallpaper (thumbnail pin).

photo-view

AgencyPhotoView

One photo on the desktop (legacy ephemeral Open; Photos now sends Media)

agency-media

AgencyMediaPlayer

Singleton Media player (images + YouTube). Letterboxed stage; library pane on the right, closed by default. Download on the chrome for the current image. Drop file.image (from the PC) or photo.* (from Photos) onto the window / desktop icon — namespaced via Agency Bus drop routing. Veronica show_media / chat click / Photos → Open in Media.

Staff administration

Schema type

Vue component

Role

user-explorer

AgencyUserExplorer

Staff-only Users explorer. Filter + list left, detail tabs right (Profile, Preferences, Groups). Manage user accounts, preferences, and group assignments. Menu → Configuration → Users (visible only when is_staff=True). Requires /api/users/, /api/users/<id>/prefs/, /api/groups/ staff endpoints. See API.

lobby-chat

AgencyLobbyChat

Ephemeral public lobby room (not a catalog explorer)

Tools / System / shell

Schema type

Vue component

Role

log-stream

AgencyLogStream (Info tab: SystemInfoPane)

System window: Info (sibling collapsibles Versions / Inference / System), Console, Channels, Tasks, Data, Logs (ops SSE: errors, tracebacks, restarts, GPU)

channel-chat

AgencyChannelChat

Channel chat surface

channel-console

AgencyChannelConsole

Raw channel / monitor console

xterm

AgencyXterm

Terminal widget

schema-inspector

AgencySchemaInspector

Inspect current UI schema JSON

user-profile

AgencyUserProfile

Signed-in user window (User · Options · Sites); opened from drawer profile header

options-panel

AgencyOptionsPanel

Options / preferences panel

stage-interface

AgencyStageNav

Helm nav (stage): sit / Home resets the camera. FPS — WASD, Space look, wheel height, Ctrl crouch. No pistol.

camera

AgencyCamera

Local webcam preview + device selector; Ask agent (JPEG frame + prompt) and Portero watch loop over /channel/agent/<id>/ (requires Model.vision)

map

AgencyMap

Operator map: dark Carto Aire basemap, Esri satellite past zoom 13, click-to-fly cursor, optional Satellite split pane (lat/lng/alt)

help

AgencyHelp

Sphinx singlehtml manual (fetch + sanitize, no iframe)

lobby-chat

AgencyLobbyChat

Ephemeral public chat (Lobby). Desktop icon AgencyDesktopLobbyIcon with presence badge; singleton address lobby. Pinia lobbyRoom store connects to /channel/room/lobby/ with reconnect backoff. No local history beyond the live session. See Connections for the socket protocol.

Adding a component

  1. Implement the Vue SFC under agency-ui/src/components/…

  2. Add a TypeScript node type in src/schema/ui.ts if props are typed

  3. Register type → component in src/renderer/registry.ts

  4. Produce nodes from Django / host schema (desktop JSON or dynamic producers)

  5. Publish with npm run build:django / ./dev ui

Do not introduce one-off host Vue pages for Agency desktop surfaces.