Q9 · dashboard design

# A control surface for ephemeral & persistent agents — organized by Teams, one merged chat.

Agents live in Teams (multi-membership allowed). The sidebar lets you check exactly which ones’ chatter you want to see — the main pane is always a single merged stream, filtered live. Clicking a sender opens its profile; clicking the eye in the sidebar enters Watch mode for that agent. `@`-mention a recipe to trigger a run.

01

## The dashboard

# market reports · 2 of 3 selected clear filter

sammons triggered m-7d3a…91
14:18
market-report-lead → sammons 14:18
Worktree ready. Fanning out to news-sentinel + tech-analyst + macro-analyst for sector inputs.
news-sentinel → market-report-lead 14:19
48 headlines classified. Net sentiment `+0.34` · semi caps softening · energy crowded long.

    {
      "sectors": { "tech": 0.6, "energy": -0.2 },
      "asymmetry_flag": true
    }

Persistent agent
market-report-lead
state● active teams market reports, research address agent:market-report-lead last seen just now
market-report-lead → news-sentinel 14:20
Ack. Holding for tech-analyst price/volume confluence — Kelly sizing will key off both.
@market-report-lead any update on the macro snapshot — VIX cluster?
Sends to market-report-lead
02

## Agents · management

# Agents

14 total · 4 ephemeral · 3 running · 1 failed
All 14 Ephemeral 4 Persistent 10 Running 3 Failed 1 No team 2
codex-reviewer persistent no team failed
aws-account-lead ephemeral infrastructure 3 running
stripe-refund-lead ephemeral commerce 2 queued
ci-watcher persistent infrastructure active
gitea-lead persistent infrastructure active
market-report-lead persistent market reports research active
aws-account-monitor persistent infrastructure paired
deploy-prod-lead ephemeral infrastructure idle
notion-sync persistent cleanup idle
orchestrator-watch persistent infrastructure idle
test-echo ephemeral no team idle
03

## Watch · remote operator console

Back to agents
Watching / market-report-lead

# market-report-lead active

Live · last 1.4s ago
$ cd /var/agentic/work/market-report-lead $ ./scripts/fan-out.sh --week 2026-w20 [14:18:04] dispatch news-sentinel → topic:research/headlines [14:18:04] dispatch tech-analyst → topic:research/tech [14:18:04] dispatch macro-analyst → topic:research/macro [14:18:04] dispatch correlation-analyst → topic:research/correlation [14:18:04] dispatch sector-strategist → topic:research/sectors [14:18:04] dispatch risk-architect → topic:research/risk [14:18:04] dispatch momentum-strategist → topic:research/momentum [14:18:04] dispatch tax-optimizer → topic:research/tax [14:18:04] dispatch position-sizer → topic:research/position [14:18:04] dispatch scenario-engineer → topic:research/scenarios ✓ 10/10 specialist runs spawned (queue depths: 0 each) [14:19:12] news-sentinel.complete · 48 headlines · sentiment +0.34 [14:19:48] macro-analyst.complete · VIX 14.2 · credit spreads tight · rates flat [14:20:31] tech-analyst.complete · price/volume confluence: 6 names [14:21:09] correlation-analyst.complete · ρ-matrix updated · 2 regime shifts [14:21:42] sector-strategist.complete · rotation: energy → semis [14:22:18] risk-architect.warning · var(95)=2.1% breaches Kelly cap [14:22:51] momentum-strategist.complete · trend-strength ranks updated [14:23:17] scenario-engineer.complete · 1000 paths · 14d horizon [14:23:42] waiting on: tax-optimizer, position-sizer (median 4m21s · p95 11m02s) [14:23:45] position-sizer.complete · drift tolerance ±0.8% · 4 rebalances [14:24:01] tax-optimizer.complete · 3 harvest candidates · no wash-sale risk $ ./scripts/synthesize.sh [14:24:08] grounder fanning out for citation pass: ground=12 sources [14:24:24] rendering HTML report → reports/2026-w20.html [14:24:31] report ready · 14 sections · 47kb · awaiting your review $
04

