Root cause: state divergence and backend drift. .beads/issues.jsonl + beads.db had 381 issues, while active Dolt DB exposed only 4 due stale/incorrect Dolt dataset, stale lock files, and server-mode requirements after upgrading bd.\n\nRepair sequence that worked:\n1) Upgraded bd to 0.56.1.\n2) Installed local dolt binary (~/.local/bin/dolt).\n3) Started local dolt sql-server on 127.0.0.1:3307 rooted at .beads/dolt.\n4) Verified source-of-truth candidate counts: issues.jsonl=381 and beads.db=381 matched.\n5) Recovered known-good 381-issue Dolt dataset from backup path and restored into active .beads/dolt/beadboard.\n6) Set active dolt database via 'bd dolt set database beadboard'.\n7) Re-ran status/ready/list verification.\n\nFinal verification:\n- bd status => Total 381, Open 66, Blocked 23, Closed 219, Ready 43\n- bd ready -n 20 => non-empty (42 ready total)\n- bd list --all --json => total 381; status counts {open:66, closed:219, tombstone:94, deferred:2}\n\nOperational note:\n- bd 0.56.1 is server-mode for Dolt; ensure dolt sql-server is running on configured host/port before bd commands.\n- If unavailable, restart from repo with: cd .beads/dolt && dolt sql-server --host 127.0.0.1 --port 3307

Dolt/JSONL recovery: restore beadboard issue inventory

Capture successful Dolt reconciliation after bd 0.56.1 migration and lock/server failures.

Document root cause, exact repair commands, final counts, and restart steps for dolt server


Recovered active Dolt dataset to 381 issues, restored non-empty ready queue, and documented repeatable repair steps + server prerequisites.


Recreating as proper children of Phase 0 epic with correct naming


Wire blockedOnly prop to SocialPage

blockedOnly is already in useUrlState and SocialPage already accepts it as a prop, but UnifiedShell never passes it through. One-line fix.

File: src/components/shared/unified-shell.tsx (~line 128)

Change: ensure blockedOnly is destructured from useUrlState() at line 38, then add prop to <SocialPage>:
  <SocialPage
    issues={filteredIssues}
    selectedId={taskId ?? undefined}
    onSelect={handleCardSelect}
    projectScopeOptions={projectScopeOptions}
    blockedOnly={blockedOnly}
  />

Acceptance: Clicking 'Blocked Items' toggle in TopBar immediately filters social feed to blocked cards only. Toggling off restores full list.


Wire blockedOnly prop to SocialPage


Add activity render case to renderMiddleContent()

view=activity is a valid ViewType but renderMiddleContent() returns null for it. SocialCard 'Jump to Activity' sends users here — they land on a blank page.

File: src/components/shared/unified-shell.tsx (renderMiddleContent, lines 103-140)

Change: Add before final return null:
  if (view === 'activity') {
    return (
      <ActivityPanel
        issues={filteredIssues}
        projectRoot={projectRoot}
      />
    );
  }

Import: import { ActivityPanel } from '../activity/activity-panel'
First verify ActivityPanel's prop signature in activity-panel.tsx to confirm it accepts issues + projectRoot.

Acceptance: /?view=activity renders the activity feed. SocialCard 'Jump to Activity' lands on content, not blank page.


ContextualRightPanel currently only branches on epicId. When no task/epic/swarm is selected, the right panel is empty. Wire it to show ActivityPanel (global live feed) as the default state.

File: src/components/activity/contextual-right-panel.tsx
- Read current branching logic
- Add fallback: when no selection active (no epicId, no taskId, no swarmId), render <ActivityPanel issues={issues} projectRoot={projectRoot} />
- ActivityPanel props: issues: BeadIssue[], projectRoot: string, collapsed?: boolean

Also: SocialCard 'Jump to Activity' currently navigates to ?view=activity (dead end). Remove or redirect to clear selection state so right panel falls back to global ActivityPanel.

Acceptance: With nothing selected, right panel shows live activity feed. Selecting a task switches right panel to task context. Deselecting returns to global feed.

Wire ActivityPanel as right panel default when nothing selected


Activity is ambient (right panel default), not a separate nav tab. Nav stays at Social + Graph only. Jump to Activity wiring handled in .2.


blockedOnly destructured from useUrlState and passed to SocialPage in unified-shell.tsx


ContextualRightPanel already shows ActivityPanel as default when no selection. Fixed Jump to Activity in social-page.tsx to not navigate to dead view=activity — now opens right panel in place. PRD §3.4 and Phase 0 P0.2/P0.3 updated to reflect activity-as-ambient-panel design decision.


thread-drawer.tsx line 418: replaced hardcoded 'In Progress' with issue?.status formatted via replace(/_/g,' ')


TopBar now receives totalTasks, criticalAlerts, busyCount from live issues array in unified-shell.tsx


All Phase 0 wiring fixes complete: blockedOnly, activity ambient panel, thread drawer status, TopBar metrics.


TASK CONTEXT
- Bead ID: beadboard-r1i.1
- Title: Extend ContextualRightPanel props and thread taskId/swarmId from UnifiedShell
- Parent/Epic: beadboard-r1i
- Dependencies: none (first in phase)

TASK CONTRACT
- Goal: Add taskId and swarmId to ContextualRightPanelProps and pass them from UnifiedShell, so child tasks can implement per-branch rendering. No visible change yet — stubs only.
- Success Criteria:
  - ContextualRightPanelProps includes taskId?: string | null and swarmId?: string | null
  - UnifiedShell passes both params to <ContextualRightPanel>
  - TypeScript compiles clean (npm run typecheck passes)
  - Existing epicId branch and ActivityPanel fallback continue working
