## Context
We want a one-click path from the right-panel task detail into the
claude-agent-service runner, without the user copy-pasting the bead id
into a CLI or another tab. The runner expects a self-contained prompt
that restates the bead id, title, description, acceptance criteria, and
the guard rails the agent must operate under (no push, no file edits,
no terraform/kubectl/helm). The prompt template lives in `src/lib/` so
it can be tested and reused from the server-side dispatch route.
The right-panel button needs to:
- Only appear when the bead is actionable (`open` or `in_progress`).
- Disable itself while the claude-agent-service is already busy (the
service has a global `asyncio.Lock` — parallel dispatches 409).
- Disable itself when the bead lacks acceptance criteria. An agent that
doesn't know what "done" looks like burns budget and closes nothing.
- Surface the resulting `job_id` or any 409/error back to the user.
The project has no toast library (no `sonner`, no `react-hot-toast`), so
we render status inline under the button rather than pulling in a new
dependency for this single surface.
## This change
- `src/lib/dispatch-prompt.ts` exports `buildDispatchPrompt(bead)` which
produces the exact prompt the agent runner expects. Bead id, priority
(`P<n>`), issue type, description, and acceptance criteria are
interpolated; `<job_id>` stays a literal placeholder because the agent
only learns its own id at runtime (env var).
- `src/components/shared/dispatch-button.tsx` is a focused client
component with three responsibilities:
1. Poll `GET /api/agent-status` every 5 s while the panel is open
(plus an initial fetch on mount), mirror `busy` into local state.
2. On click, `POST /api/agent-dispatch` with `{taskId}`; branch on
200 / 409 / other.
3. Render an inline status line under the button (`text-xs`, tone
driven by `ok | info | error`) — no toast dep required.
The poll interval self-clears on unmount so closing the panel stops
network traffic.
- `src/components/shared/thread-drawer.tsx` renders `<DispatchButton>`
alongside the existing "Edit task" button in the summary section,
wrapped in a `flex-wrap` so the two controls reflow on narrow panes.
- Registers two new tests in `package.json`'s enumerated test script.
## What is NOT in this change
- The `/api/agent-dispatch` and `/api/agent-status` routes themselves —
those land in the next commit. The button calls them but the server
side is intentionally a separate step so each commit can be reviewed
in isolation.
- No real toast system is introduced; inline status is sufficient.
- No change to how task state transitions on dispatch. The agent itself
is expected to run `bd update --claim` / `bd close` via the prompt's
operating rules.
## Test Plan
### Automated
```
$ node --import tsx --test tests/lib/dispatch-prompt.test.ts \
tests/components/shared/dispatch-button.test.tsx
# tests 7 pass 7 fail 0
```
Covers:
- Bead id appears in opening paragraph and in both `bd note` / `bd close`
commands.
- Priority rendered as `P<n>`, issue type echoed.
- Description and acceptance criteria quoted verbatim when present.
- `(no description)` / `(no acceptance criteria)` fallbacks when null.
- Guard rails block present (no terraform/kubectl/helm, workspace bd
path, `bd update … --status blocked` fallback).
- DispatchButton module loads and exports both named and default.
`npm run typecheck` shows only the pre-existing `OrchestratorChatMessage`
type gap in `left-panel.tsx` that reproduces on untouched `main`.
### Manual Verification
1. `npm install`
2. `npm run dev`
3. Open `http://localhost:3000/?task=<some-open-bead-id>`
4. Expected: "Dispatch to Agent" button next to "Edit task" in the
right-panel summary section.
5. Button disabled on beads with `status in {closed, blocked, deferred}`
(they don't render the button at all).
6. Button disabled on beads missing acceptance criteria, with tooltip
"Task is missing acceptance criteria — cannot dispatch.".
7. Click: UI flips to "Dispatching…"; once the next commit is merged,
the agent-dispatch route will surface a `job_id` (today it returns
404 which renders as "Dispatch failed (HTTP 404)").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Move leftSidebarMode from URL state to local useState in unified-shell,
avoiding force-dynamic router round-trip that made the button appear broken - Replace fileURLToPath(new URL(..., import.meta.url)) with process.cwd()
in bb-pi-bootstrap.ts — import.meta.url is a webpack:// URL in Next.js,
causing cross-realm TypeError when passed to Node.js fileURLToPath()
- Create BlockedTriageModal component at src/components/shared/blocked-triage-modal.tsx
- Implements modal with blocked task triage functionality
- Uses deriveBlockedIds and buildBlockedByTree from kanban lib
- Each row shows blocker chain and has inline archetype picker
- Modal is scrollable and closes via Escape/close button
- Add corresponding tests at tests/components/blocked-triage-modal.test.tsx
- Register test in package.json test script
- Add MessageSquare icon to GraphNodeCard; prop-thread onConversationOpen
and selectedTaskId through WorkflowGraph node data (no useUrlState
inside ReactFlow nodes — avoids context/timing issues)
- Fix ContextualRightPanel: check taskId before epicId so clicking the
conversation icon always opens ThreadDrawer even when an epic filter
is active
- setEpicId now clears task from URL so selecting an epic resets any
open conversation thread
- handleGraphSelect toggles: second click on same node calls setTaskId(null)
closing the right panel
- Add onSelect to WorkflowGraph flowModel deps to prevent stale callbacks
- Fix ContextualRightPanel onClose no-ops: wired to setTaskId(null) /
setSwarmId(null) so back button works
- Right panel always visible (removed panel==='open' gate in UnifiedShell)
- SmartDag task grid: horizontal scroll, fixed-width cards, hideClosed=true
- Add <Suspense> in page.tsx for useSearchParams compatibility
- Enable dolt auto-start in .beads/config.yaml
- Add 14 static analysis tests (graph-node-conversation.test.tsx)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NEXT_SESSION_PROMPT.md: full context for Dolt mysql2 integration
including schema, current read path, normalization approach, watcher
concern, skills to use, and files to read
- mysql2 installed (beadboard-550.1 in_progress)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Various supporting changes made during the assign archetypes feature development:
- Added contextual-right-panel.tsx and swarm-command-feed.tsx
- Updated activity-panel.tsx with new features
- UI improvements to left-panel, mobile-nav
- Test updates for url-state-integration, mobile-nav, top-bar
- Package.json updates for dependencies
- Global CSS refinements
These changes support the main assign archetypes feature but are
not directly part of its core functionality.
This commit includes the new SwarmWorkspace with its 3 sub-tabs, the LeftPanel mission picker, and the comprehensive Operations Command Dashboard featuring the live interactive DAG telemetry and task assignment prep flow.
STORY:
The session backend needed to aggregate agent health from a live
telemetry stream rather than static bead metadata. This refactor
makes liveness signals real-time and accurate.
COLLABORATION:
We extended the ActivityEvent model with a native 'heartbeat' kind,
updated extendActivityLease() to emit through the activity bus, and
refactored getAgentLivenessMap() to prioritize heartbeat activity
history over stale bead metadata.
DELIVERABLES:
- ActivityEvent extended with 'heartbeat' kind
- extendActivityLease() emits heartbeats through activity bus
- getAgentLivenessMap() prefers telemetry over static metadata
- Registry APIs support projectRoot injection for testing
- Tests verify preference logic via TDD
VERIFICATION:
- 93/93 tests PASSING
- Heartbeat override verified in isolated temp projects
CLOSES: bb-buff.1.3
BLOCKS: bb-buff.3.2, bb-buff.3.3, bb-buff.2.1
We completed the 'Deep Metadata Etch' today, transforming our Beads issues from simple trackers into a permanent narrative of our collaboration.
Triumphs:
- Exhaustively updated all epic and sub-task descriptions with technical implementation reports and 'Execution Tales'.
- Finalized the 'bb' agent CLI skill (bb.ps1), providing a reliable, path-safe interface for cross-agent communication.
- Published ADR-001 and RFC-001 to document our coordination protocols.
- Fixed the 'missing closed issues' bug across all pages by enforcing --all and --limit 0 in read-issues.ts.
Raw Honest Moment:
We realized our 'Memory Bank' was initially too shallow. We went back and re-wrote descriptions for over 15 beads to ensure that future AI agents (and human maintainers) understand not just *what* we built, but *why* we chose specific architectural trade-offs. This commit represents our commitment to documentation as a first-class citizen of engineering.
- feat(kanban): Add progressive disclosure to task details drawer
- feat(kanban): Fix title layout on mobile (remove flex-row constraint)
- feat(kanban): Add bead count and metadata to epics
- style(globals): Add status color tokens and refined scrollbars
- deps: Add dagre for true DAG layout in graph view
- chore: Update capture scripts