<p align="center">
  <img src="assets/dobby.gif" alt="Dobby" width="200">
</p>

<h1 align="center">Dobby</h1>

<p align="center">
  <em>A distributed meta-agent orchestrator that manages coding agents across your infrastructure.</em>
</p>

<p align="center">
  <a href="https://pypi.org/project/dobby-orchestrator/"><img src="https://img.shields.io/pypi/v/dobby-orchestrator?style=flat-square" alt="PyPI"></a>
  <img src="https://img.shields.io/pypi/pyversions/dobby-orchestrator?style=flat-square" alt="Python 3.11+">
  <a href="https://github.com/simonucl/dobby/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/simonucl/dobby/ci.yml?style=flat-square&label=CI" alt="CI"></a>
  <a href="https://github.com/simonucl/dobby/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT License"></a>
  <a href="http://localhost:8420/dashboard"><img src="https://img.shields.io/badge/dashboard-live-brightgreen?style=flat-square" alt="Dashboard"></a>
</p>

---

Dobby is a meta-agent orchestrator that dispatches coding tasks to AI agents (Claude Code, Codex) across multiple machines. Submit work from Slack, CLI, Claude Code (MCP), or the REST API — agents execute on your Mac, cloud servers, or GPU clusters while you track everything in a real-time web dashboard with live logs, cost accounting, and structured results.

<p align="center">
  <img src="assets/dobby_architecture.jpg" alt="Dobby Architecture" width="700">
</p>

## Features

- **Hub-and-spoke architecture** — one hub coordinates local and remote agents
- **Real-time dashboard** — live task tracking, agent network view, heatmap, flow visualization
- **Slack bot** — natural language task submission with react-to-confirm workflow
- **MCP server** — use Dobby tools natively inside Claude Code
- **Worktree parallel execution** — run multiple agents on the same repo via git worktrees
- **Plan-then-execute** — draft tasks for review before dispatching
- **Priority queue** — urgent / high / normal / low with per-project concurrency control
- **Scheduling** — cron expressions, interval repeats, and task dependency chains
- **Batch dispatch** — submit multiple tasks from a YAML file
- **Remote control** — interactive Claude Code sessions via `dobby remote`
- **GPU monitoring** — poll and track GPU jobs across nodes
- **Export** — dump task and result data as CSV or JSON

## Setup

### Prerequisites

