Appearance
Experience Agent Changelog
3.3
3.3.17 (2026-08-04)
- Add: Profile and Metrics carry a UTC capture
timestampso the Experience Manager can backfill each sample/metric at its true capture time (UC-788) - Add: An application supplying its own
timestamptoPOST /node/capture/must include a UTC offset — naive datetimes are rejected with a 422 rather than shipped as an ambiguous time that the Manager would displace by the Node's offset, and offset-aware values are normalised to UTC (UC-795) - Add: Log application start/stop/failed transitions and kiosk desktop violations as Node Events to the Experience Manager events endpoint (UC-789)
- Improvement: Node registration failure logging names the failing step and includes the endpoint, exception type, and server response body (UC-778)
- Fix: A failed Experience Manager delivery names the exception type and endpoint — httpx raises its transport errors with no message, so these were logging "HTTPError" and nothing else (UC-796)
- Fix: Parallelise on-the-fly image resizing by offloading PyVIPS to a threadpool so concurrent Image API requests no longer serialize on the loop (UC-790)
- Fix: Extend node provisioning and challenge-verify request timeouts from 30s to 300s (HOTFIX)
3.3.16 (2026-07-20)
- Add: Program hot-reload reworked to
ProgramStart/ProgramReady— Agent resolves/hot-loads by nanoid and emitsProgramReady, replacing the XM Update mechanism (UC-696) - Add: Register
PROGRAM_START→ node process andPROGRAM_READY→ MQTT (ack/ipc) routes so pushed Program commands reach the node (UC-696) - Add: Control Gateway protocols for AV Stumpfl Pixera (JSON-RPC/TCP) and LG Display, with length-prefixed TCP framing support (UC-696)
- Add:
ProgramInterfacelets gateway-driven devices receive pushed Program content;ProgramReadyfans out to matching devices (UC-696) - Add: Support
project_fileapp type (e.g. TouchDesigner.toe) with alaunched_byhost-app launcher reference and args (UC-696) - Add: Application
launch_action—launch(managed subprocess),find_process(attach to external process), ordo_nothing(track state only) (UC-739) - Add:
launched_bylauncher resolves and invokes a launcher Application (with[application.exe]substituted), replacing the Web App edge case (UC-740) - Add:
[application.nanoid]launcher-arg token, and[application.exe](renamed from[exe]), for a consistent namespaced launcher-arg contract (UC-764) - Improvement:
ProgramStartroutes via the Application Manager to ensure thelaunched_byapp runs beforeProgramReadyis emitted on completion (UC-696) - Fix:
ProgramReadyno longer loops endlessly — Agent publishes toipc/<node>but no longer subscribes to its own message (UC-696) - Fix:
ControlRequest.devicenow optional so device-less requests deserialise instead of raising aValidationError(UC-696) - Fix:
launched_byapps keep their own args — appended after the launcher args so the template can add or override launcher configuration (UC-764) - Fix: Control Gateway defers protocol connections until the app launches and disconnects on stop; connection failures log as warnings, not errors (HOTFIX)
- Fix: CMS record URL rewriting recurses nested dicts/lists so embedded asset lists are rewritten to the localhost API at any nesting depth (HOTFIX)
- Fix: Windows quit writes the
.atlas_exitsentinel instead ofos.kill, resolving[WinError 5]Access is denied on shutdown (UC-701) - Fix: Guard the Web Wrapper asset endpoint against an unsynced node/host at startup — return 503 instead of an unhandled 500 (UPSWELL-EXPERIENCE-AGENT-8N)
3.3.15 (2026-06-15)
- Add: Cache Programs from the Experience Manager — fetch
program.json, download referenced assets, rewrite S3 URLs to the localhost API, and serve locally at/private/programs/v1/{program}/(UC-696) - Add: Program hot-reload from XM Update — cache the program file and its assets, then dispatch an Ack (UC-696)
- Add: Keyed batch cache tracker so boot and hot-reload caching track completion independently (UC-696)
- Fix: Universal app MIME types now use a hardcoded extension map —
.jsno longer served astext/plainfrom the Windows registry (UC-696) - Fix: Per-item and per-asset URL rewrites during Program caching now guarded so one bad URL can't abort the
program.jsonwrite (UC-696)
3.3.14 (2026-06-12)
- Fix: Univeral application launch logic (HOTFIX)
3.3.13 (2026-06-11)
- Add: PySide6/QML kiosk dashboard showing node identity, live metrics (CPU/memory/disk/GPU), cloud status, alerts, and logs (UC-662)
- Add: Dashboard serves ReDoc API docs at the API root, grouped and alphabetised by tag; ReDoc vendored for offline use (UC-662)
- Add: Log WARNING+ messages to a daily rotating file in the OS log directory with 7-day retention (UC-467)
- Add: Launched apps now honour
layer_methodand surface above the kiosk dashboard viapywinctl(UC-175) - Add:
io.upswell.xagent.ExitMQTT message for clean remote agent shutdown without restart - Add: Launch Pre-installed applications (UC-364)
- Add: Support for Launching Universal (HTML) applications via Kiosk Web Wrapper (UC-448)
- Add: Support for macOS
.applanching, previously failed due to incorrect linking (UC-450) - Add: Add Agent support for Debian based Arm64 systems (UC-453)
- Add: Control Gateway PJLink client for Projector Control (UC-390)
- Fix: Agent
Restartfails due to loss or correct working directory (UC-179) - Fix:
ApplicationStartdoes not launch application after callingApplicationStop(UC-263) - Fix: Error in
get_gpu_load_windows, found duplicate method conflict (UC-336) - Fix:
configfail when~/.sshdirectory missing, order of operations (UC-345) - Fix: Newly downloaded application not marked
readyrequiring a restart (UC-352) - Fix: Application trying to launch before Application marked ready (UC-451)
- Fix: Pre-installed applications not auto-launching (UC-455)
- Fix: Use
certifiwith MQTT to resolve unlinked CA certificates on some OS's (UC-475) - Fix: Agent
io.upswell.xagent.Restartcommand not restarting Agent correctly (UC-476) - Fix: Discard retained MQTT messages on reconnect to prevent stale commands re-executing; fix null token guards in cache workers (UC-476)
- Fix: MQTT exceptions now return an error message to the sender (UC-395)
- Fix: Content Proxy API missing models and records endpoints (UC-610)
- Fix:
NodeProfilelost process list (UC-525) - Fix: Registration Timeout Race Condition (UC-563)
- Fix: Sentry initialised in all subprocesses with node/cluster context tags and release tracking; release registered in CI (UC-667)
- Fix: Kiosk window Z-order on Windows — use foreground promotion instead of
HWND_BOTTOMto cover desktop and taskbar (UC-662) - Fix: Restart no longer fails with
No such commandon Windows —subprocess.Popen/CreateProcesshandles paths with spaces (UC-673) - Fix: Restart and Exit no longer fail with
[WinError 5]on Windows — main process polls for.atlas_restart/.atlas_exitsentinels (UC-673) - Fix: Launched app no longer loads behind the desktop — Win32
AttachThreadInput+BringWindowToTopforce foreground on Windows (UC-671) - Fix: Auto-launch now waits for
ContentCachingCompleteSignalbefore starting; falls back to stale cache if the host is unreachable - Fix: Record URL rewrite now uses collection nanoid instead of UUID when constructing local API paths (UC-670)
- Fix: PySide6 pinned to 6.8.0.2, the latest version available across all target platforms including Debian aarch64/x86_64
- Fix:
Assetmodel now accepts nullwidth/height/aspect_ratioreturned for non-image assets, fixing an asset cache crash (UC-669) - Fix:
queue.put()in cache pagination now awaited — without it the next-page URL was dropped, so only the first page cached (UC-669) - Fix: Asset and record cache requests now use a 60-second timeout — the default 5s caused the XM assets endpoint to time out (UC-669)
- Fix: Cache pagination now queues the correct typed message (
CacheAssetsRequest/CacheRecordsRequest), fixing anAttributeError(UC-669) - Fix: Universal (HTML) apps now launch correctly — detection uses
os: "universal"instead ofapp_type == "html"(UC-693) - Fix: Agent no longer fails to bind port 8002 after restart —
XAGENT_RESTART_NO_LOCKconsumed withpop(); uvicorn retries startup (UC-677) - Fix: Dashboard top-bar clock now has equal right margin matching the left-edge title spacing
- Fix: Handle null token with appropriate HTTP status code (UPSWELL-EXPERIENCE-AGENT-51)
- Fix: Address various Sentry-reported runtime errors (UPSWELL-EXPERIENCE-AGENT-*)
- Maintenance: Replace Pillow (PIL) with PyVIPS for image processing (UC-507)
3.1
3.1.12 (2025-08-12)
- Add: Support for legacy messaging literals
io.upswell.xot.agent.apps.*(UC-348) - Add: Provide MQTT connection details to launched application through environment variabls (UC-351)
- Add: Set previously unset Cluster environment variables (HOTFIX)
- Maintenance: Migrate
Jenkinsfileto us new Atlas CI upload scripts (UC-350)
3.1.8 (2025-07-10)
- Add: Command to replace hostname for existing host instance (HOTFIX)
- Add: Compat with MQTT legacy topic scheme when Cluster broker_legacy_compat is active (UC-325)
3.1.7 (2025-06-25)
- Fix:
keysnot generating a Public Keyid_rsa.pemfile (UC-305) - Fix: GPU profile raises NVML error when NVIDIA graphics card not present (UC-311)
- Fix: System profile value validation for Unknown width/height/DPI
- Remove: Experiemental Websockify support
3.1.6 (2025-06-16)
- Add: Application Metrics capture API for fire-and-forget application metrics (UC-281)
- Add: GPU profiling for NVIDIA Graphics Cards (UC-187)
- Add: New Environment Variables, for running application and node details and new metrics endpoint
- Add: Tailscale 100.100.100.100 endpoint status task
- Add: VNC/TCP to Websocket traffic proxy Websockify for NOVNC support (UC-214)
- Fix:
configthrows error on call to create RSA keys (UC-283) - Fix:
keysdoes not make.sshfolder if it does not exist (UC-247) - Fix:
wmicdeprecated in Windows 11, profile CPU/GPU details are empty (UC-249) - Refactor: Refactor workers to segment by process/responsibility (UC-282)
- Maintenance: Pin pyenv to 3.11.13
3.0
3.0.4 (2025-06-02)
- Hotfix: Node Environment variables not passed to application on launch
3.0.3 (2025-05-13)
- First-release of the new Python based Agent 3.0
- Refactored from Qt to Python
- Added new content and node API proxies
