UI
Agency’s product UI is a schema-driven SPA: Django (and host apps) describe what the interface means; agency-ui (Vue 3 / Vite) decides how it renders.
Operators use the Agency desktop at / (after /login/). The desktop
is an installable PWA: offline it waits for the server, and a backend restart
reloads the shell. Staff admin sites remain under /admin/, /system/,
/custom/. Mission Control is the Agents / Missions / Executions app on
that desktop (Mission Control).
Three-repo split
Repo |
Role |
|---|---|
agency-ui |
Vue source — schema types, renderer, desktop + Mission Control components |
agency-django |
Domain + REST + Channels; ships published |
agency-server |
Compose, nginx, |
Publish flow:
agency-ui ──npm run build:django──► agency-django/static/agency/ui/
│
▼ collectstatic
nginx /static/ + Django /
Do not hand-edit agency-django/.../static/agency/ui/.
Core principle
Django sends semantic nodes, never Vuetify tags:
{ "type": "progress", "props": { "value": 42, "label": "Indexing" } }
The renderer maps progress → a Vue/Vuetify component. Adding a screen means
a new schema node type + registry entry, not a one-off Django template.
Component catalogue: Frontend components (agency-ui). Envelope and node contracts: UI Schema. Reactive event routing: Agency Bus. Bootstrap / observe from Python: Python: serving the SPA. Useful URLs: Sites.
User preferences & Desktop
Authenticated users have UserPreferences (workspace, UI, operator, system
voice), exposed as GET/PATCH /api/me/prefs/ and injected in bootstrap as
prefs.
UI — light/dark, language (en/es), IANA timezone. Change language in the user window; the page reloads. Timezone is used by
get_datetimewhen a secretary run is bound.RAG — active corpus workspace (Documentos / Buscar). Explorers have no workspace dropdown.
Preferences — active operator agent, system voice (grave OS lines and speaking on behalf of the user). Each Agent has its own
Voice(TTS provider + key); agent chat / mission TTS uses that, falling back to the system voice.Desktop snapshot — open windows,
minimized/maximizedflags, geometryx/y/w/h, chromepose,projection(flat/perspective), and optional childpropsfor ephemeral restore. Debounced PATCH after move / resize / open / close.
Window addresses
Stable ids for dedupe, the Windows drawer, and Desktop persistence:
Singleton (schema app):
agents,documents,system,media,map, …Instance:
kind.ref— e.g.extraction.<uuid>,agent.<uuid>,user.me,execution.<uuid>.
Dot present ⇒ instance window. kind is a window kind (view), not always a
Django model name. Helpers: agency-ui/src/desktop/windowAddress.ts and
openAddress.ts. Legacy win-* ids normalize to this grammar.
Window manager (operator UX)
RuntimeShell drawer: profile header (48px avatar + name) then tabs
Menu · Windows · Inbox. App bar (right): one System icon
(channel / two PCs while idle; REST or telemetry glyph during recent
activity — click opens System). Theme toggle only while windows are
floating. On mobile, and when a desktop window is maximized, the active
window’s minimize / close replace the theme button and the title
moves into the app bar (Agency / {window}). Desktop maximized also
shows restore. The app bar is always flat (no elevation). Mobile has no restore
— minimize is the way back.
Profile — click avatar/name in drawer →
user.mewindow (User · Options · Sites). Options is grouped UI / RAG / Preferences; Sites lists external admin/docs links.Menu — open catalog / tool windows (Agents, Missions, System, …).
Windows — all open windows (desktop and mobile). Click to focus or restore; close button on each row. Badge shows open count.
Inbox — pending HITL questions (agent + text); click opens the reply dialog.
Internationalization
Shell strings use Django gettext (same catalogs as admin). build_bootstrap
activates the user language and embeds locale + messages in
#agency-bootstrap. Preference UserPreferences.language (me/prefs/);
changing language in the user window PATCHes prefs and reloads the page.
Catalog source: agency.ui.i18n; Spanish: agency/locale/es/LC_MESSAGES/django.po.
Vue keeps agency-ui/src/i18n/*.ts only as a Vite dev fallback when bootstrap
has no messages.
Desktop: floating windows over the wallpaper; icons that are not in the drawer Menu (active-agent face, Chat, Tests). Catalog apps open from Menu. Mobile (and desktop maximize): one full-screen window at a time (same store, no floating chrome); title and min/close live in the app bar. Desktop maximize also exposes restore so the window returns to floating geometry; the app bar drops its shadow while that chrome is up.
Window controls: floating title bar has minimize / maximize / close.
Mosaic lives in the drawer tools row.
Maximize uses the same chrome as mobile. Wheel over maximize scales the
window’s CSS 3D pose.scale 5% about the cursor (persisted). Mosaic tiles every open
window — 2D shelf / 3D carousel included — in a CCTV grid (2 = split, 4 = 2×2, 5 = 1+4,
up to 16); the active window takes the featured pane. Minimize from that
chrome returns to the desktop (or the next window). Restore from the app
bar (desktop only) does the same without hiding the window. Double-click
the floating title bar toggles maximize unless noFull / noMax is set.
Staff can inspect or reset a user’s Desktop snapshot from Django admin
User preferences (/admin/ and /system/).
Desktop vs Mission Control
/ is the Agency desktop (icons, windows, drawer). Other apps on the
same shell: Help, Camera, Documents, Displays, Photos, Media, Map, System, …
Mission Control (Menu → Dispatch) is only Agents, Missions, Executions, and the APIs that drive them. Flows: Mission Control. Execution lifecycle: Execution Runtime. WebSockets: Connections.
Development & publish
Task |
Where |
|---|---|
Edit Vue source |
|
Publish dist |
|
Commit dist |
|
Collect static |
|
See DEVELOPMENT.md in each repo. Node ≥ 20.19 for Vite 8.