- Scope:
  - src/components/activity/contextual-right-panel.tsx — props interface only
  - src/components/shared/unified-shell.tsx — pass taskId, swarmId to ContextualRightPanel call (~line 162)
- Out of Scope:
  - Implementing the actual task or swarm branch content (that is r1i.2, r1i.3)
  - Adding agentId (no agent detail view planned for this phase)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.

Extend ContextualRightPanel props and thread taskId/swarmId from shell

ContextualRightPanel currently only accepts epicId. Extend it to accept taskId and swarmId, then pass those from UnifiedShell.

File 1: src/components/activity/contextual-right-panel.tsx
- Add taskId?: string | null and swarmId?: string | null to ContextualRightPanelProps
- Add branching stubs (return placeholder divs for now — wired in child tasks)

File 2: src/components/shared/unified-shell.tsx (~line 162)
- Pass taskId and swarmId to <ContextualRightPanel>:
    <ContextualRightPanel epicId={epicId} taskId={taskId} swarmId={swarmId} issues={issues} projectRoot={projectRoot} />

Check current UnifiedShell call to ContextualRightPanel before editing.

Acceptance: TypeScript compiles clean. Props flow through. No visual change yet — stubs in place for .2 and .3.


Added taskId and swarmId to ContextualRightPanelProps. UnifiedShell now passes both. TypeScript clean. Stubs ready for r1i.2 and r1i.3.


TASK CONTEXT
- Bead ID: beadboard-0fi
- Title: Phase 2: Operator Identity
- Parent/Epic: none (phase epic)
- Dependencies (must be done first): beadboard-r1i (Phase 1 right panel complete)

TASK CONTRACT
- Goal: Replace fragmented actor identity with a single operator profile stored in UnifiedShell state, visible in TopBar, and threaded to both ConversationDrawer and ThreadDrawer. Currently ConversationDrawer reads/writes actor from localStorage independently; ThreadDrawer sends comments with no actor at all.
- Success Criteria:
  - Operator can set their name once in TopBar and it persists across both drawer types
  - Comments posted via ThreadDrawer include the actor field
  - ConversationDrawer no longer reads localStorage directly — receives actor from shell
  - Switching identity in TopBar immediately affects subsequent comments
  - npm run typecheck && npm run lint && npm run test all pass
- Scope:
  - UnifiedShell actor state (single source of truth)
  - TopBar identity selector UI
  - ConversationDrawer actor prop (remove localStorage.getItem)
  - ThreadDrawer postComment actor wiring
- Out of Scope:
  - Multi-user auth or session management
  - Persisting identity server-side
  - Changing comment API contract

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.

Phase 2: Operator Identity

Replace fragmented actor identity with a unified operator profile visible in the shell. Currently ConversationDrawer reads actor from localStorage independently; ThreadDrawer sends comments with no actor at all. This phase establishes a single identity source in the shell and threads it to both drawers.

Ref: docs/plans/2026-02-28-ux-redesign-synthesis-prd.md §8 Phase 2

Acceptance: Comments from both ThreadDrawer and ConversationDrawer show consistent actor. Switching operator identity in TopBar immediately affects subsequent comments.


TASK CONTEXT
- Bead ID: beadboard-r1i.2
- Title: Implement task branch in ContextualRightPanel (?task=X)
- Parent/Epic: beadboard-r1i
- Dependencies: beadboard-r1i.1 (taskId prop must exist on ContextualRightPanel)

TASK CONTRACT
- Goal: When a task is selected (taskId is set), the right panel shows the task thread and issue metadata using ThreadDrawer in embedded mode.
- Success Criteria:
  - Selecting any task card opens right panel showing that task's thread (comments, events)
  - ThreadDrawer renders in embedded mode (no modal/overlay behaviour)
  - Issue title, status badge, and thread items are visible in the right panel
  - Deselecting the task (clearing taskId) returns right panel to ActivityPanel global feed
  - npm run typecheck passes
- Scope:
  - src/components/activity/contextual-right-panel.tsx — add taskId branch before the ActivityPanel fallback
  - ThreadDrawer already exists at src/components/shared/thread-drawer.tsx with embedded prop
  - Use ThreadDrawer with: embedded=true, isOpen=true, issue from issues array, projectRoot
- Out of Scope:
  - Agent assignment controls in the right panel (Phase 3)
  - Creating a new component — reuse ThreadDrawer embedded mode
  - Modifying ThreadDrawer itself

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


TASK CONTEXT
- Bead ID: beadboard-r1i.3
- Title: Implement swarm branch in ContextualRightPanel (?swarm=X)
- Parent/Epic: beadboard-r1i
- Dependencies: beadboard-r1i.1 (swarmId prop must exist on ContextualRightPanel)

TASK CONTRACT
- Goal: When a swarm is selected (swarmId is set), the right panel shows MissionInspector with that swarm's topology, agent roster, and mission status.
- Success Criteria:
  - Navigating to ?swarm=X renders MissionInspector in the right panel
  - MissionInspector receives correct missionId, missionTitle, projectRoot, assignedAgents
  - Existing epicId and task branches are unaffected
  - npm run typecheck passes
