SLOPSHOPPER

bdb-aos-sessions

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

panecommandprocesstimer
★ 6v5.3.0Apache-2.0updated 2026-10-14hybridlabor-api/aos/plugins/bdb-aos-sessions
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · bdb-aos-sessions
│ ┃ AOS sessions ✕ › fix the failing auth test and add an audit log call │ ┃ aos-sessions not found: install AOS v5 or r… │ ┃ read-only · data from aos-sessions (hub, A2… ⏺ Read(src/auth.ts) │ ⎿ Read 6 lines │ ⏺ Update(src/auth.ts) │ ⎿ Added 2 lines, removed 1 line │ ⏺ Bash(bun test) │ ⎿ 3 pass, 1 fail │ │ ● Done. refresh now rejects expired claims and logs an audit event. │ │ ✻ Worked for 42s · done 4:20 PM │ │ › /aos-sessions │ ⎿ bdb-aos-sessions: aos-sessions pane opened. │ │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · AOS sessions
aos-sessions not found: install AOS v5 or run bin/aos-sessi… read-only · data from aos-sessions (hub, A2A registry, ACP …
README

AOS — BDB Agent OS

Language / Sprache / Idioma: English · Deutsch · Português

AOS — BDB Agent OS

NPM Version NPM Downloads GitHub stars last commit CI license node skills MCPs harnesses SkillSpector skills.sh

agents commands playbooks A2A MCP gateway go-gate

<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%">


Why AOS

Harness defaultWith AOS
SkillsEach 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.
SubagentsAgent 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 safetyA 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 buildsAgents 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.
PlansScroll back through the chat to find what was agreed.Plan Canvas: annotate the plan in a browser, then approve it before any agent builds.
VisibilityRead 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.
SessionsEach 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 codeCoding 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.

What you get

<table> <tr> <td width="33%" valign="top">🎯 <b>Skills</b><br/>270 curated skills in eight categories, discoverable by every harness as <code>&lt;name&gt;/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.


Quick start

I want to...Run
Install for every harness I havenpx -y @hybridlabor-api/aos@latest
Install with low context overheadnpx -y @hybridlabor-api/aos@latest --profile=minimal
Refresh only the gates and hooksnpx -y @hybridlabor-api/aos@latest --hooks-only
See what would change firstnpx -y @hybridlabor-api/aos@latest --dry-run
Check a broken setupaos doctor
Open the local control page (services, catalog, store, plans)aos hub
Browse and add skills and agentsaos store ui
Add the code knowledge graphnpx -y @hybridlabor-api/aos@latest -y --modules=codebase-memory
Plan a feature, then build it/plan, then /startcycle-graph

See it in action

<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>


Skills at a glance

  • /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 escalation
  • The dispatcher invokes the subagents architect, 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 off
  • plan-canvas - local canvas where you annotate elements, chat and approve or request changes
  • plan-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 design
  • bdbmediastorm - brainstorming for live event tech, show control and real-time media
  • /playbooks - list every pb-* playbook with duration, difficulty and requirements, and start one
  • pb-bug-fix - GitHub issue to tested fix and PR; push and PR only after GO
  • pb-ship - triage, review and gate the day's PRs; merge only after GO
  • pb-release-aos - release AOS to npm through the release-please PR
  • pb-show-build - build a show across grandMA3, Resolume and TouchDesigner, offline first
  • pb-offer - draft a client offer priced from your price list; send only after GO
  • factory-collect - Factory: collect and triage feedback, telemetry, errors and issue reports
  • factory-lookback - audit recurring problems across sources for systemic fixes
  • factory-review-prs - review a configured PR queue; approve and merge stay with you
  • factory-human-digest - read-only digest of what still needs a human decision
  • gogate - show or explain the go-gate mode (hard, soft, off) and the time-limited grants; CLI: aos-gogate
  • aos-a2a - list, send to and reply to live harness peers over A2A on localhost
  • master-session - supervise several sessions: roster, status requests, GO board; workers can be spawned through aos-acp
  • mcsc - delegate a task to another installed CLI harness (agy, OpenCode, Codex)
  • agenttrail - live browser map of a multi-agent build; CLI: aos-trail
  • aos-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 memB
  • openwiki-skill - initialize, update and visualize codebase wikis with OpenWiki
  • synapse-integration-skill - BDB Synapse 3D codebase visualizer integration
  • /doctor - check the machine and the current project, print suggested permissions.allow entries, write no settings
  • aos-setup - bring a machine to a complete, verified AOS installation
  • aos-project-init - set up a project folder: slug, wiki, memory, Synapse map, AGENTS.md
  • Godmodes - domain rulebooks
  • godmode-engineering - strict DDD, TypeScript strictness, Clean Architecture, 5-step debugging triage
  • godmode-ui-ux - brand discovery, Anti-Slop rules, DTCG design tokens, fluid motion
  • godmode-eventtech - show-control execution for grandMA3, Resolume, Unreal, Rhino, Vectorworks and Adobe MCP
  • godmode-hardware-pcb - schematics, PCB layout, KiCad and OpenSCAD enclosures with DFM/DRC/ERC sign-off
  • godmode-shipping - final gatekeeper: pre-launch checks, feature-flag rollouts, rollback planning
  • Vendored helpers from BuilderIO/skills
  • read-the-damn-docs - forces a docs pass before coding third-party APIs from memory
  • stay-within-limits - respect 5-hour and weekly usage limits in long or parallel runs
  • quick-recap - end each response with a red/yellow/green status line

Full catalogs (every skill, subagent, playbook and MCP server) are in the collapsible lists under What's included.


What's new in v5

v5 changes how AOS gets onto a machine and how its parts talk to each other.

AreaWhat changed
InstallerRebuilt 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 gatewayaos-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.
A2ALive 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 agentsSubagents 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 modA 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 HubOne 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.
agenttrailOne live map per repo, started automatically, with a link in your session. A v2 control room is in progress.
Plan CanvasPlans open in a local canvas; annotations are dispatched back to the agent.
go-gateRead, 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 Factory35 pb-* playbooks, the nine factory-* skills and plan-arbiter.
Orchestrator chainmaster 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 dispatcher graph

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

Install

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 itemWhat it does
Quick UpdateRefreshes skills, templates, hooks and installed modules to the version you just ran
Run System Checkup / DoctorRuns aos doctor: dependencies, file placement, daemons, hooks
Drop Local Project HarnessCopies the dispatcher contract into the current directory (see below)
Reconfigure SystemChange targets, tier, profile or options
Uninstall AOSRemoves what the installer placed; your data stays

Profiles and options

FlagEffect
--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=minimalSkills, agents and harness rules only. No context-injection hooks, OpenWiki, Token Saver, Codenotch, optional modules, gateway or fleet. The low-context choice.
--profile=fullstandard plus every optional module (same as --modules=all with -y).

| --no-hooks | Skips only the cont

Source 2 files
hooks/register.tsx 216 lines
1import { 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}
216
types/index.d.ts 28 lines
1export 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