fix: always enable SSE auto-refresh on kanban page

Previously SSE was only enabled in single project mode (allowMutations).
Now auto-refresh works in all modes including aggregate.
This commit is contained in:
zenchantlive 2026-02-13 14:51:31 -08:00
parent ad7a7b9b00
commit 4f8f3006e9
7 changed files with 209 additions and 28 deletions

View file

@ -83,7 +83,14 @@
{"id":"bb-bvn.3","title":"Add blocked-chain highlighting and cycle anomaly signaling","description":"Add analysis overlays for blocker triage and anomaly visibility.\n\nScope:\n- Compute and highlight blocked chains from selected node.\n- Show concise blocker summary:\n - open blocker count\n - in-progress blocker count\n - first actionable blocker\n- Cycle/anomaly signaling:\n - detect cycles in dependency graph\n - mark involved nodes/edges with warning style and explanation text\n\nUI behavior:\n- \"Show blocking path only\" toggle to reduce noise.\n- Hovering a node/edge highlights direct dependency chain.\n- Keep styling subtle and readable; avoid visual overload.\n\nRules:\n- Analysis is read-only and derived from current graph model.\n- Must not fail hard on malformed dependency data; degrade with warnings.\n\nTest plan:\n- Unit tests for blocked-chain derivation and cycle detection logic.\n- UI tests for toggle behavior and warning visibility.\n- Screenshot verification for normal and anomaly cases.\r\n","acceptance_criteria":"- Selected issue can display clear blocked-chain context.\n- Cycle/anomaly conditions are detected and visibly flagged.\n- Blocking-path-only mode materially reduces graph noise.\n- Analysis features remain performant and do not break base graph rendering.\n- Tests and screenshots verify normal + anomaly paths.\r\n","notes":"Addressed review P1 in detectDependencyCycles: removed early-return DFS behavior that leaked recStack/path state; traversal now always unwinds and collects cycles without contaminating predecessor nodes. Added regression test in tests/lib/graph-view.test.ts: detectDependencyCycles does not mark non-cycle predecessor as cyclic. Verification: node --import tsx --test tests/lib/graph-view.test.ts (pass), npm run typecheck (pass), npm run test (pass).","status":"closed","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:11.687878-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T18:57:24.8694169-08:00","closed_at":"2026-02-12T18:57:24.8694169-08:00","close_reason":"Implemented blocked-chain analysis, blocking-path emphasis, and cycle anomaly signaling with regression coverage; tests/typecheck are green.","labels":["analysis","graph"],"dependencies":[{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T17:12:11.6890831-08:00","created_by":"zenchantlive"},{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn.2","type":"blocks","created_at":"2026-02-11T17:12:37.378326-08:00","created_by":"zenchantlive"},{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn.4","type":"blocks","created_at":"2026-02-11T20:10:03.6326727-08:00","created_by":"zenchantlive"}]}
{"id":"bb-bvn.4","title":"Epic Design Gate: scope, decisions, and acceptance contract","description":"Design/discovery gate for bb-bvn before further implementation.\n\nMust capture:\n- Product intent and user outcomes for this epic\n- Explicit architecture decisions and tradeoffs\n- API/data contracts and edge cases\n- Windows-specific constraints and path/process assumptions\n- Test strategy and verification commands\n- Non-goals and out-of-scope boundaries\n\nCompletion rule:\nDo not start new implementation tasks in this epic until this gate is closed with agreed decisions.","acceptance_criteria":"A written execution-grade plan exists for this epic and all child task descriptions are updated with concrete implementation details, dependencies, and testable acceptance criteria.","notes":"Graph design gate completed: agreed React Flow deterministic UX, default 2-hop depth controls, mobile simplified fallback, typed edge semantics, and verification contract (tests + screenshots + smoke). Child tasks bb-bvn.1/.2/.3 updated with execution-grade details.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T20:09:40.290642-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T20:59:12.4823711-08:00","closed_at":"2026-02-11T20:59:12.4823711-08:00","close_reason":"Design gate complete: bb-bvn child tasks now contain concrete scope, contracts, dependencies, and testable acceptance criteria.","dependencies":[{"issue_id":"bb-bvn.4","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T20:09:40.2922349-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv","title":"Agent Communication \u0026 Coordination Patterns","description":"Agents need a standardized way to coordinate (handoffs, help requests, blockers) without breaking flow. We are opting for a **Issue-Centric** communication model (using Comments) rather than an Inbox-Centric model. This epic defines the protocols, patterns, and tool support needed to make that robust.\n\nGoals:\n- Define 'Protocol' for agent-to-agent comments (prefixes, structure).\n- Establish Identity standards (how agents refer to themselves).\n- Ensure CLI support for all protocol actions (commenting, signaling).\n\nDeliverables:\n- RFC-001: Agent Coordination Protocol.\n- Skill: beadboard-driver (teaching the protocol).\n\nThis epic blocks bb-u6f (Agent Sessions) because session attribution relies on the Identity standards defined here.","status":"open","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T21:35:07.1826787-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:36:56.4424829-08:00"}
{"id":"bb-dcv.1","title":"Research \u0026 RFC: Agent Skills and Handoff Protocols","description":"Conduct research and draft a 'Request for Comments' (RFC) document that defines the standard operating procedures for agent-to-agent interaction within Beadboard.\n\nKey Questions to Answer:\n1. Identity: How do we consistently identify an agent? (e.g. assignee formats).\n2. Handoff Protocol: Structure of a handoff comment (e.g. [HANDOFF]).\n3. Blocker Signaling: How to raise a flag (e.g. [BLOCKED]).\n4. Parsing: Can/should we have bd parse-comments?\n\nDeliverables:\n- docs/RFC-001-Agent-Coordination.md: Finalized spec.\n- skills/beadboard-driver/SKILL.md (Draft): Prototype skill.\n- Gap Analysis: Missing CLI commands.\n\nAcceptance Criteria:\n- RFC document created and committed.\n- Protocol covers: Identity, Handoff, Blocker, Assignment.\n- Gap analysis lists required code changes.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T21:37:32.9086915-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:37:32.9086915-08:00","dependencies":[{"issue_id":"bb-dcv.1","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-12T21:37:32.9107758-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.1","title":"Research \u0026 RFC: Agent Skills and Handoff Protocols","description":"Conduct research and draft a 'Request for Comments' (RFC) document that defines the standard operating procedures for agent-to-agent interaction within Beadboard.\n\nKey Questions to Answer:\n1. Identity: How do we consistently identify an agent? (e.g. assignee formats).\n2. Handoff Protocol: Structure of a handoff comment (e.g. [HANDOFF]).\n3. Blocker Signaling: How to raise a flag (e.g. [BLOCKED]).\n4. Parsing: Can/should we have bd parse-comments?\n\nDeliverables:\n- docs/RFC-001-Agent-Coordination.md: Finalized spec.\n- skills/beadboard-driver/SKILL.md (Draft): Prototype skill.\n- Gap Analysis: Missing CLI commands.\n\nAcceptance Criteria:\n- RFC document created and committed.\n- Protocol covers: Identity, Handoff, Blocker, Assignment.\n- Gap analysis lists required code changes.","notes":"Drafted RFC and skill artifacts: docs/RFC-001-Agent-Coordination.md and skills/beadboard-driver/SKILL.md. Includes identity, handoff/blocker/assignment protocol and gap analysis for bb agent CLI.\nSkill deliverable moved to a dedicated later task so RFC scope remains protocol/spec + gap analysis only.","status":"in_progress","priority":1,"issue_type":"task","assignee":"zenchantlive","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T21:37:32.9086915-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T14:45:05.8683583-08:00","dependencies":[{"issue_id":"bb-dcv.1","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-12T21:37:32.9107758-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.2","title":"Define bb agent CLI contract and storage schema","description":"Write the thin-layer CLI contract for bb agent commands and the on-disk schema under .beadboard/agent. Include command I/O examples and validation rules. This is implementation input, not a refactor.","acceptance_criteria":"Spec includes: register/list/show, send/inbox/read/ack, reserve/release/status; JSON schema and file layout are documented; failure modes are defined.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:41.2806805-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:41.2806805-08:00","labels":["agents","cli","design"],"dependencies":[{"issue_id":"bb-dcv.2","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:41.2822506-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.2","depends_on_id":"bb-dcv.1","type":"blocks","created_at":"2026-02-13T12:57:08.7260185-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.3","title":"Final verification and readiness sweep for agent CLI","description":"Run full verification for the thin-layer agent CLI and publish evidence from tests/lint/typecheck plus dependency sanity.","acceptance_criteria":"typecheck/test/lint pass; dependency graph is acyclic and reflects plan; readiness summary posted.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:55.8190789-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:55.8190789-08:00","labels":["agents","qa","verification"],"dependencies":[{"issue_id":"bb-dcv.3","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:55.8211858-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.3","depends_on_id":"bb-dcv.5","type":"blocks","created_at":"2026-02-13T12:57:13.0099035-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.3","depends_on_id":"bb-dcv.8","type":"blocks","created_at":"2026-02-13T14:45:12.4489854-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.4","title":"Implement reservation commands with TTL","description":"Implement reserve/release/status commands for work surfaces with TTL expiry and stale ownership handling.","acceptance_criteria":"reserve/release/status work; expired reservations are surfaced/cleared; conflict scenarios are test-covered.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:56.3114764-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:56.3114764-08:00","labels":["agents","cli","reservations"],"dependencies":[{"issue_id":"bb-dcv.4","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:56.3130569-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.4","depends_on_id":"bb-dcv.2","type":"blocks","created_at":"2026-02-13T12:57:10.8788059-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.4","depends_on_id":"bb-dcv.7","type":"blocks","created_at":"2026-02-13T12:57:11.4135844-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.5","title":"Integrate bb agent UX with bd claim workflow","description":"Add CLI UX layer and docs so bb agent flows pair cleanly with bd update --claim, without direct JSONL writes.","acceptance_criteria":"Docs include canonical session flow; commands produce operator-friendly output; no direct JSONL writes introduced.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:56.7418732-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:56.7418732-08:00","labels":["agents","cli","workflow"],"dependencies":[{"issue_id":"bb-dcv.5","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:56.7434894-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.5","depends_on_id":"bb-dcv.6","type":"blocks","created_at":"2026-02-13T12:57:11.9292114-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.5","depends_on_id":"bb-dcv.4","type":"blocks","created_at":"2026-02-13T12:57:12.4685539-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.6","title":"Implement agent mail commands (send/inbox/read/ack)","description":"Implement file-backed message transport for registered agents with unread/read/acked states and bead-linked thread context.","acceptance_criteria":"send/inbox/read/ack commands work end-to-end; sender/recipient must be registered; message lifecycle is test-covered.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:57.2090515-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:57.2090515-08:00","labels":["agents","cli","mail"],"dependencies":[{"issue_id":"bb-dcv.6","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:57.210616-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.6","depends_on_id":"bb-dcv.2","type":"blocks","created_at":"2026-02-13T12:57:09.7811635-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.6","depends_on_id":"bb-dcv.7","type":"blocks","created_at":"2026-02-13T12:57:10.3349432-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.7","title":"Implement agent identity registry commands","description":"Implement bb agent register/list/show with unique-name enforcement and stable metadata files under .beadboard/agent/agents.","acceptance_criteria":"register/list/show commands work; duplicate names fail with clear error; tests cover happy/error paths.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T12:56:57.6944409-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T12:56:57.6944409-08:00","labels":["agents","cli","identity"],"dependencies":[{"issue_id":"bb-dcv.7","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T12:56:57.6961264-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.7","depends_on_id":"bb-dcv.2","type":"blocks","created_at":"2026-02-13T12:57:09.2534901-08:00","created_by":"zenchantlive"}]}
{"id":"bb-dcv.8","title":"Create beadboard-driver skill from implemented bb agent workflows","description":"Use skill-creator workflow to produce the beadboard-driver skill only after bb agent identity, mail, reservation, and workflow commands are implemented and verified.","acceptance_criteria":"SKILL.md matches implemented CLI behavior; trigger language is explicit; no speculative commands included; quick validation performed.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-13T14:45:05.4433258-08:00","created_by":"zenchantlive","updated_at":"2026-02-13T14:45:05.4433258-08:00","labels":["agents","docs","skill"],"dependencies":[{"issue_id":"bb-dcv.8","depends_on_id":"bb-dcv","type":"parent-child","created_at":"2026-02-13T14:45:05.4449006-08:00","created_by":"zenchantlive"},{"issue_id":"bb-dcv.8","depends_on_id":"bb-dcv.5","type":"blocks","created_at":"2026-02-13T14:45:11.9133726-08:00","created_by":"zenchantlive"}]}
{"id":"bb-n7p","title":"Swimlane status model: ready + dependency-derived blocked","notes":"Implemented new swimlane model: removed deferred lane from board usage; added ready lane and dependency-derived blocked lane. Lane rules: closed-\u003eDone; blocked-\u003eBlocked if explicit status blocked OR has active incoming blocker edge; in_progress/review-\u003eIn Progress; otherwise Ready. Added laneToMutationStatus to map board lane writes to bead statuses (ready-\u003eopen). Updated board labels/colors, drag-drop lane source tracking, and controls stat label Open-\u003eReady. TDD: updated tests/lib/kanban.test.ts for ready/blocked semantics. Verification: node --import tsx --test tests/lib/kanban.test.ts (pass), npm run typecheck (pass), npm run test (pass).","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T17:55:04.1851993-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T18:40:08.0620089-08:00","closed_at":"2026-02-12T18:40:08.0620089-08:00","close_reason":"Implemented ready/blocked swimlane model, blocked-tree deep links to lane focus, and verification passed (kanban tests, typecheck, full test suite).","labels":["kanban","status","swimlane"]}
{"id":"bb-q1s","title":"UI Bead Editing Across Kanban + Graph","description":"Objective:\nAdd true UI editing for bead fields across both detail panels (Kanban + Graph) using one shared edit core so behavior stays consistent.\n\nWhy:\nWrite-back infrastructure exists, but users currently cannot edit bead content from UI detail panels.\n\nScope:\n- Shared edit validation + mutation adapter.\n- Reusable editor UI block for issue fields.\n- Integration into both Kanban and Graph detail panels.\n- Verification for responsive behavior and mutation safety.\n\nOut of scope:\n- Dependency relation editing.\n- AI content generation.\n- Bulk editing.","acceptance_criteria":"- Users can edit core bead fields from both Kanban and Graph detail panels.\n- Both surfaces use the same validation and update path.\n- Save/cancel/error states are consistent across both surfaces.\n- Typecheck/tests/guards pass and no direct JSONL writes are introduced.","notes":"Execution order enforced through child dependencies.\nExecution order: bb-q1s.1 shared core -\u003e bb-q1s.2 kanban + bb-q1s.3 graph (parallel) -\u003e bb-q1s.4 verification/polish.","status":"closed","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T20:50:12.3431904-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:11:43.1747329-08:00","closed_at":"2026-02-12T21:11:43.1747329-08:00","close_reason":"Shared UI bead editing shipped across Kanban and Graph with verification evidence.","labels":["editing","mutation","ui"]}
{"id":"bb-q1s.1","title":"Shared edit core: schema + update adapter + state machine","description":"Build shared edit core used by both detail panels.\n\nIncludes:\n- editable field schema\n- validation rules\n- payload adapter for /api/beads/update\n- form state model: pristine/dirty/saving/error","acceptance_criteria":"- Shared edit core is framework-agnostic and reused by both UIs.\n- Validation covers title/priority/labels/assignee/owner/description.\n- Adapter emits stable update payload.","notes":"Implemented shared edit core in src/lib/issue-editor.ts with draft schema, validation, diff-to-update adapter, label parsing, and edit-state classifier. Added tests in tests/lib/issue-editor.test.ts and expanded mutation adapter to support issueType updates.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-12T20:50:31.668852-08:00","created_by":"zenchantlive","updated_at":"2026-02-12T21:10:59.9315015-08:00","closed_at":"2026-02-12T21:10:59.9315015-08:00","close_reason":"Shared edit core delivered and validated via unit tests + typecheck.","labels":["editing","lib","shared"],"dependencies":[{"issue_id":"bb-q1s.1","depends_on_id":"bb-q1s","type":"parent-child","created_at":"2026-02-12T20:50:31.6709483-08:00","created_by":"zenchantlive"}]}

View file

@ -0,0 +1,171 @@
# RFC-001 Agent Coordination Protocol
Date: 2026-02-13
Owner: `bb-dcv.1`
Status: Draft
Scope: Define a CLI-first, issue-linked protocol for multi-agent coordination in BeadBoard.
## 0) Reference Position
`mcp_agent_mail` is used as a pattern reference only (identity registration, inbox/ack workflow, reservations).
We are not integrating MCP mail transport into BeadBoard for this phase.
Decision:
1. Borrow concepts.
2. Implement a local thin-layer `bb agent` CLI.
3. Keep Beads as issue/dependency system of record.
## 1) Problem Statement
BeadBoard needs reliable agent-to-agent coordination that does not depend on chat context and does not mutate `.beads/issues.jsonl` directly. Today, ownership is partially covered by Beads (`bd update --claim`), but directed communication, acknowledgements, and short-lived work-surface reservations are not standardized.
This RFC defines:
1. Agent identity conventions.
2. Handoff/blocker/decision communication protocol.
3. Assignment/claim expectations.
4. The required thin-layer `bb agent` CLI capabilities.
## 2) Design Goals and Non-Goals
Goals:
1. Keep Beads as source of truth for issue lifecycle and dependencies.
2. Add durable coordination metadata with clear auditability.
3. Require explicit bead linkage for coordination events.
4. Support parallel work without accidental overlap.
Non-goals:
1. Replacing Beads issue state with a new tracker.
2. Direct writes to Beads JSONL outside `bd`.
3. Introducing MCP requirements for core local workflows.
## 3) Identity Standard
Each automation participant uses a stable `agent_id` (example: `agent-ui-1`, `agent-graph-1`).
Rules:
1. `agent_id` is globally unique within a repo.
2. `agent_id` is immutable after registration.
3. Operator identity and agent identity are both retained in logs.
Canonical fields:
1. `agent_id`
2. `display_name`
3. `role` (`ui`, `graph`, `infra`, `qa`, etc.)
4. `created_at`
5. `last_seen_at`
6. `status` (`idle`, `working`, `blocked`, `done`)
## 4) Assignment and Ownership Protocol
Ownership remains Beads-native:
1. Claim issue with `bd update <id> --claim`.
2. Move lifecycle through normal `bd` commands.
3. Use Beads dependencies as execution truth.
Agent protocol requirements:
1. Every coordination message includes `bead_id`.
2. Any handoff sets a clear next owner or recipient.
3. Any blocker message includes a requested action and urgency.
## 5) Communication Protocol
Message categories:
1. `HANDOFF`: work transition with current state and next action.
2. `BLOCKED`: hard blocker requiring external action.
3. `DECISION`: decision record with rationale.
4. `INFO`: non-blocking operational context.
Required message envelope:
1. `message_id`
2. `thread_id` (default `bead:<id>`)
3. `bead_id`
4. `from_agent`
5. `to_agent` (or `broadcast`)
6. `category`
7. `subject`
8. `body`
9. `created_at`
10. `state` (`unread`, `read`, `acked`)
Ack requirement:
1. `BLOCKED` and `HANDOFF` messages require acknowledgement.
2. `DECISION` and `INFO` acknowledgements are optional.
## 6) Reservation Protocol
Reservations are advisory by default with TTL:
1. Reserve scope before edits on contested surfaces.
2. Scope examples: `src/components/graph/*`, `kanban-surface`, `api/mutations`.
3. Expired reservations are considered stale and available for takeover.
Required reservation fields:
1. `reservation_id`
2. `scope`
3. `agent_id`
4. `bead_id`
5. `created_at`
6. `expires_at`
7. `state` (`active`, `released`, `expired`)
## 7) Gap Analysis (Current vs Required)
Available now:
1. `bd update --claim` provides atomic issue claim.
2. `bd` dependency graph provides blocked/ready sequencing.
3. `bd agent state/heartbeat` can report liveness for agent beads.
Missing (must be added):
1. Agent registration and identity registry commands.
2. Directed message transport with unread/read/acked lifecycle.
3. Reservation commands with TTL and stale handling.
4. Unified status view tying claim + message + reservation state.
Command matrix:
1. Have now: `bd update --claim`, `bd update`, `bd close`, `bd dep`, `bd comments`.
2. Need build: `bb agent register/list/show`.
3. Need build: `bb agent send/inbox/read/ack`.
4. Need build: `bb agent reserve/release/status`.
Failure modes to handle:
1. Duplicate `agent_id` registration.
2. Unknown sender or recipient in send flow.
3. Missing `bead_id` on required message categories.
4. Reservation conflicts and stale-expiry takeover behavior.
5. Ack on unknown or already terminal message state.
## 8) Required Thin-Layer CLI Surface
Proposed commands (`bb agent`):
1. `register`, `list`, `show`
2. `send`, `inbox`, `read`, `ack`
3. `reserve`, `release`, `status`
Storage:
1. `.beadboard/agent/agents/*.json`
2. `.beadboard/agent/messages/*.jsonl`
3. `.beadboard/agent/reservations/*.json`
4. `.beadboard/agent/index/*.json` (optional fast lookup)
Safety rules:
1. No direct writes to `.beads/issues.jsonl`.
2. Bead lifecycle mutations remain via `bd`.
3. All timestamps are UTC ISO-8601.
## 9) Acceptance Criteria Mapping
Identity covered: Section 3.
Handoff covered: Sections 4 and 5 (`HANDOFF`).
Blocker signaling covered: Sections 5 and 6 (`BLOCKED`, reservation escalation).
Assignment covered: Section 4 (`bd --claim` as ownership source).
Gap analysis covered: Section 7.
## 10) Rejected Alternatives
1. Full MCP-native mail integration now.
Reason: unnecessary platform dependency for immediate local workflow goals.
2. Keep coordination only in ad-hoc bead comments.
Reason: no directed inbox/ack semantics and weak reservation signaling.
3. Replace Beads lifecycle with custom coordination store.
Reason: duplicates existing dependency/lifecycle truth and raises migration risk.

View file

@ -553,14 +553,14 @@ export function DependencyGraphPage({
if (dep.type !== 'blocks') continue;
// Avoid self-loops
if (issue.id === dep.target) continue;
const edgeId = `${issue.id}:blocks:${dep.target}`;
const edgeId = `${dep.target}:blocks:${issue.id}`;
const linkedToSelection = selectedId ? issue.id === selectedId || dep.target === selectedId : false;
graphEdges.push({
id: edgeId,
source: issue.id,
target: dep.target,
source: dep.target,
target: issue.id,
className: linkedToSelection ? 'workflow-edge-selected' : 'workflow-edge-muted',
animated: linkedToSelection,
label: 'BLOCKS',

View file

@ -188,10 +188,8 @@ export function KanbanPage({
}
}, [projectRoot]);
// Auto-refresh when issues change on disk (SSE)
useEffect(() => {
if (!allowMutations) {
return;
}
const source = new EventSource(`/api/events?projectRoot=${encodeURIComponent(projectRoot)}`);
const onIssues = () => {
void refreshIssues({ silent: true });
@ -203,7 +201,7 @@ export function KanbanPage({
source.removeEventListener('issues', onIssues as EventListener);
source.close();
};
}, [allowMutations, projectRoot, refreshIssues]);
}, [projectRoot, refreshIssues]);
const mutateStatus = async (issue: BeadIssue, targetStatus: KanbanStatus) => {
if (!allowMutations) {

View file

@ -100,7 +100,12 @@ export function buildGraphModel(issues: BeadIssue[], options: BuildGraphModelOpt
continue;
}
const edgeKey = `${issue.id}::${dependency.type}::${dependency.target}`;
// Beads "blocks" dependency means: issue depends on target, so target blocks issue.
// Normalize graph direction to blocker -> blocked for all blocker analytics and UI signals.
const source = dependency.type === 'blocks' ? dependency.target : issue.id;
const target = dependency.type === 'blocks' ? issue.id : dependency.target;
const edgeKey = `${source}::${dependency.type}::${target}`;
if (edgeKeys.has(edgeKey)) {
diagnostics.droppedDuplicates += 1;
continue;
@ -108,8 +113,8 @@ export function buildGraphModel(issues: BeadIssue[], options: BuildGraphModelOpt
edgeKeys.add(edgeKey);
edges.push({
source: issue.id,
target: dependency.target,
source,
target,
type: dependency.type,
});
}

View file

@ -43,11 +43,11 @@ test('buildGraphViewModel limits visible nodes by hop depth around focus', () =>
assert.deepEqual(
depth1.nodes.map((x) => x.id),
['bb-2', 'bb-1', 'bb-3'],
['bb-2', 'bb-3', 'bb-1'],
);
assert.deepEqual(
depth2.nodes.map((x) => x.id),
['bb-2', 'bb-1', 'bb-3', 'bb-4'],
['bb-2', 'bb-4', 'bb-3', 'bb-1'],
);
});
@ -81,7 +81,7 @@ test('buildGraphViewModel keeps deterministic edge ordering', () => {
assert.deepEqual(
view.edges.map((x) => `${x.source}|${x.type}|${x.target}`),
['bb-2|blocks|bb-3', 'bb-2|parent|bb-1'],
['bb-2|parent|bb-1', 'bb-3|blocks|bb-2'],
);
assert.equal(view.nodes.every((x) => Number.isFinite(x.position.x) && Number.isFinite(x.position.y)), true);
});
@ -96,8 +96,8 @@ test('buildPathWorkspace returns upstream/downstream levels around focus', () =>
const workspace = buildPathWorkspace(model, { focusId: 'bb-2', depth: 2, hideClosed: false });
assert.equal(workspace.focus?.id, 'bb-2');
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-1']]);
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-3']]);
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-3']]);
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-1']]);
});
test('buildPathWorkspace hides closed nodes when requested', () => {
@ -122,15 +122,15 @@ test('buildPathWorkspace full depth keeps deterministic blocker and dependent le
const workspace = buildPathWorkspace(model, { focusId: 'bb-3', depth: 'full', hideClosed: false });
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-2'], ['bb-1']]);
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-4'], ['bb-5']]);
assert.deepEqual(workspace.blockers.map((level) => level.map((node) => node.id)), [['bb-4'], ['bb-5']]);
assert.deepEqual(workspace.dependents.map((level) => level.map((node) => node.id)), [['bb-2'], ['bb-1']]);
});
test('analyzeBlockedChain returns blocker counts, first actionable blocker, and chain edges', () => {
const model = buildGraphModel([
issue({ id: 'bb-1', status: 'open', dependencies: [{ type: 'blocks', target: 'bb-2' }] }),
issue({ id: 'bb-2', status: 'in_progress', dependencies: [{ type: 'blocks', target: 'bb-3' }] }),
issue({ id: 'bb-3', status: 'blocked' }),
issue({ id: 'bb-1', status: 'open' }),
issue({ id: 'bb-2', status: 'in_progress', dependencies: [{ type: 'blocks', target: 'bb-1' }] }),
issue({ id: 'bb-3', status: 'blocked', dependencies: [{ type: 'blocks', target: 'bb-2' }] }),
]);
const summary = analyzeBlockedChain(model, { focusId: 'bb-3' });
@ -155,7 +155,7 @@ test('detectDependencyCycles reports cycle nodes and edges for blocks relations'
assert.equal(anomaly.cycles.length, 1);
assert.deepEqual(anomaly.cycleNodeIds, ['bb-1', 'bb-2', 'bb-3']);
assert.deepEqual(anomaly.cycleEdgeIds, ['bb-1:blocks:bb-2', 'bb-2:blocks:bb-3', 'bb-3:blocks:bb-1']);
assert.deepEqual(anomaly.cycleEdgeIds, ['bb-1:blocks:bb-3', 'bb-2:blocks:bb-1', 'bb-3:blocks:bb-2']);
});
test('detectDependencyCycles does not mark non-cycle predecessor as cyclic', () => {
@ -170,5 +170,5 @@ test('detectDependencyCycles does not mark non-cycle predecessor as cyclic', ()
assert.deepEqual(anomaly.cycleNodeIds, ['bb-a', 'bb-b', 'bb-c']);
assert.equal(anomaly.cycleNodeIds.includes('bb-x'), false);
assert.equal(anomaly.cycleEdgeIds.includes('bb-x:blocks:bb-a'), false);
assert.equal(anomaly.cycleEdgeIds.includes('bb-a:blocks:bb-x'), false);
});

View file

@ -62,8 +62,8 @@ test('buildGraphModel extracts supported dependency types with deterministic ord
model.edges.map((x) => `${x.source}|${x.type}|${x.target}`),
[
'bb-1|supersedes|bb-3',
'bb-2|blocks|bb-3',
'bb-2|parent|bb-1',
'bb-3|blocks|bb-2',
'bb-3|duplicates|bb-1',
'bb-3|relates_to|bb-2',
],
@ -119,9 +119,9 @@ test('buildGraphModel builds incoming/outgoing adjacency maps', () => {
const model = buildGraphModel(issues);
assert.deepEqual(model.adjacency['bb-1'].outgoing.map((x) => x.target), ['bb-2']);
assert.deepEqual(model.adjacency['bb-1'].incoming.map((x) => x.source), []);
assert.deepEqual(model.adjacency['bb-2'].incoming.map((x) => x.source), ['bb-1']);
assert.deepEqual(model.adjacency['bb-2'].outgoing.map((x) => x.target), ['bb-3']);
assert.deepEqual(model.adjacency['bb-1'].outgoing.map((x) => x.target), []);
assert.deepEqual(model.adjacency['bb-1'].incoming.map((x) => x.source), ['bb-2']);
assert.deepEqual(model.adjacency['bb-2'].incoming.map((x) => x.source), []);
assert.deepEqual(model.adjacency['bb-2'].outgoing.map((x) => x.target), ['bb-1', 'bb-3']);
assert.deepEqual(model.adjacency['bb-3'].incoming.map((x) => x.source), ['bb-2']);
});