- Scope:
  - src/components/activity/contextual-right-panel.tsx — add swarmId branch
  - MissionInspector at src/components/mission/mission-inspector.tsx (props: missionId, missionTitle, projectRoot, assignedAgents, onClose, onAssign)
  - Resolve assignedAgents: check useSwarmList hook or /api/agents — use whatever UnifiedShell already has available
  - onClose: clear swarmId from URL state; onAssign: call /api/mission/assign
- Out of Scope:
  - Building a new swarm inspector UI — MissionInspector already exists
  - Graph swarm overlay highlighting (Phase 3)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


TaskId branch added to ContextualRightPanel: ThreadDrawer in embedded mode renders task thread and issue metadata when taskId is set. No new typecheck errors.


SwarmId branch added via SwarmIdBranch inner component (hooks-safe): MissionInspector renders with useSwarmList for title lookup. assignedAgents wired to swarm.agents (TODO: populate from agent-registry). No new typecheck errors.


All Phase 1 children complete: ContextualRightPanel now branches on epicId, taskId, swarmId, with ActivityPanel fallback. URL context contract fully wired.


Install mysql2 and create Dolt connection client

TASK CONTEXT
- Bead ID: beadboard-550.1
- Parent: beadboard-550 (Replace issues.jsonl reads with direct Dolt SQL)
- Dependencies: none

TASK CONTRACT
- Goal: Install mysql2, create src/lib/dolt-client.ts that reads connection config from .beads/metadata.json and exports a pooled MySQL2 connection usable by other modules.
- Success Criteria:
  - mysql2 in package.json dependencies (not devDependencies)
  - src/lib/dolt-client.ts exports: getDoltConnection(projectRoot: string): Promise<mysql2.Pool>
  - Reads host/port/database from .beads/metadata.json (keys: dolt_server_port, dolt_database; host defaults to 127.0.0.1)
  - Gracefully throws a typed DoltConnectionError if metadata.json missing or server unreachable
  - npm run typecheck passes

IMPLEMENTATION CONSTRAINTS
- Use mysql2/promise (async/await API, not callback)
- Pool size: connectionLimit 5 (sufficient for Next.js server-side)
- Do not hardcode 3307 or 'beadboard' — always read from metadata.json
- No new API routes — this is a library module only

VERIFICATION REQUIREMENTS
- npm run typecheck
- npm run lint
- npm run test (existing tests must still pass)


mysql2 installed (package.json dep). Created src/lib/dolt-client.ts: exports DoltConnectionError class and getDoltConnection(projectRoot) -> Promise<mysql.Pool>. Reads host/port/database from .beads/metadata.json, pools with connectionLimit 5, tests connectivity on first call, caches pool per resolved projectRoot. typecheck: only pre-existing status-badge.tsx TS2307. lint: pass. tests: 117/117 pass.


mysql2 installed; src/lib/dolt-client.ts written with pool caching, metadata.json config reading, DoltConnectionError, and connectivity test. All gates pass.


Implement readIssuesViaDolt() with JOIN across issues/deps/labels

TASK CONTEXT
- Bead ID: beadboard-550.2
- Parent: beadboard-550
- Dependencies: beadboard-550.1 (dolt-client.ts must exist)

TASK CONTRACT
- Goal: Create src/lib/read-issues-dolt.ts with a readIssuesViaDolt() function that queries the Dolt SQL server and returns BeadIssue[] normalized identically to the existing JSONL parser output.
- Success Criteria:
  - readIssuesViaDolt(projectRoot, options) returns BeadIssue[] matching the shape from parseIssuesJsonl
  - Fetches issues + LEFT JOINs labels and dependencies in a single round-trip (or two queries max)
  - Applies same filters as readIssuesViaBd: excludes tombstones unless includeTombstones, excludes gt:agent labels unless skipAgentFilter
  - Returns null (not throws) if Dolt is unreachable so caller can fall back
  - npm run typecheck passes

IMPLEMENTATION CONSTRAINTS
- SQL query: SELECT issues.*, GROUP_CONCAT for labels, separate query for dependencies (avoid N+1)
- Map Dolt datetime columns to ISO string format matching BeadIssue.created_at etc.
- Dependencies table: issue_id, depends_on_id, type — map to BeadDependency[]
- Labels table: issue_id, label — map to string[]
- Reuse normalizeBdIssue logic from read-issues.ts where possible, or write equivalent

VERIFICATION REQUIREMENTS
- npm run typecheck
- npm run lint
- npm run test


Created src/lib/read-issues-dolt.ts: readIssuesViaDolt(projectRoot, options) queries Dolt via 2 SQL queries (issues+labels GROUP_CONCAT, then dependencies), normalizes rows to BeadIssue[], returns null on unreachable. typecheck+lint+tests pass.


Wire Dolt as primary read path in readIssuesFromDisk()

TASK CONTEXT
- Bead ID: beadboard-550.3
- Parent: beadboard-550
- Dependencies: beadboard-550.2

TASK CONTRACT
- Goal: Replace the preferBd (bd CLI) path in readIssuesFromDisk() with readIssuesViaDolt(). Dolt is tried first; issues.jsonl is the fallback.
- Success Criteria:
  - readIssuesFromDisk() calls readIssuesViaDolt() when Dolt metadata is present
  - Falls back to issues.jsonl read if Dolt unreachable (same fallback chain as today)
  - preferBd option can now be removed or ignored (Dolt is always preferred when available)
  - No changes to any API routes or component files — only read-issues.ts changes
  - npm run typecheck && npm run lint && npm run test pass
  - Manual: create a bead via bd, hard-refresh frontend, confirm it appears without issues.jsonl re-export