## Approvals · inbox + review

## Approvals 47 · 3 pending

Channel All 47 aws-account-provision 14 stripe-refund 22 deploy-prod 11
State Pending 3 Approved 31 Rejected 9 Amended 4
Pending 3
a3f1…8b
aws-account-provision
from gitea-lead
2m
b7c2…1d
stripe-refund
from agent:billing
8m
c4e5…9a
deploy-prod
from sammons
34m
Recent 7d · 44
d8f6…2c
aws-account-provision
approved · gitea-lead
1h
e2a3…7e
stripe-refund
rejected · agent:billing
3h
aa11…7f
deploy-prod
amended · sammons
8h
f1b9…4d
aws-account-provision
approved · gitea-lead
6h
bc22…48
stripe-refund
approved · agent:billing
1d
47 total · 3 pending · median TTA 4m12s
aws-account-provision / request from gitea-lead
a3f1…8b ● pending
Requester gitea-lead Created 14:23:11 · 2m ago Updated—
Payload application/json
1{ 2 "region": "us-east-1", 3 "purpose": "staging environment for q3-features", 4 "budget_usd_per_month": 250, 5 "auto_teardown_days": 14, 6 "tags": { 7 "team": "platform", 8 "cost_center": "eng-infra", 9 "requested_by": "sammons@infinity-loop.dev" 10 } 11}
Timeline

- 14:23:11 Created by gitea-lead
- — Awaiting decision — no further events.

Decision
Decided by sammons
04·a

## Amend modal

aws-account-provision / request from gitea-lead
a3f1…8b ● pending
Payload
1{ 2 "region": "us-east-1"… 3 "budget": 250 4}
Amend approvala3f1…8b
Submitting an amend transitions the state to amended and records a new payload version. A payload is required — the right side is what you’re changing.
Original · v1 read-only
1 {
2 "region": "us-east-1",
3 "purpose": "staging environment",
4− "budget_usd_per_month": 250,
5 "auto_teardown_days": 14,
6 "tags": { … }
7 }
Amended · v2 edit me
1 {
2 "region": "us-east-1",
3 "purpose": "staging environment",
4+ "budget_usd_per_month": 100,
5+ "budget_alert_pct": 80,
6 "auto_teardown_days": 14,
7 "tags": { … }
8 }
Note to requester · optional
`⌘` `↵` submit · `esc` cancel
05

## Reminders · per-agent nudge queues

Reminders

# market reports · 2 of 3 selected clear filter

1 reminder · 1 firing · 0 dormant · next delivery in 37m
Recurring prompts pasted into an agent’s tmux session on a cadence until marked done. Each reminder fires independently. Filter by checking agents in the sidebar — same filter as the chat. Also addable via `collab reminder add`.
Next delivery in 37m · to market-report-lead
› Update report.md with the daily summary — top 5 movers + sentiment shift + any breaking news that hit during the trading window.
every 60m · last 23m ago · 12 deliveries · by sammons
Deliveries · last 24h
12 total · across 1 reminder in filter
−22
−16
−10
−4
now
Pick agent… ▾ every 30m ▾
skip if active
market-report-lead ephemeral active 1 reminder·next in 37m
Update report.md with the daily summary — top 5 movers + sentiment shift + any breaking news that hit during the trading window.
every 60m · last 23m ago · next in 37m · 12 deliveries · by sammons
news-sentinel persistent active 0 reminders·no nudges set
None yet — add one above or via `collab reminder add news-sentinel "<prompt>" --cadence 30m`.
Recently completed last 7d · 0 in filter
No completed reminders for these agents in the last 7d. Clear the filter to see the full history.
1 reminder firing · 0 dormant · 0 completed last 7d (in filter) · 23 hidden by filter
06

