Skip to content

Live Observer Dashboard

The Claw dashboard lets you watch a society execute in real-time. It visualizes the agent graph, streams events as they flow along edges, and tracks artifact changes — all in your browser.

Quick Start

# 1. Build the dashboard (one time)
cd dashboard && npm install && npm run build && cd ..

# 2. Run any society with the dashboard
uv run python examples/pr_review_dashboard.py

# 3. Open http://127.0.0.1:8765 in your browser

That's it. The dashboard shows the society graph, streams events in real-time, and shuts down when the society completes.

Using serve() in Your Own Code

The serve() function is a drop-in replacement for calling LocalRuntime.run() directly. It runs the society and dashboard server concurrently:

import asyncio
from claw import Society, Agent, Delegation, serve
from claw.llm import MockLLM

# Build your society
s = Society(name="my-society")
alice = Agent(name="alice", role="worker", model="mock")
bob = Agent(name="bob", role="reviewer", model="mock")
s.connect(alice, bob, Delegation())

# Run with dashboard (instead of LocalRuntime.run())
result = asyncio.run(serve(
    s,
    task="Do something interesting",
    llm=MockLLM(),
))

serve() Parameters

Parameter Type Default Description
society Society required The society to execute
task str required Task description to seed the first event
llm LLM required LLM backend (MockLLM, LiteLLMBackend, etc.)
host str "127.0.0.1" Server bind address
port int 8765 Server bind port
artifacts list None Artifacts to pre-register

Return Value

serve() returns a SocietyResult — the same object you get from LocalRuntime.run(). The server shuts down automatically after the society completes.

Dashboard Layout

┌─────────────────────────────────────────────────────┐
│ 🦀 Claw │ society-name │ Running │ Events: 12 │ ● │  ← Header
├────────────────────────────────┬────────────────────┤
│                                │ 10:32:01 pm → cod… │
│         Graph View             │ 10:32:01 coder → … │
│                                │ 10:32:02 reviewer… │  ← Event Feed
│   [pm] ──→ [coder] ──→ [rev]  │ 10:32:02 coder → … │
│                                │ 10:32:03 reviewer… │
├────────────────────────────────┴────────────────────┤
│ Agent: coder │ Artifacts │                          │  ← Detail Panel
│ Role: implementer │ Model: mock │ Events: 5         │
└─────────────────────────────────────────────────────┘
  • Graph View (center, 60%): Agent nodes with status indicators, color-coded edges
  • Event Feed (right, 25%): Chronological log with filtering
  • Detail Panel (bottom, 15%): Agent details or artifact version history

Node Status Colors

Status Color Meaning
Idle Gray Waiting for events
Active Green Currently executing
Completed Blue Society has terminated

Edge Type Colors

Edge Type Color
Cooperation Green
Competition Red
Oversight Blue
Delegation Orange
Coopetition Purple

Development Workflow

For working on the dashboard frontend with hot module replacement:

# Terminal 1: Run the Python server + society
uv run python examples/pr_review_dashboard.py

# Terminal 2: Run Vite dev server with HMR
cd dashboard && npm run dev

Then open http://localhost:5173 (Vite dev server). The Vite config proxies /ws and /api requests to the Python server on port 8765.

Advanced: Manual Setup

If you need more control (e.g., custom CORS, running the observer independently):

import asyncio
import uvicorn
from claw import LocalRuntime, Society
from claw.server import WebSocketObserver, create_app

society = build_your_society()
llm = your_llm_backend()

# Create observer and app separately
observer = WebSocketObserver(society, buffer_size=1000)
app = create_app(observer, cors_origins=["https://my-domain.com"])

# Create runtime with observer
runtime = LocalRuntime(llm, observer=observer)

# Run server and society however you want
async def main():
    config = uvicorn.Config(app, host="0.0.0.0", port=8765)
    server = uvicorn.Server(config)

    server_task = asyncio.create_task(server.serve())
    result = await runtime.run(society, "my task")
    server.should_exit = True
    await server_task
    return result

asyncio.run(main())

REST API

The server also exposes REST endpoints (useful for debugging or building custom UIs):

Endpoint Method Description
/ GET Serves the dashboard (or a help page if not built)
/api/society GET Current society graph as JSON
/api/artifacts GET Current artifact state
/api/trace GET Full buffered event trace
/ws WebSocket Live event stream

Late-Joining Clients

The server buffers the last 500 events (configurable via buffer_size). If you open the dashboard after the society has started, you'll receive a replay of buffered events before switching to the live stream.

# Custom buffer size
observer = WebSocketObserver(society, buffer_size=2000)