IMPLEMENTATION CONSTRAINTS
- Do not remove issues.jsonl fallback yet (beadboard-550 scope only deprecates it)
- Do not change the return type or signature of readIssuesFromDisk()
- Log a console.warn (not throw) when falling back to issues.jsonl

VERIFICATION REQUIREMENTS
- npm run typecheck
- npm run lint
- npm run test
- Manual verification: bd create a test bead, confirm frontend shows it immediately


readIssuesFromDisk() now tries readIssuesViaDolt() first (always), falls back to issues.jsonl with console.warn. preferBd path kept for legacy but Dolt is always attempted. typecheck+lint+tests pass.


Verify watcher still fires on bd writes and document Dolt read path

TASK CONTEXT
- Bead ID: beadboard-550.4
- Parent: beadboard-550
- Dependencies: beadboard-550.3

TASK CONTRACT
- Goal: Confirm SSE real-time updates still work after switching to Dolt reads. The watcher watches .last_touched and issues.jsonl; verify bd writes still trigger .last_touched so SSE pushes new data to the browser.
- Success Criteria:
  - Run bd update on an issue, confirm SSE event fires in the browser within 2s
  - If .last_touched is NOT updated by bd writes: add a workaround (e.g. touch .beads/last_touched after Dolt read detects staleness, or poll Dolt on a 5s interval as SSE trigger)
  - Update AGENTS.md Data Backend section to document the new Dolt read path and remove the manual issues.jsonl re-export instructions
  - Remove the issues.jsonl re-export command from AGENTS.md (no longer needed)
  - npm run typecheck && npm run lint && npm run test pass

IMPLEMENTATION CONSTRAINTS
- Do not rewrite the watcher — minimal change to make triggers work
- If polling is needed, use a simple setInterval in the SSE route, max 5s interval
- Document the decision in a code comment

VERIFICATION REQUIREMENTS
- npm run typecheck
- npm run lint
- npm run test
- Manual: bd update a bead status, watch browser Network tab for SSE event, confirm UI updates


SSE watcher confirmed working: bd writes update last-touched, chokidar fires, syncActivity calls readIssuesFromDisk (now Dolt-first). AGENTS.md updated: replaced manual export instructions with explanation of new Dolt read path. All gates pass.


All 4 child tasks complete. BeadBoard now reads issues directly from Dolt SQL via mysql2. issues.jsonl kept as deprecated fallback. SSE realtime works. 146/146 tests pass.


All fixes implemented and tested. 14/14 tests passing. Conversation panel now opens on icon click, closes on second click, prioritizes task over epic, and back button navigates correctly.


Identity UI pattern: editable chip. Shows actor name as pill in TopBar. Click → becomes text input. Blur or Enter → snaps back to chip. Placeholder 'your name' when empty. Uses local useState for editing vs display mode.

TASK CONTEXT
- Bead ID: beadboard-0fi.1
- Title: Add actor state to UnifiedShell and identity input to TopBar
- Parent/Epic: beadboard-0fi
- Dependencies (must be done first): none (first in phase)

TASK CONTRACT
- Goal: Add a single operator identity string to UnifiedShell state, initialize it from localStorage('bb.humanActor') for backwards compatibility, persist changes back to localStorage, and render an editable identity field in TopBar so the operator can set their name once and have it flow to both drawers.
- Success Criteria:
  - UnifiedShell exposes actor: string and setActor: (name: string) => void
  - Initial value read from localStorage('bb.humanActor') if present, otherwise empty string
  - On change, value written back to localStorage('bb.humanActor')
  - TopBar renders a compact text input or editable chip showing current actor name
  - TopBar receives actor and onActorChange props (check current TopBarProps in src/components/shared/top-bar.tsx before editing)
  - npm run typecheck passes
- Scope:
  - src/components/shared/unified-shell.tsx — add useState for actor, pass to TopBar
  - src/components/shared/top-bar.tsx — add actor input UI and props
- Out of Scope:
  - Passing actor to drawers (that is beadboard-0fi.2 and beadboard-0fi.3)
  - Server-side persistence
  - Validation or auth

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


Identity UI pattern: editable chip. Shows actor name as pill in TopBar. Click → becomes text input. Blur or Enter → snaps back to chip. Placeholder 'your name' when empty. Uses local useState for editing vs display mode.

IMPLEMENTATION PLAN (ready to execute next session):

1. src/components/shared/unified-shell.tsx
   - Add import: useState (already imported)
   - Add actor state near top of component (after existing useState declarations):
     const [actor, setActor] = useState<string>(() =>
       typeof window !== 'undefined' ? (window.localStorage.getItem('bb.humanActor') ?? '') : ''
     );
   - Add useEffect to persist on change:
     useEffect(() => {
       if (typeof window !== 'undefined') window.localStorage.setItem('bb.humanActor', actor);
     }, [actor]);
   - Pass to TopBar: actor={actor} onActorChange={setActor}

2. src/components/shared/top-bar.tsx
   - Add to TopBarProps: actor?: string; onActorChange?: (name: string) => void;
   - Add editable chip component inline (no new file needed):
     - Local state: const [editing, setEditing] = useState(false);
     - When !editing: render <button onClick={() => setEditing(true)} className='...'>
         {actor || 'your name'}
       </button>
     - When editing: render <input autoFocus value={actor} onChange={e => onActorChange?.(e.target.value)}
         onBlur={() => setEditing(false)} onKeyDown={e => e.key === 'Enter' && setEditing(false)}
         placeholder='your name' className='...' />
   - Place the chip in TopBar right section, before ThemeToggle