## Settings · engine configs, prefs, surfaces, destinations

# Settings

4 engine configs · 2 preferences · 3 pages · 2 data stores · 1 destination
Engine defaults applied to agents, client-side preferences for this device, published page surfaces, agent-writable data stores, and outbound destinations for notifications.

### Engine configs

YAML frontmatter defaults

Each engine config defines default frontmatter for agents that opt in. Agent-level frontmatter overrides these defaults. Hooks, indicators, detection, custom buttons, and env are all configurable here.

claude engine: claude default for 8 agents
model sonnet · thinking high · hooks start · resume · compact · exit · interrupt · reload · submit
indicators build-running · test-failed · waiting-input · detection enabled · custom buttons 2 · env 1
1 engine: claude 2 model: sonnet 3 thinking: high 4 permissions: write 5 6 start: 7 - shell: claude --print --resume-if-exists 8 - wait: 3000 9 - keystroke: Enter 10 11 indicators: 12 build-running: 13 regex: 'Compiling…|building' 14 badge: build 15 style: running 16 17 detection: 18 idleThreshold: 30000 19 autoRecover: true 20 21 env: 22 ANTHROPIC_LOG: warn
claude-fast engine: claude default for 2 agents
model haiku · thinking off · hooks start · exit · indicators none
codex engine: codex default for 3 agents
model gpt-5 · hooks start · resume · exit · detection enabled
opencode engine: opencode default for 1 agent
engine: opencode model: claude-3-5-sonnet start: - shell: opencode - wait: 2000 detection: idleThreshold: 25000 autoRecover: true
Editing YAML — saves to `engine_configs.opencode` `⌘``S` save · `esc` cancel

### Preferences

this device · localStorage

Saved per-browser. Not synced to the orchestrator.

Submit mode How the composer Send button is bound to your keyboard.
Cmd / Ctrl + Enter Enter
Close keyboard on send iOS only — dismisses the on-screen keyboard after submitting.
Enabled

### Published pages

static surfaces served at `/pages/<slug>`

Agents publish directories via `collab publish <slug> <dir>`. Each page is a snapshot at publish time.

pulsar-staging-summary page
12 files · 1.2 MB · published by gitea-lead · 2h ago
design-mock-q9 page
4 files · 47 KB · published by sammons · 5d ago
market-2026-q1 page
28 files · 480 KB · published by market-report-lead · 18h ago

### Data stores

agent-writable key-value

Agents create stores via `collab store create <name>`. Storage is shared across agents on the same orchestrator instance.

pulsar-runs store
142 keys · updated 14m ago · owner ci-watcher
refund-ledger store
38 keys · updated yesterday · owner stripe-refund-lead

### Destinations

outbound channels

Agents can send messages to external destinations. Currently only Telegram is supported.

my-telegram telegram enabled
chat −1001234567890 · token 123456:ABC-••• · updated 3d ago
New Telegram destination
Name
Bot token
Chat ID
Create a bot via `@BotFather` on Telegram to get a token. Send the bot a message, then call `https://api.telegram.org/bot<token>/getUpdates` to find the chat ID.
07

## Search · global · agents · messages · approvals · reminders · pages

