Summary
Matrix3D office page (src/screens/matrix3d/) currently derives agent activity by polling each Hermes profile's state.db directly via a Python subprocess every 4s from the SwitchUI server (src/routes/api/crew-status.ts). This is schema-coupled, brittle, has no real-time fidelity, and lacks true delegation identity.
Replace it with a push-based consumer once the gateway exposes a global activity feed.
Blocked on: Interstellar-code/hermes-agent#132 (Phase A — gateway matrix-activity plugin: WS /api/activity + GET /api/activity/recent).
Work
- Open ONE WebSocket to
/api/activity via the existing /ws-hermes proxy pattern. Drive the office state machine from typed events:
subagent_start → character walks to desk, speech bubble = the actual child_goal.
tool.start / tool.complete → desk monitor content.
subagent_stop → character walks away / returns to idle.
on_session_start / on_session_end → main-agent (HERMES) presence.
- Seed initial state from
GET /api/profiles/sessions (cross-profile list, server-computed is_active, each row tagged with profile) — replaces the per-profile sqlite reads for first paint.
- Delete the SwitchUI-side Python subprocess sqlite reader in
src/routes/api/crew-status.ts (the readCrewOwnActivity / readDelegatedChildSessions embedded-Python paths) and the 4s polling plumbing in use-matrix3d-office-data.ts.
- Keep
src/lib/crew-delegation.ts assignment logic only if still needed for avatar mapping; the gateway now provides real subagent_id/role, so most of the heuristic assignment can be retired.
Context
Current interim state (already landed, uncommitted at time of writing): crew-status reads each profile's own state.db for ground-truth recency + lists active delegated child sessions from the hermes-switch db, with a pure assignDelegatedSessions avatar mapper. That was the stopgap to fix desync; this issue is the proper push-based replacement.
Prior root-cause analysis: the three legacy "working" signals (gateway ?profile= filtering, keyword-guessed delegation, name-fuzzy matching) were all dead — see session notes. delegate_task args carry no agent identity, which is exactly why Phase A surfaces subagent_start/subagent_stop hook payloads (parent_session_id, child_session_id, child_role, child_goal).
Acceptance
- Matrix3D drives all character animation from the
/api/activity WebSocket; no sqlite subprocess remains.
- Delegating a task lights up the correct worker character with the real goal text in its bubble within one event round-trip (not a 4s poll).
- Reconnect re-seeds from
/api/activity/recent + /api/profiles/sessions.
Summary
Matrix3D office page (
src/screens/matrix3d/) currently derives agent activity by polling each Hermes profile'sstate.dbdirectly via a Python subprocess every 4s from the SwitchUI server (src/routes/api/crew-status.ts). This is schema-coupled, brittle, has no real-time fidelity, and lacks true delegation identity.Replace it with a push-based consumer once the gateway exposes a global activity feed.
Blocked on: Interstellar-code/hermes-agent#132 (Phase A — gateway
matrix-activityplugin:WS /api/activity+GET /api/activity/recent).Work
/api/activityvia the existing/ws-hermesproxy pattern. Drive the office state machine from typed events:subagent_start→ character walks to desk, speech bubble = the actualchild_goal.tool.start/tool.complete→ desk monitor content.subagent_stop→ character walks away / returns to idle.on_session_start/on_session_end→ main-agent (HERMES) presence.GET /api/profiles/sessions(cross-profile list, server-computedis_active, each row tagged withprofile) — replaces the per-profile sqlite reads for first paint.src/routes/api/crew-status.ts(thereadCrewOwnActivity/readDelegatedChildSessionsembedded-Python paths) and the 4s polling plumbing inuse-matrix3d-office-data.ts.src/lib/crew-delegation.tsassignment logic only if still needed for avatar mapping; the gateway now provides realsubagent_id/role, so most of the heuristic assignment can be retired.Context
Current interim state (already landed, uncommitted at time of writing): crew-status reads each profile's own
state.dbfor ground-truth recency + lists active delegated child sessions from the hermes-switch db, with a pureassignDelegatedSessionsavatar mapper. That was the stopgap to fix desync; this issue is the proper push-based replacement.Prior root-cause analysis: the three legacy "working" signals (gateway
?profile=filtering, keyword-guessed delegation, name-fuzzy matching) were all dead — see session notes.delegate_taskargs carry no agent identity, which is exactly why Phase A surfacessubagent_start/subagent_stophook payloads (parent_session_id,child_session_id,child_role,child_goal).Acceptance
/api/activityWebSocket; no sqlite subprocess remains./api/activity/recent+/api/profiles/sessions.