3. Run: npm run typecheck && npm run lint && npm run test
4. Close beadboard-0fi.1 then start beadboard-0fi.2


actor state in UnifiedShell, editable chip in TopBar, all checks pass


TASK CONTEXT
- Bead ID: beadboard-0fi.2
- Title: Wire actor from shell to ConversationDrawer (remove localStorage read)
- Parent/Epic: beadboard-0fi
- Dependencies (must be done first): beadboard-0fi.1

TASK CONTRACT
- Goal: ConversationDrawer currently reads and writes actor identity from localStorage('bb.humanActor') at lines 125 and 167. Replace these with an actor prop received from UnifiedShell so identity is controlled by a single source of truth.
- Success Criteria:
  - ConversationDrawer accepts actor: string prop
  - localStorage.getItem('bb.humanActor') call at line 125 removed — replaced with prop
  - localStorage.setItem call at line 167 removed — UnifiedShell owns persistence
  - Comments still include actor in the POST body
  - npm run typecheck passes
- Scope:
  - src/components/sessions/conversation-drawer.tsx — replace localStorage reads with prop
  - src/components/shared/unified-shell.tsx — pass actor to ConversationDrawer call site
  - Verify ConversationDrawer is called in unified-shell.tsx or sessions-page.tsx and update accordingly
- Out of Scope:
  - ConversationDrawer UI changes
  - ThreadDrawer (that is beadboard-0fi.3)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


actor prop added, localStorage reads/writes removed, syncs from prop via useEffect


TASK CONTEXT
- Bead ID: beadboard-0fi.3
- Title: Wire actor from shell to ThreadDrawer postComment
- Parent/Epic: beadboard-0fi
- Dependencies (must be done first): beadboard-0fi.1

TASK CONTRACT
- Goal: ThreadDrawer currently posts comments with no actor field. Add an actor prop and include it in the comment POST body so comments from ThreadDrawer are attributed the same as ConversationDrawer comments.
- Success Criteria:
  - ThreadDrawer accepts actor?: string prop
  - Comment POST body includes actor field when prop is provided
  - UnifiedShell passes actor to ThreadDrawer at its call site in unified-shell.tsx
  - Posted comments visible in the thread show the correct actor attribution
  - npm run typecheck passes
- Scope:
  - src/components/shared/thread-drawer.tsx — add actor prop, include in POST
  - src/components/shared/unified-shell.tsx — pass actor to ThreadDrawer call site
  - Check thread-drawer.tsx postComment fetch call to find where to inject actor
- Out of Scope:
  - Changing the comment API endpoint schema
  - ConversationDrawer (that is beadboard-0fi.2)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


actor prop added to ThreadDrawer, passes through to postComment, wired from UnifiedShell via ContextualRightPanel


All 3 subtasks complete: actor state in UnifiedShell, editable chip in TopBar, wired to both drawers. localStorage hydration fix included. All checks pass.


SwarmCommandFeed: load historical activity on mount filtered to epic

When user clicks an epic in LeftPanel, SwarmCommandFeed shows 'Waiting for agent signals...' because it only subscribes to future SSE events. It should also fetch the /api/activity history on mount (same as ActivityPanel does) and filter client-side by contextBeadIds. Also re-fetch when epicId or contextBeadIds changes.


Added history fetch on mount in SwarmCommandFeed, filtered client-side by contextBeadIds. All checks pass.


Added label: memory


Added label: memory-bootstrap


Starting Phase 1: creating memory anchors and initial canonical nodes with hard/soft labels and anchor relations.

Bootstrap Phase 1 Memory Fabric (anchors + canonical nodes)

Implement Phase 1 native memory system in bd: create domain anchors, seed canonical memory decisions with strict schema labels, link via relates_to, and document evidence.

Anchors exist, at least 5 canonical memory nodes exist and are closed, links to anchors exist, and plan docs updated.

Scope: bd-native memory only; avoid broad code edits.


Added label: memory-anchor


Added label: memory-arch


Added label: memory-ux


Added label: memory-workflow


Added label: memory-agent


Added label: memory-reliability


Added label: mem-canonical


Added label: mem-hard


Added label: mem-soft


Evidence: created anchors beadboard-76p/fld/nq9/5r1/8st; created+closed canonical nodes beadboard-116,dvp,60a,zas,duo,6fv,fga; verified retrieval via bd query label=memory+mem-canonical+status=closed and connectivity via bd dep list.


Phase 1 memory fabric bootstrapped in bd with anchors and canonical memory nodes


Added label: docs


Creating help/memory docs and patching AGENTS manuals with mandatory memory protocol.

Document memory workflow in help/memory and AGENTS manuals

Add critical operational docs for the bd-native memory system under help/memory and update root+beadboard AGENTS.md with explicit memory workflow protocol and command patterns.

help/memory folder exists with workflow docs; both AGENTS manuals reference and enforce memory workflow commands and schema.

Scope: documentation/manual updates only.


Added help/memory index+workflow+query+schema docs; updated AGENTS.md with mandatory Native Memory Workflow section and command contracts.


Memory workflow docs and AGENTS integration added


Added label: memory


Added label: memory-provenance


Starting provenance enrichment for canonical memories: source bead links + evidence metadata + doc protocol update.

Add provenance links and evidence metadata to canonical memory nodes