Search 9 results · across 5 types · scope: all 14 agents `⌘``K` from anywhere
All 9 Agents 1 Messages 4 Approvals 2 Reminders 1 Pages 1 Settings 0
Agents 1
deploy-watcher persistent idle
Watches deployment pipelines and reports status. Sends a paste to the team channel when a deploy succeeds or fails.
matched in name, persona · no team · last active 6h ago
↵
Messages 4
sammons → ci-watcher 14:30 today
yeah let’s verify CI is green before we deploying this. holding on the prod push until the flaky tests pass twice.
↵
aws-account-lead → sammons 13:15 today
deploy is queued, awaiting approval on the staging budget bump. I’ll hold the worktree until you respond on a3f1…8b.
↵
sammons → market-report-lead yesterday 18:22
after deploy completes, kick the daily report — should be safe to start at 19:00 if the rollout is clean.
↵
ci-watcher → sammons 2d ago
deploy-prod completed successfully · 4m 12s · no rollback. All checks green.
↵
Approvals 2
bc4a…91 channel: deploy-prod ● pending
› "target": "prod-us-east", "sha": "a7f3b9c", "strategy": "rolling"
requested by sammons · created 34m ago · matched in channel
↵
aa11…7f channel: deploy-prod ● amended
› amended to drop strategy from "blue-green" to "rolling"; note: capacity headroom
by sammons · 8h ago · matched in channel, payload
↵
Reminders 1
to deploy-watcher completed yesterday
› Stop polling the deploy-prod queue — the maintenance window is over.
every 5m · 38 deliveries before complete · by sammons · matched in prompt, agent name
↵
Pages 1
deploy-runbook page
… a clean deploy typically follows the rolling strategy. If the maintenance window includes a database migration, schedule the deploy after the read replica has caught up.
12 files · 1.4 MB · published by gitea-lead · matched in slug, 3 files
↵
`↑``↓` navigate `↵` open `⌘``↵` open in new pane `tab` scope chip `esc` clear / close Scope follows sidebar — uncheck agents to narrow results.
08

## Overlays · modals + popovers

08·a

## + New agent · modal

# Agents

14 total · 4 ephemeral · 3 running
+ New agent creates a persistent agent or ephemeral recipe
Kind
Persistent agent long-lived
One process, one tmux session. Responds to direct messages and lives until you stop it.
Ephemeral recipe template
A template that fans out one-shot instances when `@`-mentioned in chat. Each instance gets its own worktree.
Identity
Name
Lowercase, kebab-case. Will be the agent’s address: `agent:gitea-lead`.
Engine config
Model override
cwd
Ephemeral recipe shown only when kind = ephemeral
cwd base
Topics
aws-account-provision × deploy-prod ×
Prepare hook git worktree add "$WORKTREE" "$BRANCH" cd "$WORKTREE" && npm install --no-audit --no-fund
Cleanup hook git worktree remove --force "$WORKTREE"
Teams
infrastructure 4 commerce 2 cleanup 2 market reports 3
An agent can be in multiple teams. Teams are UI-only filters for chat, reminders, and search.
Persona body markdown · system prompt
You are gitea-lead, an agent that manages release coordination through Gitea. Your responsibilities: - Reviewing pull requests for the release branch - Coordinating with deploy-watcher on staging promotions - Posting release notes summaries to the team channel When uncertain, ask sammons via the chat composer before taking destructive actions.
`⌘` `↵` create · `esc` cancel
08·b

## + New team · modal

# All agents· all 14 selected

+ New team UI-only grouping · no kernel behavior
Name
Members
Pick agents to include. Members can belong to more than one team.
ci-watcher per
deploy-watcher per
orchestrator-watch per
gitea-lead eph
aws-account-lead eph
market-report-lead eph
news-sentinel per
tech-analyst per
3 selected · 11 more available
08·c

## Edit persona · modal

# gitea-lead running

Edit persona gitea-lead · ephemeral · `persistent-agents/gitea-lead.md`
Frontmatter YAML · saved on submit
engine: claude model: sonnet thinking: high cwd: /Users/sammons/Desktop/gitea-lead cwd_base: /tmp/agent-worktrees topics: - aws-account-provision - deploy-prod prepare: - shell: git worktree add "$WORKTREE" "$BRANCH" - shell: cd "$WORKTREE" && npm install --no-audit cleanup: - shell: git worktree remove --force "$WORKTREE" indicators: pr-ready: regex: 'opened PR #\d+' badge: pr style: ok
Body Markdown · system prompt
You are gitea-lead, an agent that manages release coordination through Gitea. ## Responsibilities - Reviewing pull requests for the release branch - Coordinating with deploy-watcher on staging promotions - Posting release notes summaries to the team channel - Flagging PRs that are stale ( >3 days without review) ## Behavior - When uncertain, ask sammons via the chat composer before taking destructive actions. - Always commit through the worktree path provided in `$WORKTREE`. - Prefer small, scoped commits with conventional-commit subjects. ## Communication - Address other agents by their kebab-case name. - Open approvals on the `deploy-prod` channel for any prod rollout.
Reload persona on save Replaces the running tmux session — drains the active message queue first.
08·d

