AOS sessions viewer: every session of every harness plus the ACP workers


Language / Sprache / Idioma: English · Deutsch · Português
<b>The operating system for AI agent harnesses.</b><br/> One install: the same skills in nine harnesses. Subagents and the hook-enforced GO gate on Claude Code, Antigravity, Codex and OpenCode.
Built for <b>event and media technicians</b>, <b>designers</b> and <b>managers</b>, for <b>builders of custom installations</b> (show control, 3D, PCB and enclosure), and just as much for <b>everyday coding</b> of apps, tools and plugins. The skill library and the MCP servers cover both worlds.
AOS installs a curated skill library, a subagent roster, gate hooks and a runnable multi-agent build pipeline into every coding-agent harness on your machine.
npx -y @hybridlabor-api/aos@latest
<img alt="Claude Code" src="https://img.shields.io/badge/Claude%20Code-D97757?logo=anthropic&logoColor=white"> <img alt="Antigravity" src="https://img.shields.io/badge/Google%20Antigravity-4285F4?logo=google&logoColor=white"> <img alt="Codex CLI" src="https://img.shields.io/badge/Codex%20CLI-412991?logo=openai&logoColor=white"> <img alt="OpenCode" src="https://img.shields.io/badge/OpenCode-111827"> <img alt="Cursor" src="https://img.shields.io/badge/Cursor-000000?logo=cursor&logoColor=white"> <img alt="Windsurf" src="https://img.shields.io/badge/Windsurf-0B100F"> <img alt="Roo Code / Cline" src="https://img.shields.io/badge/Roo%20Code%20%2F%20Cline-5B21B6"> <img alt="Aider" src="https://img.shields.io/badge/Aider-14B814"> <img alt="AOS CLI" src="https://img.shields.io/badge/AOS%20CLI-pi--based-0d1117">
<sub>Recommended: the full installer above. Alternatively, use the skills CLI:</sub>
<table> <tr> <td width="100%" valign="top" align="left"><b>Install skills only</b><br/><br/><code>npx skills add hybridlabor-api/aos</code><br/><br/><sub>Gate hooks and MCP servers require the full installer. Plugin marketplace route is in progress; see <a href="#plugins-and-marketplace">Plugins and marketplace</a>.</sub></td> </tr> </table>
<sub>Skills use the open <a href="https://agentskills.io">Agent Skills</a> format (<code>SKILL.md</code>). AOS installs them for <b>Claude Code, Google Antigravity, Codex CLI, OpenCode, Cursor, Windsurf, Roo Code / Cline, Aider and the AOS CLI</b>, so all of them behave the same way.</sub>
<img src="docs/assets/readme/architecture-hero.svg" alt="How AOS fits together: nine harnesses feed one kernel of 270 skills, 45 subagents, gate hooks and 21 MCP servers, which drives three pipelines, session-to-session messaging and local tools, with the GO gate in front of every release command" width="100%">
| Harness default | With AOS | |
|---|---|---|
| Skills | Each harness has its own skill folder and its own copies. | <!-- count:skills -->270<!-- /count --> skills in eight categories, written as <name>/SKILL.md into every harness you have. One source tree. |
| Subagents | Agent files written by hand, per harness, in that harness's format. | <!-- count:agents -->45<!-- /count --> subagents compiled into each harness's native agent format (Claude Code, Antigravity, Codex, OpenCode only; others use rules in AGENTS.md). |
| Release safety | A rule in a prompt that the agent is asked to respect. | A PreToolUse hook (Claude Code, Antigravity, Codex, OpenCode) or rules in AGENTS.md (others) that blocks git push, npm publish, npm version and recursive rm until your own message is the literal word GO. |
| Multi-agent builds | Agents that call agents, with the routing inside their prompts. | A dispatcher graph: nodes never invoke each other, state is durable, a repair loop has a no-progress guard, escalation goes to you. |
| Plans | Scroll back through the chat to find what was agreed. | Plan Canvas: annotate the plan in a browser, then approve it before any agent builds. |
| Visibility | Read logs in several terminals. | agenttrail live map per repo, and a fleet band in Claude Code with gate mode, token-weather and who waits for your GO. |
| Sessions | Each session is alone in its terminal. | A2A between live Claude Code, OpenCode, agy and Codex sessions on localhost. An inbound message is never a GO. |
| Beyond code | Coding assistants know code. | 19 media-eventtech skills and MCP servers for grandMA3, Resolume, TouchDesigner, Unreal, DaVinci, After Effects, Blender and Rhino; godmode-hardware-pcb for KiCad and OpenSCAD; playbooks for offers, invoices, crew call sheets and event trackers. |
<table> <tr> <td width="33%" valign="top">🎯 <b>Skills</b><br/>270 curated skills in eight categories, discoverable by every harness as <code><name>/SKILL.md</code>.<br/>→ <a href="#skills-at-a-glance">Skills at a glance</a></td> <td width="33%" valign="top">👥 <b>Subagents</b><br/>45 subagents: Architect, TechLead, Reviewer, Godmodes and specialist reviewers.<br/>→ <a href="#the-dispatcher-graph">The dispatcher graph</a></td> <td width="33%" valign="top">🔌 <b>MCP servers</b><br/>21 servers for creative software, OS control, memory and cross-harness delegation.<br/>→ <a href="#mcp-servers">MCP servers</a></td> </tr> <tr> <td width="33%" valign="top">🚀 <b>Pipelines & GO gate</b><br/><code>/startcycle</code>, <code>/startcycle-graph</code>, <code>/startcycle-graph-user</code>, and hook-enforced release gate.<br/>→ <a href="#the-pipelines">The pipelines</a></td> <td width="33%" valign="top">💬 <b>Sessions that talk</b><br/>A2A between Claude Code, OpenCode, agy and Codex sessions on localhost.<br/>→ <a href="#a2a-sessions-that-talk-to-each-other">A2A</a></td> <td width="33%" valign="top">🛠️ <b>Tools</b><br/>Plan Canvas, agenttrail, archify, AOS Store, AOS Hub, aos sessions, fleet band, aos doctor.<br/>→ <a href="#skills-at-a-glance">Tools</a></td> </tr> </table>
<table> <tr> <td width="20%" valign="top"><b>Event & media tech</b><br/>• Live show control: grandMA3, Resolume, TouchDesigner<br/>• Media production: Unreal, DaVinci, After Effects</td> <td width="20%" valign="top"><b>Design</b><br/>• UI/UX design system and brand discovery<br/>• Landing pages, app redesigns, Plan Canvas</td> <td width="20%" valign="top"><b>Management</b><br/>• Offers, invoices, budget tracking<br/>• Crew sheets, event planning, meeting actions</td> <td width="20%" valign="top"><b>Custom builds</b><br/>• PCB design and OpenSCAD enclosures<br/>• 3D assets, Rhino, Blender modeling</td> <td width="20%" valign="top"><b>General dev</b><br/>• Backend, frontend, testing, and shipping<br/>• 45 subagents, three pipelines, library skills</td> </tr> </table>
See Playbooks for guided workflows across these domains.
| I want to... | Run |
|---|---|
| Install for every harness I have | npx -y @hybridlabor-api/aos@latest |
| Install with low context overhead | npx -y @hybridlabor-api/aos@latest --profile=minimal |
| Refresh only the gates and hooks | npx -y @hybridlabor-api/aos@latest --hooks-only |
| See what would change first | npx -y @hybridlabor-api/aos@latest --dry-run |
| Check a broken setup | aos doctor |
| Open the local control page (services, catalog, store, plans) | aos hub |
| Browse and add skills and agents | aos store ui |
| Add the code knowledge graph | npx -y @hybridlabor-api/aos@latest -y --modules=codebase-memory |
| Plan a feature, then build it | /plan, then /startcycle-graph |
<img src="docs/assets/readme/agenttrail-live.gif" alt="agenttrail live plan map of a running multi-agent build" width="100%"><br/> <sub><b>agenttrail.</b> The live map of a multi-agent build while it runs. <a href="docs/assets/readme/agenttrail-live.mp4">▶ Full-quality video</a></sub>
<table> <tr> <td width="50%" valign="top" align="center"> <img src="docs/assets/readme/plan-canvas.png" alt="Plan Canvas with an annotation on a plan element" width="100%"><br/> <sub><b>Plan Canvas.</b> Annotate the plan in the browser, then approve it before any agent builds.</sub> </td> <td width="50%" valign="top" align="center"> <img src="docs/assets/readme/ao-pipeline.png" alt="AO workspace: the AOS Pipeline monitor with plan, gate, build, review and ship stages and the role-to-model routing" width="100%"><br/> <sub><b>AO workspace.</b> The pipeline monitor, plan to ship, with role and model routing per node.</sub> </td> </tr> <tr> <td width="50%" valign="top" align="center"> <img src="docs/assets/readme/aos-store.png" alt="AOS Store web UI: skills, agents and playbooks by scope, category and source" width="100%"><br/> <sub><b>AOS Store.</b> Skills, agents and playbooks on 127.0.0.1:4322.</sub> </td> <td width="50%" valign="top" align="center"> <img src="docs/assets/readme/codenotch-usage.png" alt="Codenotch: agents running and busy per harness, AOS and AO versions" width="100%"><br/> <sub><b>Codenotch.</b> Agents running and busy per harness.</sub> </td> </tr> </table>
<img src="docs/assets/readme/fleet-band.png" alt="Fleet band in Claude Code showing gate mode, context use and sessions with their GO counts" width="100%"><br/> <sub><b>Fleet band.</b> In Claude Code: gate mode, token-weather, and the sessions that wait for your GO.</sub>
<img src="docs/assets/readme/aos-installer.gif" alt="AOS installer: boot animation, pre-flight telemetry and the setup menu" width="100%"><br/> <sub><b>Installer.</b> <code>npx -y @hybridlabor-api/aos@latest</code>: boot, pre-flight telemetry, then the setup menu. <a href="docs/assets/readme/aos-installer.mp4">▶ Full-quality video</a></sub>
/startcycle - linear build pipeline (Architect, TechLead, parallel build, Reviewer) with file hand-offs in production_artifacts//startcycle-graph - dispatcher graph with durable state.json, Reviewer repair loop, quality gate and escalationarchitect, techlead, godmode-ui-ux, godmode-engineering, godmode-media-eventtech, reviewer and godmode-shipping; they never call each other/startcycle-graph-user - throwaway 2-4 node fan-out for any project, nothing persistent left behind/plan - draft, render in a browser canvas, annotate, await approval, then hand offplan-canvas - local canvas where you annotate elements, chat and approve or request changesplan-arbiter - compare competing plans from several agents and produce one recommended plan/bdbrainstorm - multi-agent brainstorm that ends in a hand-off to /startcycle-graph/grill-me - relentless interview to sharpen a plan or designbdbmediastorm - brainstorming for live event tech, show control and real-time media/playbooks - list every pb-* playbook with duration, difficulty and requirements, and start onepb-bug-fix - GitHub issue to tested fix and PR; push and PR only after GOpb-ship - triage, review and gate the day's PRs; merge only after GOpb-release-aos - release AOS to npm through the release-please PRpb-show-build - build a show across grandMA3, Resolume and TouchDesigner, offline firstpb-offer - draft a client offer priced from your price list; send only after GOfactory-collect - Factory: collect and triage feedback, telemetry, errors and issue reportsfactory-lookback - audit recurring problems across sources for systemic fixesfactory-review-prs - review a configured PR queue; approve and merge stay with youfactory-human-digest - read-only digest of what still needs a human decisiongogate - show or explain the go-gate mode (hard, soft, off) and the time-limited grants; CLI: aos-gogateaos-a2a - list, send to and reply to live harness peers over A2A on localhostmaster-session - supervise several sessions: roster, status requests, GO board; workers can be spawned through aos-acpmcsc - delegate a task to another installed CLI harness (agy, OpenCode, Codex)agenttrail - live browser map of a multi-agent build; CLI: aos-trailaos-store - browse, preview and install skills and agents from a local web UI (aos store)memb-skill - local-first long-term memory engine (memB)memb-ingest - ingest project files and conversation logs into memBopenwiki-skill - initialize, update and visualize codebase wikis with OpenWikisynapse-integration-skill - BDB Synapse 3D codebase visualizer integration/doctor - check the machine and the current project, print suggested permissions.allow entries, write no settingsaos-setup - bring a machine to a complete, verified AOS installationaos-project-init - set up a project folder: slug, wiki, memory, Synapse map, AGENTS.mdgodmode-engineering - strict DDD, TypeScript strictness, Clean Architecture, 5-step debugging triagegodmode-ui-ux - brand discovery, Anti-Slop rules, DTCG design tokens, fluid motiongodmode-eventtech - show-control execution for grandMA3, Resolume, Unreal, Rhino, Vectorworks and Adobe MCPgodmode-hardware-pcb - schematics, PCB layout, KiCad and OpenSCAD enclosures with DFM/DRC/ERC sign-offgodmode-shipping - final gatekeeper: pre-launch checks, feature-flag rollouts, rollback planningread-the-damn-docs - forces a docs pass before coding third-party APIs from memorystay-within-limits - respect 5-hour and weekly usage limits in long or parallel runsquick-recap - end each response with a red/yellow/green status lineFull catalogs (every skill, subagent, playbook and MCP server) are in the collapsible lists under What's included.
v5 changes how AOS gets onto a machine and how its parts talk to each other.
| Area | What changed |
|---|---|
| Installer | Rebuilt flow: Kernel, Harnesses, Packages, Optional, Verify. Profiles minimal, standard, full; --no-hooks, --hooks-only, --without=<ids>; repair and uninstall from the manifest; one version check at the start with Update as the default. See Install and docs/install-options.md. |
| MCP gateway | aos-gateway: one local endpoint (1mcp behind a token-checking forwarder) in front of an allow list of shipped servers, aos-gateway adopt for your own stdio servers, and one MCP per app (Blender, Resolume, After Effects). Installed with the default profile; opt out with aos-gateway direct, --without=gateway or --profile=minimal. docs/mcp-gateway.md. |
| A2A | Live Claude Code, OpenCode, agy and Codex sessions message each other with aos-a2a. An inbound message is never a GO. Any MCP-capable harness can join through the aos-a2a MCP server. docs/a2a.md. |
| Native agents | Subagents are compiled into the formats and paths each harness really reads, including OpenCode and agy. No model is pinned unless you set one: docs/agent-models.md. |
| Fleet mod | A band in Claude Code: gate mode, token-weather (context percent as a weather word plus a sparkline), and which sessions work or wait for you with their GO counts. aos-gogate shows gate state read-only. |
| AOS Hub | One local page for everything AOS runs on demand, on 127.0.0.1:7900: Services, Catalog, Store and Plans. aos hub, aos services, aos restart. It replaces the old Launchpad HTTP server; aos-dashboard is now a thin alias. docs/hub.md. |
| agenttrail | One live map per repo, started automatically, with a link in your session. A v2 control room is in progress. |
| Plan Canvas | Plans open in a local canvas; annotations are dispatched back to the agent. |
| go-gate | Read, test and build commands with no write or network effect pass without a GO; deny logs mask credentials; hooks in four harnesses; a machine-wide gate profile (strict, work, off) narrows or widens it. |
| Playbooks and Factory | 35 pb-* playbooks, the nine factory-* skills and plan-arbiter. |
| Orchestrator chain | master session, project orchestrator, package orchestrator, mapped to real mechanisms. |
In progress, not claimed as shipped. agenttrail v2 control room, A2A intercom and a2abook, A2A spawn mode, skill-create and instinct-*.
The graph is harness-neutral and runs on Claude Code's Dynamic Workflows, Antigravity's parallel execution, and any compatible agent harness.
%%{init: {"theme": "base", "themeVariables": {"lineColor": "#6e7681", "edgeLabelBackground": "#f6f1e8", "textColor": "#15171A", "clusterBkg": "#F7F4EC", "clusterBorder": "#B9B5AA", "titleColor": "#15171A", "primaryColor": "#FFFFFF", "primaryBorderColor": "#15171A", "primaryTextColor": "#15171A"}}}%%
flowchart TB
subgraph SG[" "]
direction TB
U(["User"])
A["<b>Architect</b><br/>System Plan"]
T["<b>TechLead</b><br/>Capability Map"]
UX["<b>UI_UX</b><br/>Frontend"]
EN["<b>Engineering</b><br/>Backend"]
ME["<b>Media_EventTech</b><br/>Creative"]
R["<b>Reviewer</b><br/>QA"]
S["<b>Shipping</b><br/>Gate"]
U --> A --> T
T --> UX & EN & ME
UX & EN & ME --> R
R --> S
T -.->|reject| A
R -.->|findings| UX
S -.->|gate fail| EN
R -.->|escalate| U
end
classDef plan fill:#E6F4EA,stroke:#1A7F3C,color:#15171A
classDef build fill:#FFFFFF,stroke:#15171A,color:#15171A
classDef gate fill:#1A7F3C,stroke:#1A7F3C,color:#FFFFFF
classDef human fill:#F7F4EC,stroke:#5B6168,color:#15171A
classDef store fill:#F7F4EC,stroke:#B9B5AA,color:#15171A
linkStyle default stroke:#6e7681,stroke-width:2px
style SG fill:#F7F4EC,stroke:#B9B5AA,color:#15171A
class A,T plan
class UX,EN,ME build
class R,S gate
class U human
Requirements. Node.js >= 20. macOS, Linux and Windows (PowerShell).
npx -y @hybridlabor-api/aos@latest
First run. The installer detects which harnesses are present, asks which to target and which tier (Pro MEDIA or Basic), copies the skills into each harness's skill directory, compiles the subagents, wires the hooks, merges the MCP configuration into each harness's own config file (existing entries are kept), and offers the optional modules listed below.
Every later run opens a menu instead:
| Menu item | What it does |
|---|---|
| Quick Update | Refreshes skills, templates, hooks and installed modules to the version you just ran |
| Run System Checkup / Doctor | Runs aos doctor: dependencies, file placement, daemons, hooks |
| Drop Local Project Harness | Copies the dispatcher contract into the current directory (see below) |
| Reconfigure System | Change targets, tier, profile or options |
| Uninstall AOS | Removes what the installer placed; your data stays |
| Flag | Effect |
|---|---|
--profile=standard (default) | Skills, agents, rules, all hooks, MCPs, OpenWiki, fleet. Token Saver is off by default (use --profile=full to include it); for CLI output compression install rtk yourself, AOS does not install it. |
--profile=minimal | Skills, agents and harness rules only. No context-injection hooks, OpenWiki, Token Saver, Codenotch, optional modules, gateway or fleet. The low-context choice. |
--profile=full | standard plus every optional module (same as --modules=all with -y). |
| --no-hooks | Skips only the cont
hooks/register.tsx 216 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { Overview, SessionRow } from '../types'
5
6const PANE = 'aos-sessions'
7const MAX_ROWS = 200
8const MAX_STR = 80
9const CARD_MAX = 8
10type PaneInput = Parameters<EngineInterface['ui']['resolve']>[0] & { props: { bodyColumns?: number } }
11
12const overviewAtom = atom({ plugin: 'bdb-aos-sessions', key: 'overview' } as const, null as Overview | null)
13const errorAtom = atom({ plugin: 'bdb-aos-sessions', key: 'error' } as const, '')
14const atAtom = atom({ plugin: 'bdb-aos-sessions', key: 'at' } as const, 0)
15
16const cut = (s: unknown): string => (typeof s === 'string' ? s.slice(0, MAX_STR) : '')
17
18function cleanRow(r: Record<string, unknown>): SessionRow {
19 const section = r.section
20 const age = typeof r.ageMs === 'number' && Number.isFinite(r.ageMs) ? r.ageMs : null
21 return {
22 source: cut(r.source),
23 id: cut(r.id),
24 name: cut(r.name),
25 harness: cut(r.harness),
26 state: cut(r.state),
27 section: section === 'needs' || section === 'working' || section === 'idle' || section === 'acp' || section === 'dead' ? section : 'idle',
28 detail: cut(r.detail),
29 ageMs: age,
30 }
31}
32
33export function parseOverview(text: string): Overview | null {
34 let parsed: Record<string, unknown>
35 try {
36 parsed = JSON.parse(text)
37 } catch {
38 return null
39 }
40 if (!parsed || typeof parsed !== 'object') return null
41 if (!Array.isArray(parsed.sessions) || !Array.isArray(parsed.acp)) return null
42 const hub = parsed.hub === 'running' ? 'running' : 'down'
43 const now = typeof parsed.now === 'number' ? String(parsed.now) : cut(parsed.now)
44 const sessions = (parsed.sessions as unknown[]).slice(0, MAX_ROWS).map(r => cleanRow((r ?? {}) as Record<string, unknown>))
45 const acp = (parsed.acp as unknown[]).slice(0, MAX_ROWS).map(r => cleanRow((r ?? {}) as Record<string, unknown>))
46 return { now, hub, sessions, acp }
47}
48
49export function sectionCounts(o: Overview) {
50 const needs = o.sessions.filter(s => s.section === 'needs').length
51 const working = o.sessions.filter(s => s.section === 'working').length
52 const idle = o.sessions.filter(s => s.section === 'idle').length
53 const running = o.acp.filter(s => s.state === 'running').length
54 const stalled = o.acp.filter(s => s.state === 'stalled').length
55 const done = o.acp.filter(s => s.state === 'done').length
56 const go = o.acp.filter(s => /go/i.test(s.state) || /go/i.test(s.detail)).length
57 return { needs, working, idle, acp: o.acp.length, running, stalled, done, go }
58}
59
60export function ageLabel(ms: number | null): string {
61 if (ms === null || ms === undefined) return '—'
62 if (ms < 5000) return 'now'
63 const s = Math.floor(ms / 1000)
64 if (s < 60) return `${s}s`
65 const m = Math.floor(s / 60)
66 if (m < 60) return `${m}m`
67 return `${Math.floor(m / 60)}h`
68}
69
70export function harnessLabel(h: string): string {
71 return /kimi/i.test(h) ? 'kimi (via trail)' : h
72}
73
74export function demoOverview(): Overview {
75 return {
76 now: 'demo',
77 hub: 'running',
78 sessions: [
79 { source: 'demo', id: 'demo-orchestrator', name: 'demo-orchestrator', harness: 'claude', state: 'waiting', section: 'needs', detail: 'waiting for a GO', ageMs: 40000 },
80 { source: 'demo', id: 'demo-web', name: 'demo-web', harness: 'codex', state: 'working', section: 'working', detail: 'building', ageMs: 240000 },
81 { source: 'demo', id: 'demo-api', name: 'demo-api', harness: 'kimi', state: 'idle', section: 'idle', detail: 'idle', ageMs: 10800000 },
82 ],
83 acp: [
84 { source: 'acp', id: 'demo-glm-1', name: 'demo-glm-1', harness: 'agy', state: 'running', section: 'acp', detail: 'running', ageMs: 60000 },
85 { source: 'acp', id: 'demo-glm-2', name: 'demo-glm-2', harness: 'opencode', state: 'GO needed', section: 'acp', detail: 'GO needed', ageMs: 120000 },
86 ],
87 }
88}
89
90export async function loadOverview($: EngineInterface): Promise<void> {
91 try {
92 if ((await $.env.get('AOS_FLEET_DEMO')) === '1') {
93 const nowMs = await $.clock.now()
94 await update($, overviewAtom, () => demoOverview())
95 await update($, errorAtom, () => '')
96 await update($, atAtom, () => nowMs)
97 return
98 }
99 const home = await $.env.get('HOME')
100 const attempts: string[][] = [[ 'node', `${home}/.agents/bin/aos-sessions.mjs`, '--json' ], ['aos-sessions', '--json']]
101 for (const args of attempts) {
102 try {
103 const r = await $.process.run(args)
104 if (r.exitCode !== 0) continue
105 const parsed = parseOverview(r.stdout)
106 if (!parsed) continue
107 await update($, overviewAtom, () => parsed)
108 await update($, errorAtom, () => '')
109 await update($, atAtom, () => Date.now())
110 return
111 } catch {
112 continue
113 }
114 }
115 await update($, overviewAtom, () => null)
116 await update($, errorAtom, () => 'aos-sessions not found: install AOS v5 or run bin/aos-sessions.mjs')
117 await update($, atAtom, () => Date.now())
118 } catch {
119 await update($, overviewAtom, () => null)
120 await update($, errorAtom, () => 'aos-sessions not found: install AOS v5 or run bin/aos-sessions.mjs')
121 }
122}
123
124let timerOn = false
125
126export const register: Register = registerHook => {
127 registerHook('session.start', async ($, e, next) => {
128 const result = await next(e)
129 await $.command.register({ name: 'aos-sessions', description: 'Show all sessions and ACP workers' })
130 return result
131 })
132
133 registerHook('command.run', { command: 'aos-sessions' }, async $ => {
134 await loadOverview($)
135 if (!timerOn) {
136 timerOn = true
137 $.clock.every(10_000, () => void loadOverview($).catch(() => undefined))
138 }
139 await $.ui.open({ id: PANE, title: 'AOS sessions' })
140 return { text: 'aos-sessions pane opened.' }
141 })
142
143 registerHook('ui.render', { component: 'Pane', requestId: PANE }, async ($, e: PaneInput) => {
144 const ui = $.ui.resolve(e)
145 const { Box, Text } = ui
146 const err = await read($, errorAtom)
147 const o = await read($, overviewAtom)
148 if (err || !o) {
149 return (
150 <Box flexDirection="column">
151 <Text dimColor color="yellow" wrap="truncate-end">{err || 'no data yet'}</Text>
152 <Text dimColor wrap="truncate-end">read-only · data from aos-sessions (hub, A2A registry, ACP logs)</Text>
153 </Box>
154 )
155 }
156 const counts = sectionCounts(o)
157 const active = o.sessions.length
158 const acpTitle = `ACP WORKERS running ${counts.running} · stalled ${counts.stalled} · done ${counts.done}`
159 const fit = (s: string, n: number) => (s.length > n ? s.slice(0, n - 1) + '…' : s)
160 const renderRow = (r: SessionRow, glyph: string, color: string, key: string) => (
161 <Box key={key} flexDirection="row" justifyContent="space-between">
162 <Box key={`${key}-l`} flexDirection="row">
163 <Text key={`${key}-g`} color={color} wrap="truncate-end">{glyph} </Text>
164 <Text key={`${key}-h`} dimColor wrap="truncate-end">{harnessLabel(r.harness).padEnd(16).slice(0, 16)} </Text>
165 <Text key={`${key}-n`} bold wrap="truncate-end">{r.name} </Text>
166 <Text key={`${key}-d`} dimColor wrap="truncate-end">{fit(r.detail, 40)}</Text>
167 </Box>
168 <Text key={`${key}-a`} dimColor wrap="truncate-end">{ageLabel(r.ageMs)}</Text>
169 </Box>
170 )
171 const card = (title: string, borderColor: string, key: string, rows: SessionRow[], glyph: string, color: string, acpMode = false) => {
172 const shown = rows.slice(0, CARD_MAX)
173 const more = rows.length - shown.length
174 return (
175 <Box key={key} flexDirection="column" borderStyle="round" borderColor={borderColor} paddingX={1} marginBottom={1}>
176 <Text key={`${key}-t`} bold wrap="truncate-end">{title}</Text>
177 {shown.length === 0 ? (
178 <Text key={`${key}-none`} dimColor wrap="truncate-end">none</Text>
179 ) : acpMode ? (
180 shown.map(r => {
181 const g = r.state === 'running' ? { glyph: '●', color: 'green' } : /go/i.test(r.state) || /go/i.test(r.detail) ? { glyph: '▲', color: 'yellow' } : r.state === 'stalled' ? { glyph: '◌', color: 'gray' } : { glyph: '✓', color: 'gray' }
182 return renderRow(r, g.glyph, g.color, `${key}-${r.id}`)
183 })
184 ) : (
185 shown.map(r => renderRow(r, glyph, color, `${key}-${r.id}`))
186 )}
187 {more > 0 && <Text key={`${key}-more`} dimColor wrap="truncate-end">+{more} more</Text>}
188 </Box>
189 )
190 }
191 const needs = card('NEEDS YOU', 'yellow', 'needs', o.sessions.filter(s => s.section === 'needs'), '▲', 'yellow')
192 const working = card('WORKING', 'green', 'working', o.sessions.filter(s => s.section === 'working'), '●', 'green')
193 const idle = card('IDLE', 'gray', 'idle', o.sessions.filter(s => s.section === 'idle'), '○', 'gray')
194 const acp = card(acpTitle, 'blue', 'acp', o.acp, '●', 'blue', true)
195 const wide = (e.props.bodyColumns ?? 80) >= 96
196 const body = wide ? (
197 <Box key="cols" flexDirection="row">
198 <Box key="col-left" flexGrow={1} flexDirection="column">{needs}{working}</Box>
199 <Box key="col-right" flexGrow={1} flexDirection="column">{idle}{acp}</Box>
200 </Box>
201 ) : (
202 <Box key="stack" flexDirection="column">{needs}{working}{idle}{acp}</Box>
203 )
204 return (
205 <Box flexDirection="column">
206 <Box key="head" flexDirection="row" justifyContent="space-between">
207 <Text key="title" bold wrap="truncate-end">SESSIONS</Text>
208 <Text key="sub" dimColor wrap="truncate-end">{active} active · hub {o.hub}</Text>
209 </Box>
210 {body}
211 <Text dimColor wrap="truncate-end">read-only · data from aos-sessions (hub, A2A registry, ACP logs)</Text>
212 </Box>
213 )
214 })
215}
216types/index.d.ts 28 lines1export type SessionRow = {
2 source: string
3 id: string
4 name: string
5 harness: string
6 state: string
7 section: 'needs' | 'working' | 'idle' | 'acp' | 'dead'
8 detail: string
9 ageMs: number | null
10}
11
12export type Overview = {
13 now: string
14 hub: 'running' | 'down'
15 sessions: SessionRow[]
16 acp: SessionRow[]
17}
18
19declare module 'claude-code' {
20 interface PluginState {
21 'bdb-aos-sessions': {
22 overview: Overview | null
23 error: string
24 at: number
25 }
26 }
27}
28