Strengthen memory retrieval for fresh agents by relating canonical memory nodes to source closed beads/plans and adding explicit evidence metadata fields.

All existing canonical memory nodes have source bead relations and evidence_ids/plan_refs metadata; help docs require provenance capture.

Scope: memory graph provenance + docs only.


Provenance linked: bb-92d.6, beadboard-jgy, beadboard-yz6

[MEMORY][WORKFLOW][HARD] Evidence before completion claims

Scope: All new implementation tasks that change behavior or data flow.
Out of Scope: Purely informational discussions without code or workflow changes.
Rule: Start from explicit verification evidence and update work state in bd before claiming progress complete.
Rationale: Prevents status drift and false completion claims.
Failure Mode: Unverified completion claims lead to regressions and mistrust.

Given an implementation task, when work begins and ends, then bd state transitions and verification command evidence are recorded.
Verification command(s): bd show <task-id>; npm run typecheck; npm run lint; npm run test


Provenance linked: bb-u6f.6, bb-u6f.6.1, beadboard-r1i

[MEMORY][AGENT][SOFT] Parallelize independent work with clear ownership

Scope: Any task with 2+ independent units of work.
Out of Scope: Single-file trivial edits.
Rule: Parallelize independent reads/exploration and isolate ownership for independent execution threads.
Rationale: Reduces cycle time while preserving traceability.
Failure Mode: Serial execution on independent work causes avoidable delays.

Given independent subtasks, when execution starts, then each subtask has explicit ownership and verification evidence.
Verification command(s): bd dep tree <epic-id>; bd ready; git status --short


Provenance linked: bb-bvn, beadboard-r1i, beadboard-68k

[MEMORY][ARCH][HARD] Dependencies model execution order, not visual order

Scope: Dependency graph design and updates.
Out of Scope: Visual layout decisions that do not alter execution semantics.
Rule: Dependencies encode execution order and blocking semantics, never visual grouping.
Rationale: Keeps ready/blocked states truthful and machine-reliable.
Failure Mode: Incorrect dependency direction causes false blocking or unsafe parallelism.

Given a dependency update, when graph state is queried, then blocked/ready outcomes match intended execution order.
Verification command(s): bd dep tree <issue-id>; bd blocked; bd ready


Provenance linked: beadboard-68k.4, beadboard-68k.5, beadboard-r1i.1

[MEMORY][ARCH][HARD] Shared logic for cross-view behavior

Scope: Repeated logic used by multiple views or pages.
Out of Scope: One-off prototypes and disposable experiments.
Rule: Reuse shared paths/components for cross-view behavior; avoid one-off logic drift.
Rationale: Prevents silent divergence between Kanban, Graph, and API views.
Failure Mode: Patching one surface only creates inconsistent user behavior.

Given a behavior change touching multiple views, when implementation lands, then shared logic path is reused and covered by tests.
Verification command(s): rg "<shared-function-or-hook>" src tests; npm run test


Provenance linked: beadboard-68k.4, beadboard-68k.2, bb-u6f.3

[MEMORY][UX][SOFT] User-facing copy must stay simple and explicit

Scope: UI copy in labels, controls, and status messaging.
Out of Scope: Internal comments and engineering-only diagnostics.
Rule: Use simple user-facing language and explicit status words.
Rationale: Reduces ambiguity and onboarding friction.
Failure Mode: Dense or vague copy increases mistakes and support load.

Given newly introduced UI copy, when reviewed, then wording is concise and unambiguous for first-time users.
Verification command(s): npm run lint; targeted UI review in changed components


Provenance linked: beadboard-03r, beadboard-8rg, bb-xtu, bb-tpc.3

[MEMORY][RELIABILITY][HARD] Triage stale-state bugs via parity and watcher checks

Scope: Bug triage and remediation for stale state, watcher, and refresh failures.
Out of Scope: Non-state-related cosmetic bugs.
Rule: Verify source-of-truth parity first, then inspect read paths and watcher inputs before patching symptoms.
Rationale: Prevents superficial fixes that hide core data flow faults.
Failure Mode: Repeated regressions when stale-state root cause remains unresolved.

Given a stale update bug, when triage starts, then parity, read path, and watcher inputs are explicitly checked before implementation.
Verification command(s): bd show <issue-id>; npm run test -- tests/lib/watcher.test.ts


Provenance linked: bb-ff6, bb-6bx, beadboard-5vs

[MEMORY][RELIABILITY][SOFT] Workarounds require trigger rollback and owner

Scope: Temporary workaround decisions under delivery pressure.
Out of Scope: Final architecture decisions already ratified.
Rule: Any workaround must include trigger conditions, rollback criteria, and owner for retirement.
Rationale: Keeps tactical decisions from becoming accidental permanent architecture.
Failure Mode: Undocumented workaround debt accumulates and obscures system intent.

Given a workaround task, when created, then trigger, rollback criteria, and retirement owner are present.
Verification command(s): bd show <workaround-id>


Completed provenance upgrade: all 7 canonical memory beads now link to source closed beads and include metadata keys evidence_ids + plan_refs. Updated help/memory docs to require provenance capture and provenance checks in task-start workflow.


Canonical memory provenance linked to historical beads and help/memory updated


Adding regular memory contribution cadence and provenance relation rules to both AGENTS manuals.

Enforce regular memory contribution + provenance relations in AGENTS manuals

Update root and beadboard AGENTS manuals to require recurring memory additions and explicit provenance relation/metadata rules for canonical memory nodes.