## Profile popover · anchored on sender click

# All agents· all 14 selected

market-report-lead → sammons · 14:18
Daily summary published. Top movers: AAPL +2.1%, NVDA −1.4%. Sentiment slightly bearish on chips.
gitea-lead → sammons · 14:24
opened PR #142 — release v2.7 candidate. CI is green. ready when you are.
gitea-lead ephemeral
running · 3 instances
Address `agent:gitea-lead`
Teams infrastructure reliability
Activity 8 messages today · last 4m ago
3 reminders firing
Triggered by sammons · 47m ago
Watching w
Filter chat to just this f
Copy address c
Open in tmux t
Edit persona…
More…
ci-watcher → sammons · 14:30
deploy-prod completed successfully · 4m 12s · no rollback. All checks green.
09

## Components

02·a
Teams & filter
market reports 3
market-report-lead
news-sentinel
tech-analyst
02·b
Agent profile (click sender)
Ephemeral recipe
/aws-account-lead
state 3 running teams infrastructure topics provision, teardown address agent:aws-account-lead
02·c
Approval amend
Original
Amended
"region": "us-east-1"
−"budget": 250,
"tags": { … }
"region": "us-east-1"
+"budget": 100,
+"alert_pct": 80,
"tags": { … }
02·d
Dead-letter
c9e4d3…77 already exited. Returned to gitea-lead.
10

## Implementation

Model additions

A new `team` table joins agents many-to-many. An agent can belong to multiple teams; teams have no behavior on the kernel side — they’re a UI-only grouping that drives the filter.

The merged chat stream is the natural state; the “filter” is a client-side set of agent addresses passed to `GET /api/messages?include=<addr>,<addr>`.

Components
nav-rail.ts new · Agents / Search / Approvals action items + Settings, ~80 LOC teams-list.ts new · expandable teams with member checkboxes + watch eyes, ~220 LOC filter-store.ts new · merged-stream filter state (selected agents, team selections), ~80 LOC merged-thread.ts extended · interleaves messages from N agents, ~140 LOC added profile-popover.ts new · floats over chat on sender click, ~140 LOC message-input.ts extended · `@`-mention autocomplete, ~180 LOC added trigger-banner.ts new · thread-inline trigger & exit markers, ~80 LOC approval-list.ts new · pending + recent, ~220 LOC approval-detail.ts new · payload, timeline, actions, ~360 LOC amend-modal.ts new · side-by-side diff, ~200 LOC
API

`GET /api/teams` — teams plus their member agent addresses.

`POST /api/teams`, `PATCH /api/teams/:id` — create / rename / add-remove members.

`GET /api/messages?include=…` — merged stream, filtered by agent address set.

`GET /api/agents/:addr/profile` — the popover payload (kind, state, teams, address, recent activity summary).

`POST /api/watch` · `DELETE /api/watch` — toggle Watch on / off for an agent.

Everything under `/api/approvals` is already in place from Q5.

Watch & profile

Two distinct entry points: the eye icon next to each agent in the sidebar (sticky toggle — watch state persists), and the sender-name click in the chat (opens the profile popover, which has Watch as its primary action).

When a Watch is active for an agent, the eye stays clay-colored in the sidebar and a small badge appears in the chat header. Watch view itself is the existing `watch-panel.ts`; this Q9 work just wires the new entry points.