Python: serving the SPA ======================= How **agency-django** boots the Agency desktop SPA and pushes live catalog rows. Schema shape: :doc:`schema`. Vue components: :doc:`frontend`. Bootstrap shell --------------- ``agency.views.ui`` renders ``templates/agency/ui/index.html`` with: - Vite manifest → hashed JS/CSS under ``/static/agency/ui/`` - ``#agency-bootstrap`` JSON: ``user``, ``prefs`` (``workspaceId`` + ``desktop``), ``apiBase``, ``websocket``, ``ui`` (desktop document) Product URL: ``/``. Login: ``/login/`` (``mode: login`` bootstrap). The shell is an installable PWA: ``/manifest.webmanifest`` + ``/sw.js`` (scope ``/``). ``/health/`` returns ``boot_id`` / ``ui_build`` so the SPA can reload after a backend restart. ``/offline.html`` is the cached wait screen. Preferences API: ``GET/PATCH /api/me/prefs/``. Window geometry and chrome pose for the session are mirrored into ``prefs.desktop`` (see :doc:`index`). ``agency.ui.pose.parse_pose`` accepts numbers only. Desktop schema -------------- Default desktop layout: ``agency/data/default_desktop.json`` (dock icons, window defs). Window *ids* use the address grammar (``agents``, ``documents``, …). Host apps can extend via their own schema producers; live geometry lives in the frontend ``windowsStore`` and is persisted via user prefs, not in the schema document. Live lists (observe) -------------------- Register a model once:: from agency.channel.observe import observe observe( Execution, resource="execution", card=execution_catalog_card, fetch=lambda pk: Execution.objects.select_related("mission", "agent").get(pk=pk), ) On save/delete → catalog bus envelope on ``/channel/`` (group ``users``) → SPA catalog projector updates explorer lists without polling. Card shape = list serializer fields. Catalog hydrates (agent, mission, tool, model, provider) walk every DRF page (``fetchList``). Default ``PAGE_SIZE`` is 10 — keeping only ``results`` drops rows such as ``tools.tavily.internet_search``. Timelines (executions, tasks) stay paged. To add a resource: 1. Django: ``observe(...)`` + list API 2. agency-ui: ``registerObserveBucket`` in the owning Pinia store 3. No new resource-specific event — same catalog envelope (``..catalog.``) Wire details: :doc:`../../framework/connections`.