Both manuals include mandatory post-close memory review cadence and provenance relation commands/requirements.


Updated both AGENTS manuals: added mandatory post-close memory review cadence, provenance relation commands, required evidence_ids/plan_refs metadata, and fresh-agent provenance validation steps.


AGENTS manuals now enforce regular memory additions and provenance relations


TASK CONTEXT
- Bead ID: beadboard-8ij.1
- Title: Extract useArchetypePicker hook from AssignmentPanel
- Parent/Epic: beadboard-8ij
- Dependencies (must be done first): none (first in phase)

TASK CONTRACT
- Goal: Extract the archetype fetching and assignment logic from AssignmentPanel into a reusable useArchetypePicker hook so it can be used in SocialCard, LeftPanel, and TopBar without duplicating code.
- Success Criteria:
  - New hook at src/hooks/use-archetype-picker.ts exports useArchetypePicker
  - Hook encapsulates: fetching archetypes from /api/archetypes, selected archetype state, and handleAssign(issueId) function that calls /api/mission/assign
  - AssignmentPanel refactored to use the new hook (no behaviour change, existing graph assign mode still works)
  - npm run typecheck passes
- Scope:
  - src/hooks/use-archetype-picker.ts (new file)
  - src/components/graph/assignment-panel.tsx (refactor to use hook)
  - Read AssignmentPanel fully before extracting to understand current API calls and state
- Out of Scope:
  - Changing AssignmentPanel UI
  - Using the hook in SocialCard or TopBar yet (beadboard-8ij.2, beadboard-8ij.3)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


Hook extracted with archetype selection state and assignment logic. AssignmentPanel refactored to use hook. Typecheck passes with 0 errors.


useArchetypePicker hook created and integrated into AssignmentPanel


TASK CONTEXT
- Bead ID: beadboard-8ij.2
- Title: Add inline Assign affordance to SocialCard for blocked/unassigned tasks
- Parent/Epic: beadboard-8ij
- Dependencies (must be done first): beadboard-8ij.1

TASK CONTRACT
- Goal: Tasks in blocked or open/unassigned state should show an Assign button directly on the SocialCard, opening an inline archetype picker without leaving the social view or opening a modal.
- Success Criteria:
  - SocialCard shows an Assign button when issue.status === 'blocked' or (issue.status === 'open' and no assignee)
  - Clicking Assign opens an inline dropdown/popover using useArchetypePicker
  - Selecting an archetype calls handleAssign and updates the card
  - Cards with an existing assignee do not show the Assign button
  - npm run typecheck passes
- Scope:
  - src/components/social/social-card.tsx — add conditional Assign button
  - Use useArchetypePicker hook from beadboard-8ij.1
  - Inline UI only — no modal, no view switch
- Out of Scope:
  - Changing SocialCard layout for other states
  - Agent presence/liveness indicators (Phase 4)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


Inline assign affordance added to blocked/unassigned cards. Uses useArchetypePicker hook. Archetypes fetched in SocialPage and passed to SocialCard. Typecheck passes with 0 errors.


Inline assign working on SocialCard for blocked/unassigned tasks


TASK CONTEXT
- Bead ID: beadboard-8ij.3
- Title: Add Launch Swarm action to LeftPanel epic rows
- Parent/Epic: beadboard-8ij
- Dependencies (must be done first): beadboard-8ij.1

TASK CONTRACT
- Goal: Each epic row in the LeftPanel should have a Launch Swarm affordance (button or icon) that opens LaunchSwarmDialog scoped to that epic.
- Success Criteria:
  - Each epic row shows a launch icon/button (visible on hover or always)
  - Clicking it opens LaunchSwarmDialog with projectRoot pre-filled
  - On successful launch, navigates to ?swarm=X so the new swarm appears in the right panel
  - Existing epic row expand/collapse and epic selection behaviour is unchanged
  - npm run typecheck passes
- Scope:
  - src/components/shared/left-panel.tsx — add launch button to epic row render
  - src/components/swarm/launch-dialog.tsx — check props (projectRoot, onSuccess already exist)
- Out of Scope:
  - TopBar Launch Swarm (beadboard-8ij.4)
  - Swarm overlay on graph

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


Launch Swarm button added to epic rows in LeftPanel. LaunchSwarmDialog renders conditionally. Typecheck passes with 0 errors.


Launch Swarm accessible from LeftPanel epic rows


TASK CONTEXT
- Bead ID: beadboard-8ij.4
- Title: Add LaunchSwarmDialog to TopBar as global action
- Parent/Epic: beadboard-8ij
- Dependencies (must be done first): beadboard-8ij.1

TASK CONTRACT
- Goal: Promote swarm launching to a top-level action in TopBar so the operator can start a swarm from any view without navigating to a specific page or epic first.
- Success Criteria:
  - TopBar shows a Launch Swarm button (or icon with tooltip)
  - Clicking it opens LaunchSwarmDialog (src/components/swarm/launch-dialog.tsx)
  - On success, navigates to ?swarm=X so the new swarm appears in the right panel immediately
  - Existing TopBar layout and other controls are unaffected
  - npm run typecheck passes
- Scope:
  - src/components/shared/top-bar.tsx — add launch button and dialog trigger
  - src/components/shared/unified-shell.tsx — pass onSuccess handler to TopBar if needed
  - src/components/swarm/launch-dialog.tsx — props: projectRoot, onSuccess
- Out of Scope:
  - Changing LaunchSwarmDialog internals
  - LeftPanel launch (beadboard-8ij.3)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.


