Skip to content

Latest commit

 

History

History
164 lines (133 loc) · 6.76 KB

File metadata and controls

164 lines (133 loc) · 6.76 KB

Agent Instructions — Beads Viz

Read-only task graph visualizer for Claude Desktop. MCP server (TypeScript/Node.js) wrapping the bd CLI, with a Svelte single-file UI bundle showing interactive DAG visualization, list view, and stats dashboard. Runs inside Claude Desktop as an MCP App (sandboxed iframe).

Quick Start

npm install
npm run build        # Build UI bundle + server
npm run dev          # Vite dev server (UI only, no MCP host)

Claude Desktop Configuration

Add to ~/.config/claude-desktop/config.json:

{
  "mcpServers": {
    "beads-viz": {
      "command": "node",
      "args": ["dist/server/index.js"],
      "cwd": "/path/to/your/beads-project"
    }
  }
}

The server discovers the Beads project by walking up from cwd to find .beads/config.yaml.

Architecture

Claude Desktop (MCP Host)
  ├── Chat conversation
  │     "Show me the task graph"
  │     → calls visualize-tasks tool
  ├── MCP Server (Node.js, stdio)
  │     ├── visualize-tasks → bd list --all --json → summary + tasks + ui ref
  │     ├── poll-tasks (app-only) → bd list --all --json → fresh data
  │     ├── show-task (app-only) → bd show <id> --json → task detail
  │     └── ui://beads-viz resource → serves dist/index.html
  └── Sandboxed iframe (MCP App)
        ├── Top Strip (project, stats pills, DAG/LIST/STATS tabs)
        ├── Canvas (DAG / List / Stats views)
        ├── Bottom Drawer (task detail on click)
        └── Polls server every 3s for fresh data

Key insight: The UI is read-only. All task mutations (claim, close, create) happen through the agent chat, not the UI.

Project Structure

src/
├── server/                 # MCP server (Node.js target)
│   ├── index.ts            # Entry point: McpServer + stdio transport
│   ├── tools.ts            # Tool registrations (visualize, poll, show)
│   ├── beads-client.ts     # bd CLI wrapper (execFile + JSON parse)
│   └── types.ts            # Server-side TypeScript types
└── ui/                     # Svelte app (browser target, Vite-bundled)
    ├── App.svelte           # Root: view switching, layout, keyboard
    ├── main.ts              # Svelte mount + MCP bridge init
    ├── app.css              # CSS variables, reset, animations
    ├── index.html           # Vite entry point
    ├── components/
    │   ├── TopStrip.svelte  # 32px strip: project, stats, tabs
    │   ├── DagView.svelte   # ELK.js DAG canvas + SVG edges
    │   ├── DagNode.svelte   # 156x42 node card with phase colors
    │   ├── ListView.svelte  # Status-grouped task list
    │   ├── StatsView.svelte # Progress ring, phase bars, velocity
    │   └── TaskDrawer.svelte # Bottom drawer with task details
    └── lib/
        ├── elk-layout.ts    # ELK.js layout computation
        ├── phase.ts         # 9-phase color system (dark + light)
        ├── stores.ts        # Svelte writable stores
        ├── mcp-bridge.ts    # MCP App SDK bridge (connect, poll, theme)
        └── types.ts         # UI-side TypeScript types

Build System

Command What it does
npm run build:ui Vite build → dist/index.html (single-file bundle)
npm run build:server tscdist/server/*.js
npm run build Both of the above
npm run dev Vite dev server at localhost:5173 (standalone UI testing)
npm start Run MCP server via stdio (node dist/server/index.js)

The UI is built as a single self-contained HTML file using vite-plugin-singlefile. All CSS, JS, and Svelte compiled output are inlined. The server reads this file at runtime to serve as the ui://beads-viz MCP resource.

Key Design Decisions

  1. TypeScript MCP Server — MCP Apps SDK is JS/TS-native; Node.js is the natural choice
  2. Svelte 5 — Small bundle size, reactive stores, matches Hangar's tech stack
  3. ELK.js — Layered DAG algorithm; deterministic layout unlike D3-force
  4. Polling (3s) — MCP Apps run in sandboxed iframes; no WebSocket/SSE possible
  5. bd CLI wrapping — Shell out to bd via execFile rather than parsing JSONL directly
  6. Single HTML bundle — Standard MCP App packaging; served as resource
  7. cwd project discovery — Walk up to find .beads/config.yaml, same as bd itself

Phase Color System

9 phases ported from Hangar IDE. Colors map from ELK layer index:

Phase Color Dark Fill Dark BG
P1 Cyan #38bdf8 #0c2d48
P2 Indigo #818cf8 #1e1b4b
P3 Purple #c084fc #2e1065
P4 Pink #f472b6 #4a0d2e
P5 Orange #fb923c #431407
P6 Yellow #facc15 #3f3005
P7 Emerald #34d399 #052e16
P8 Red #f87171 #450a0a
P9 Slate #94a3b8 #1e293b

Layer-to-phase mapping: phase = (layer % 9) + 1 (wraps around for deep graphs).

MCP App Data Flow

  1. User asks "Show me the task graph"
  2. Claude calls visualize-tasks tool
  3. Server runs bd list --all --json, returns summary + tasks + _meta.ui.resourceUri
  4. Host opens ui://beads-viz in sandboxed iframe
  5. UI receives initial data via ontoolresult callback
  6. UI starts polling poll-tasks every 3s via app.callServerTool()
  7. Host theme changes propagate via onhostcontextchanged

Task Tracking

This project uses bd (beads) for issue tracking.

bd ready              # Find available work
bd show <id>          # View issue details
bd close <id>         # Complete work
bd graph --all        # View full dependency graph
bd sync               # Sync with git

Development Notes

  • Standalone mode: The UI gracefully handles missing MCP host (for npm run dev testing). The bridge logs a warning and the UI shows empty state.
  • Theme: Dark theme is default. Light theme adapts via [data-theme="light"] CSS and phaseColorMapLight.
  • Bundle size: ~557KB gzipped. ELK.js is ~180KB of that. Could lazy-load for optimization.
  • Node viewport: 156x42px compact nodes designed for ~600x500px MCP App viewport.
  • No mutations from UI: No Claim/Close buttons. The agent handles all task mutations via chat.

Landing the Plane (Session Completion)

When ending a work session, you MUST:

  1. File issues for remaining workbd create "title" --description "..."
  2. Run quality gatesnpm run build must pass
  3. Update issue statusbd close <id> for completed work
  4. Push to remote:
    git pull --rebase
    bd sync
    git push
  5. Verifygit status shows clean, git log shows pushed