- Python >= 3.11
- [uv](https://github.com/astral-sh/uv) (recommended) or pip

### Installation

Install from PyPI:

```bash
pip install dobby-orchestrator
```

Or with uv:

```bash
uv pip install dobby-orchestrator
```

### Development Installation

For development or contributing:

```bash
git clone https://github.com/simonucl/dobby.git
cd dobby
uv sync
```

Or with pip:

```bash
pip install -e .
```

### First-time setup

Run the interactive setup wizard:

```bash
uv run dobby init
```

This will:
1. Create a `.env` file from the template
2. Prompt for your hub URL (default: `http://127.0.0.1:8420`)
3. Optionally configure Slack integration tokens
4. Register the current directory as a project
5. Print the MCP config snippet for Claude Code

Or do it manually:

```bash
cp .env.example .env
# Edit .env with your values
```

See `.env.example` for all supported environment variables.

## Quick Start

```bash
# 1. Start the hub daemon
dobby start

# 2. Register a project
dobby register ~/projects/my-project --name myproject

# 3. Submit a task
dobby add "write unit tests for the auth module" --project myproject

# 4. Check status
dobby status
```

The daemon starts on `http://localhost:8420`. Open `http://localhost:8420/dashboard` for the web UI.

**Connect a remote spoke** (on any machine with Dobby installed):

```bash
dobby agent --hub https://your-hub-url --id my-machine
```

**Start the Slack bot** (requires Slack tokens in `.env`):

```bash
dobby slack
```

### Setting up the Slack bot

1. Go to [api.slack.com/apps](https://api.slack.com/apps) and create a new app
2. Under **OAuth & Permissions**, add these Bot Token Scopes: `chat:write`, `channels:history`, `groups:history`, `im:history`, `reactions:read`, `reactions:write`, `users:read`
3. Under **Socket Mode**, enable it and generate an app-level token with `connections:write` scope
4. Under **Event Subscriptions**, subscribe to: `message.channels`, `message.groups`, `message.im`, `reaction_added`
5. Install the app to your workspace
6. Copy tokens into your `.env`:
   ```
   SLACK_BOT_TOKEN=xoxb-...
   SLACK_APP_TOKEN=xapp-...
   ```

### Connecting Claude Code via MCP

Add to `~/.claude/.mcp.json` (global) or `.mcp.json` (per-project):

```json
{
  "mcpServers": {
    "dobby": {
      "command": "uv",
      "args": ["run", "--project", "/path/to/dobby", "dobby-mcp"],
      "env": {
        "DOBBY_URL": "http://127.0.0.1:8420"
      }
    }
  }
}
```

Replace `/path/to/dobby` with the absolute path to your cloned Dobby repo. If your hub is exposed remotely, replace the `DOBBY_URL` with the public URL.

### Registering projects and adding spokes

**Projects** are local repositories that Dobby manages. Register one:

```bash
uv run dobby register /absolute/path/to/repo --name myproject --context "A short description"
```

**Spokes** are remote machines that run agents. On the remote machine, install Dobby and run:

```bash
uv run dobby agent --hub https://your-hub-url --id gpu-node-1
```

The spoke will register with the hub, send heartbeats, and poll for tasks.

## Architecture

```
You ──→ CLI / Slack / MCP / API ──→ Dobby Hub (asyncio + aiohttp, port 8420)
                                          │
                                    ┌─────┴─────┐
                                    │  SQLite DB │
                                    └─────┬─────┘
                                          │
                          ┌───────────────┼───────────────┐
                          ▼               ▼               ▼
                    Local Dispatch   Spoke Agent #1   Spoke Agent #2
                    (Claude Code)    (remote machine)  (GPU node)
```

Tasks enter a priority queue (`urgent > high > normal > low`). The queue manager picks the next eligible task and dispatches it to a local agent or holds it until a remote spoke claims it. One agent per project by default (configurable). Spokes register with the hub, send periodic heartbeats, and long-poll for work. On completion, results (summary, artifacts, cost) are collected and stored.

| Hub Component | Purpose |
|---------------|---------|
| Queue Manager | Priority scheduling with per-project concurrency locks |
| Dispatcher | Spawns Claude Code subprocesses with semaphore concurrency |
| Collector | Parses agent output into structured results |
| Store | SQLite with WAL mode — tasks, projects, results, spokes |
| EventBus | Publishes state changes via SSE for live dashboard updates |
| REST API | ~30 endpoints for tasks, projects, results, batches, spokes |

## File Structure

```
dobby/
├── cli/          # Click CLI (main.py, client.py)
├── core/         # Hub daemon, API server, dispatcher, queue, collector
│   ├── daemon.py       # Main daemon entry point
│   ├── api.py          # aiohttp REST endpoints
│   ├── dispatcher.py   # Agent process management
│   ├── queue.py        # Priority queue manager
│   ├── collector.py    # Result parsing and collection
│   ├── spoke_agent.py  # Remote spoke agent logic
│   ├── worktree.py     # Git worktree management
│   └── remote_session.py  # Interactive remote control
├── store/        # SQLite persistence layer
├── web/          # Dashboard (HTML/CSS/JS, served by aiohttp)
├── slack/        # Slack bot (Bolt framework)
├── mcp/          # MCP server for Claude Code integration
├── deploy/       # VPS provisioning (Vultr)
├── models.py     # Shared data models
└── config.py     # Configuration loading
```

## CLI Reference

| Command | Description |
|---------|-------------|
| `dobby init` | Interactive first-time setup (creates `.env`, registers project, prints MCP config) |
| `dobby start` | Start the Dobby daemon |
| `dobby agent --hub URL --id NAME` | Run as a spoke agent connected to a remote hub |
| `dobby register PATH --name NAME` | Register a project repository |
| `dobby add "desc" --project NAME` | Queue a task (flags: `--priority`, `--cron`, `--every`, `--after`) |
| `dobby plan "desc" --project NAME` | Create a draft task requiring review |
| `dobby batch FILE` | Dispatch a batch of tasks from a YAML file |
| `dobby status [PROJECT]` | Show task status, optionally filtered by project |
| `dobby detail-status TASK_ID` | Live agent activity (files, tools, tokens) |
| `dobby logs TASK_ID` | Fetch task logs |
| `dobby results TASK_ID\|PROJECT` | Show results for a task or project |
| `dobby batch-status BATCH_ID` | Check batch progress |
| `dobby cancel TASK_ID` | Cancel a running or pending task |
| `dobby retry TASK_ID [--cascade]` | Retry a failed task (cascade retries dependents) |
| `dobby stats` | Aggregate statistics (tokens, costs) |
| `dobby projects` | List registered projects |
| `dobby export [--project] [--format]` | Export data as CSV or JSON |
| `dobby remote` | Start a Claude Code remote control session |
| `dobby slack` | Start the Slack bot |
| `dobby deploy` | Manage VPS deployment on Vultr |

## Slack Bot

Mention `@Dobby` in a channel or DM:

```
@Dobby fix the login bug in spare
@Dobby add docs to dobby with high priority
@Dobby run eval on spare-tillicum using codex
```

**Batch tasks** (bullet list):

```
@Dobby
- fix tests in spare
- add docs to dobby
- run eval on adpo
```

**Status commands:**

| Command | Description |
|---------|-------------|
| `status` | Bullet-point overview (last 4h) |
| `status 12h` | Custom time range |
| `summary` | Detailed AI summary (last 12h) |
| `summary spare 24h` | Per-project with time range |
| `running` | Currently executing tasks |
| `projects` | List all projects |
| `help` | Show all commands |

Task submissions use **react-to-confirm**: Dobby posts a preview, react with a checkmark to submit or X to cancel. Reply to the preview to edit before submitting.

## MCP Server

See [Connecting Claude Code via MCP](#connecting-claude-code-via-mcp) above for setup.

Available tools: `dobby_add_task`, `dobby_batch_add`, `dobby_plan_task`, `dobby_status`, `dobby_get_task`, `dobby_results`, `dobby_list_results`, `dobby_cancel`, `dobby_retry`, `dobby_detail_status`, `dobby_stats`, `dobby_projects`, `dobby_register`.

## Dashboard

The web dashboard at `http://localhost:8420/dashboard` provides real-time monitoring via Server-Sent Events:

- **Agent Network** — connected spokes with heartbeat status and running task indicators
- **Heatmap** — GitHub-style activity chart showing completions per project per day
- **Flow View** — agent execution timeline (click any task → Logs → Flow)
- **Live Jobs** — currently running tasks with real-time updates
- **Usage** — Claude rate limit utilization bars
- **Task list** — searchable, filterable by status and project
- **Task detail** — tabbed panel with Logs, Details, and Timeline views
- **Batch tracking** — multi-task batch progress
- **Dark/light theme** — toggle with localStorage persistence

## Configuration

### Daemon config (`dobby.yaml`)

Optional. Pass with `dobby start --config dobby.yaml`:

```yaml
port: 8420                    # REST API + dashboard port
host: 127.0.0.1               # Bind interface
max_concurrent_agents: 5      # Max simultaneous agents
default_timeout: 1800         # Task timeout in seconds (30 min)
gpu_poll_interval: 300        # GPU job poll interval (5 min)
results_dir: results          # Task artifact/log storage
db_path: dobby.db             # SQLite database path
api_key: null                 # Optional API key for auth
webhook_url: null             # POST on task completion/failure
stale_timeout: 1800           # Seconds before marking idle task as stale
hub_url: ""                   # Public URL for dashboard links (Slack, etc.)
github_url: ""                # GitHub repo URL shown in dashboard sidebar
```

### Exposing the hub remotely (Cloudflare Tunnel)

```bash
cloudflared tunnel create dobby
cloudflared tunnel route dns dobby your-subdomain.example.com
cloudflared tunnel run --url http://localhost:8420 dobby
```

Then set `DOBBY_URL=https://your-subdomain.example.com` for spokes and the MCP server.

### Project Policies

Set per-project behavior via the API:

- `default_backend` — `claude` or `codex`
- `default_timeout` — override global timeout
- `max_concurrent` — allow multiple agents per project
- `default_priority` — default task priority
- `auto_chain` — auto-depend new tasks on the latest pending/running task

## REST API

The hub exposes ~30 REST endpoints on port 8420. Key routes:

```
POST   /tasks                    Create a task
GET    /tasks                    List tasks
GET    /tasks/{id}               Get task status
PATCH  /tasks/{id}               Update a task
POST   /tasks/{id}/retry         Retry a task
GET    /tasks/{id}/events        SSE event stream
GET    /tasks/{id}/artifacts     Task artifacts
GET    /tasks/{id}/detail-status Live agent status
GET    /tasks/{id}/logs          Task logs
POST   /projects                 Register a project
GET    /projects                 List projects
GET    /results                  List results
GET    /results/{task_id}        Get task result
POST   /batches                  Create a batch
GET    /batches/{batch_id}       Batch status
POST   /spokes/register          Register a spoke
GET    /spokes                   List spokes
GET    /stats                    Queue statistics
GET    /events                   Global SSE stream
GET    /health                   Health check
```

## Safety Warning

Dobby dispatches AI agents that execute code on your machines. Agents run with the permissions of the user that started them. By default, Claude Code runs in interactive mode and asks for permission before executing commands.

If you use `--dangerously-skip-permissions` (or configure agents to do so), agents will execute arbitrary commands **without confirmation**. Use this only on isolated machines or sandboxed environments. You are responsible for the actions agents take on your infrastructure.

## Citing

If you use Dobby in your research, please cite:

```bibtex
@software{dobby2025,
  title  = {Dobby: A Distributed Meta-Agent Orchestrator},
  author = {Simon Yu},
  year   = {2025},
  url    = {https://github.com/simonucl/dobby}
}
```

## License

Dobby is free. Dobby has no master.