Launch Swarm button added to TopBar. LaunchSwarmDialog accessible globally. Typecheck passes with 0 errors.


LaunchSwarmDialog promoted to global TopBar action


TASK CONTEXT
- Bead ID: beadboard-8ij.5
- Title: Wire ?swarm=X URL param to highlight swarm tasks in both views
- Parent/Epic: beadboard-8ij (Phase 3: Coordination Layer Integration)
- Dependencies (must be done first): none (can run in parallel with 8ij.1-8ij.4)

TASK CONTRACT
- Goal: Make swarm selection visible in both Social and Graph views by wiring the swarmId URL param to highlight/overlay logic.
- Success Criteria:
  - SocialPage reads swarmId from useUrlState and highlights cards assigned to that swarm
  - GraphPage/SmartDag reads swarmId and renders a visual overlay showing the swarm subgraph
  - Agent avatars appear on graph nodes for tasks assigned to the selected swarm
  - npm run typecheck passes
- Scope:
  - Modify SocialPage to accept and use swarmId prop for card highlighting
  - Modify GraphPage/SmartDag to accept and use swarmId for subgraph overlay
  - Read swarmId from useUrlState (already exists) and pass to both views
  - Visual treatment: subtle highlight border or background on swarm cards/nodes
- Out of Scope:
  - Creating new swarm assignment logic (that's in 8ij.1-8ij.4)
  - Modifying the swarm data model or APIs
  - Adding swarm creation UI (that's LaunchSwarmDialog in 8ij.4)

IMPLEMENTATION CONSTRAINTS
- useUrlState already supports swarmId param - do not modify the URL state contract
- Preserve existing card/node rendering logic - add overlay treatment only
- Reuse AgentAvatar component for graph node overlays
- Keep visual treatment consistent with existing theme tokens

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Manual verification:
  - Navigate to /?view=social&swarm=test-swarm-id and confirm cards are highlighted
  - Navigate to /?view=graph&swarm=test-swarm-id and confirm subgraph overlay appears
- Report any edge cases (empty swarm, invalid ID) in completion notes

When ?swarm=X is in URL: (1) SocialPage highlights cards assigned to that swarm, (2) GraphPage/SmartDag overlays swarm subgraph with agent avatars on nodes, (3) Both views read swarmId from useUrlState, (4) npm run typecheck passes


swarmId wired from URL to SocialPage with visual highlighting on cards. swarmId passed to GraphPage/SmartDag for future overlay implementation. Typecheck passes with 0 errors.


Swarm URL param wired to both views with visual highlighting foundation


Added label: template:release


Completed: Removed LaunchSwarmDialog, rewired all Rocket buttons to AssignmentPanel. Commits c246cea, a0787f8.


Completed: Fixed cross-view nav with atomic buildUrlParams URL updates. Commit c246cea.


Completed: Standardized icon buttons across DAG nodes and social cards. Commits c246cea, a0787f8.


Completed: Created TelemetryStrip with real /api/activity + SSE data. Commit 114bb18.


Completed: Added minimize/restore flow for all feed panels. Commit a0787f8.


Completed: Unified-shell wired as central panel state coordinator. Commit c246cea.


Completed: All subtasks done. Full UX consolidation shipped on feat/themev2. Commits c246cea, a0787f8, 114bb18.


Added label: memory


Added label: mem-canonical


Added label: mem-hard


Added label: memory-arch


Added label: mem-soft


Added label: memory-ux


Added label: brainstorm


Added label: memory-view


Added label: ux


Added label: dolt


Added label: history


Added label: frontend


Added label: innovation


Added label: roadmap


Added label: planning


Starting TDD: lift useSessionFeed/livenessMap to UnifiedShell

TASK CONTEXT
- Bead ID: beadboard-x3l.1
- Title: Move useSessionFeed/livenessMap up to UnifiedShell
- Parent/Epic: beadboard-x3l
- Dependencies (must be done first): none (first in phase)

TASK CONTRACT
- Goal: useSessionFeed is currently only called in sessions-page.tsx (deprecated route). Call it in UnifiedShell and make livenessMap available as a prop to SocialCard and SmartDag.
- Success Criteria:
  - useSessionFeed(projectRoot) called in UnifiedShell
  - livenessMap: Record<string, string> available in UnifiedShell scope
  - livenessMap passed down to SocialPage and SmartDag as a prop (even if they don't use it yet — that is beadboard-x3l.2 and beadboard-x3l.3)
  - No duplicate SSE connections opened (verify useSessionFeed does not re-subscribe on re-render)
  - npm run typecheck passes
- Scope:
  - src/components/shared/unified-shell.tsx — add useSessionFeed call
  - src/hooks/use-session-feed.ts — read to understand return shape before using
  - src/components/social/social-page.tsx — add livenessMap prop (pass through to cards later)
  - src/components/graph/smart-dag.tsx — add livenessMap prop (use in x3l.3)
- Out of Scope:
  - Rendering agent avatars yet (beadboard-x3l.2, x3l.3)
  - Removing useSessionFeed from sessions-page.tsx (leave it, legacy route)

IMPLEMENTATION CONSTRAINTS
- Preserve existing backend/API contracts unless explicitly stated otherwise.
- Reuse shared components and logic; avoid one-off forks.
- Keep changes targeted and minimal for this bead.

VERIFICATION REQUIREMENTS
- Required commands:
  - npm run typecheck
  - npm run lint
  - npm run test
- Report any remaining risks and follow-up beads explicitly.