midtown 0.3.1

Midtown - a multi-Claude Code workspace manager, inspired by Gastown
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# Midtown

Coordinate multiple **Claude Code** instances working on the same codebase using native Claude Code tasks.

## Quick Start

### 1. Install

From [crates.io](https://crates.io/crates/midtown):

```bash
cargo install midtown
```

Or from source:

```bash
cargo install --path .
```

### 2. Start midtown

From your project directory:

```bash
midtown start
```

This starts the daemon and creates a tmux session with the Lead window.

For multi-repo projects, specify a project name and additional repos:

```bash
midtown start --project myapp --repo /path/to/frontend --repo /path/to/shared-lib
```

### 3. Attach to the session

```bash
midtown attach
```

You're now in the Lead's Claude Code instance.

To attach to a named project from any directory:

```bash
midtown attach myapp
```

### 4. Spawn coworkers

The Lead can spawn coworkers to parallelize work:

```bash
midtown coworker spawn
# => Spawned coworker: lexington
```

Coworkers are named after Manhattan avenues: lexington, park, madison, broadway, amsterdam, columbus, riverside, york, pleasant, vernon.

### 5. Monitor progress

```bash
midtown status
```

Shows: active coworkers, open tasks, open PRs, recent channel activity.

### 6. Stop when done

```bash
midtown stop
```

## Why Midtown?

Midtown is inspired by [Gastown](https://github.com/anthropics/claude-code/tree/main/.claude/docs/gastown.md), but a bit simpler, less exciting, and, well, more mid.

At its core, Midtown is built around an IRC-like messaging model: a shared channel where team members (both the human-facing Lead and autonomous Coworkers) post updates, coordinate handoffs, and stay in sync. This append-only message stream is the backbone of multi-agent collaboration—each Claude Code instance reads the channel at natural pause points, just like checking a team chat.

When you're working with Claude Code on a complex project, you might want to parallelize work:

- The Lead collaborates with the human to create a plan & split up the work into tasks & dependencies.
- Multiple Coworkers implement independent components simultaneously
- The Coworkers review & merge PRs while the Lead & human collaborate on what's next

Midtown provides the infrastructure for this coordination:

- **Channel messaging** - IRC-like append-only message stream for team communication
- **Coworker spawning** - Launch Claude Code instances in isolated git worktrees
- **Task coordination** - Coworkers claim tasks via Claude Code's native task system
- **Multi-project support** - Run multiple projects simultaneously with isolated daemons

## Features

### Multi-Project Support

Midtown can manage multiple projects, each with its own daemon, tmux session, and set of coworkers. Projects are identified by name and can span multiple repositories.

**Starting a project:**

```bash
# Single-repo project (name inferred from directory)
midtown start

# Named project with additional repos
midtown start --project myapp --repo /path/to/frontend --repo /path/to/shared-lib
```

**Managing projects:**

```bash
# List all known projects and their status
midtown project list

# Attach to a specific project
midtown attach myapp
```

Each project gets:
- Its own daemon process and Unix socket
- A tmux session named `midtown-<project>`
- A dedicated channel log and task list
- An auto-assigned webhook port (47023+)
- Per-project configuration in `~/.midtown/projects/<project>/config.toml`

### Multi-Repo Worktrees

For projects spanning multiple repositories, coworkers automatically get isolated worktrees in every repo. When a coworker spawns, midtown creates a git worktree in each configured repo and passes them to Claude Code via `--add-dir` flags. This gives each coworker access to all repos in the project.

When coworkers shut down, worktrees with no commits and no uncommitted changes are automatically cleaned up, along with their branches.

### Shared Webserver

A standalone webserver provides a unified view across all projects:

```bash
midtown webserver run          # Start on port 47022
midtown webserver stop         # Stop the webserver
midtown webserver restart      # Restart the webserver
```

The shared webserver discovers running project daemons and proxies to their per-project webhook servers. Port 47022 is reserved for the shared webserver; per-project daemons use ports 47023+.

The `midtown start` command auto-launches the shared webserver if it's not already running.

### Web App

Access Midtown remotely via the built-in web interface:

```bash
midtown start  # Web server starts automatically
```

The web app provides:
- **Real-time chat** with WebSocket updates and markdown rendering
- **Kanban board** showing tasks and PRs at a glance
- **Tmux tab** for streaming any tmux window
- **Mobile-friendly** Svelte interface for on-the-go monitoring
- **Project tabs** for switching between projects (shared webserver)

### Kanban Board

A visual task board appears in both the terminal (chat pane) and web UI:

- **Backlog** column shows pending tasks
- **In Progress** column shows active tasks with owner and duration
- **Review** column shows open PRs with CI status dots (● green, ● red, ○ pending), author, and reviewer
- **Done** column shows recently merged PRs
- Clickable GitHub hyperlinks to PRs
- Collapsible column headings
- **Repo badges** in multi-repo projects (e.g., `[frontend] PR#42`)

The terminal also displays a **repo status bar** showing the latest commit, CI status, and tag for each repo. Multi-repo projects show one status line per repo.

### Automation

The daemon handles routine coordination automatically:

- **Auto-spawn** - Spawns coworkers when pending tasks are available
- **Auto-shutdown** - Shuts down idle coworkers after 5 minutes
- **Auto-review** - Spawns reviewers for open PRs
- **CI failure handling** - Notifies PR owners of CI failures and merge conflicts
- **Plugin sync** - Automatically installs required plugins for coworkers
- **Duplicate detection** - Kills duplicate workers claiming the same task
- **Reviewer slot reservation** - Reserves 2 coworker slots for PR reviewers
- **Orphan recovery** - Detects and nudges orphaned coworkers to resume their tasks
- **Channel log rotation** - Auto-rotates channel.jsonl every 24 hours

### Chat TUI

The terminal chat pane includes:

- **Selection mode** (`s` key) - Toggle for copying text
- **Coworker colors** - Each coworker has a distinct color
- **Grouped messages** - Messages from the same author are grouped
- **Live updates** - Async tail-based updates for instant message delivery
- **Scrollable history** - Mouse wheel scrolling through message history
- **Expandable input** - Input box grows vertically with line wrapping
- **Scroll-to-bottom button** - Quick return to latest messages

### Notifications & Nudges

Stay informed about important events:

- **@mention routing** - Messages mentioning `@coworker` are delivered to that coworker
- **PR activity nudges** - Coworkers are nudged when their PRs receive comments or reviews
- **Review completion nudges** - Idle PR authors are nudged when reviews finish
- **Feedback detection** - Lead is nudged when coworkers request input
- **Mobile nudges** - Lead receives nudges for messages sent from the mobile web app
- **Orphan detection** - Detects and restarts stuck or orphaned coworkers

### GitHub Integration

Automatic webhook integration with GitHub events (requires `gh auth login`):

- PR opened, merged, closed events appear in channel
- CI status updates (checks passing/failing)
- Review comments and approvals
- Merge conflict detection

### Custom System Prompts

Customize the system prompts for Lead and Coworkers with markdown files:

- `~/.midtown/LEAD.md` / `~/.midtown/COWORKER.md` - Global custom prompts
- `~/.midtown/projects/<project>/LEAD.md` / `COWORKER.md` - Per-project custom prompts

Content from these files is appended to the built-in system prompts. Project-level files supplement global ones.

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                      Human Developer                         │
└─────────────────────────┬───────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                    Lead (Claude Code)                        │
│                    main git worktree                         │
└─────────────────────────┬───────────────────────────────────┘
                          │ midtown CLI
┌─────────────────────────────────────────────────────────────┐
│                    Midtown Daemon                            │
├─────────────────────────┬───────────────────────────────────┤
│      Channel            │          Coworker Manager          │
│   (append-only log)     │       (spawn/track/shutdown)       │
└─────────────────────────┴───────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│              tmux session: midtown-<project>                 │
├─────────────┬─────────────┬─────────────┬───────────────────┤
│    Lead     │  lexington  │    park     │     madison       │
│  (window)   │  (window)   │  (window)   │    (window)       │
│             │  worktree   │  worktree   │    worktree       │
└─────────────┴─────────────┴─────────────┴───────────────────┘
```

All agents run as windows within a single tmux session. Use `Ctrl-b w` to see everyone, `Ctrl-b n/p` to switch between them.

For multi-project setups, each project gets its own daemon and tmux session. A shared webserver on port 47022 provides a unified view:

```
┌─────────────────────────────────────────────────────────────┐
│              Shared Webserver (:47022)                        │
│         discovers and proxies to project daemons             │
└────────┬────────────────────────┬───────────────────────────┘
         │                        │
         ▼                        ▼
┌────────────────────┐   ┌────────────────────┐
│  Project: backend  │   │  Project: frontend │
│  Daemon (:47023)   │   │  Daemon (:47024)   │
│  tmux: midtown-    │   │  tmux: midtown-    │
│        backend     │   │        frontend    │
└────────────────────┘   └────────────────────┘
```

## CLI Reference

```
midtown [OPTIONS] <COMMAND>

Options:
  -C, --repo <PATH>    Path to git repository (defaults to cwd)

Commands:
  start               Start the daemon and tmux session
    --project <NAME>     Project name (overrides auto-detection)
    --repo <PATH>        Additional repository paths (repeatable)
    --daemon-only        Start daemon without tmux session
  stop                Stop daemon and all coworkers
    --keep-session       Keep the tmux session running
  restart             Restart midtown (stop + start)
  attach [PROJECT]    Attach to a project's tmux session
  status              Show system status

  project             Project management
    list                 List all projects and their status

  channel             Channel messaging
    post <MSG>           Post a message
    read                 Read recent messages

  coworker            Coworker management
    spawn                Spawn a new coworker
    list                 List active coworkers
    shutdown <NAME>      Shutdown coworker by name

  webserver            Standalone multi-project webserver
    run                  Start the webserver (port 47022)
    stop                 Stop the webserver
    restart              Restart the webserver
```

## Configuration

Midtown uses two levels of config files:

1. **Global config** at `~/.midtown/config.toml` — applies to all projects
2. **Project config** at `~/.midtown/projects/<project>/config.toml` — overrides per project

Project settings take precedence over global defaults. All fields are optional.

### Global `config.toml`

```toml
# ~/.midtown/config.toml

[default]
bin_command = "midtown"         # CLI command to invoke midtown
chat_layout = "auto"            # "auto", "split", or "window"
chat_min_width = 160            # Min terminal width for split layout (auto mode)
max_coworkers = 16              # Maximum concurrent coworkers

[plugins]
required = [
    "superpowers@claude-plugins-official",
]

[daemon]
webhook_port = 47022                  # Web UI & webhook port (0 to disable)
webhook_secret = "your-secret"        # GitHub webhook signature secret
webhook_restart_interval_secs = 300   # Webhook forwarder restart interval
pr_poll_interval_secs = 30            # PR polling interval
chat_monitor_enabled = true           # Enable @mention routing
```

### Project `config.toml`

Project configs support all global settings plus project metadata:

```toml
# ~/.midtown/projects/myapp/config.toml

[project]
name = "myapp"
repos = ["/path/to/backend", "/path/to/frontend"]
primary_repo = "/path/to/backend"

[default]
bin_command = "cargo run --release --"
max_coworkers = 4

[daemon]
webhook_port = 47023              # Auto-assigned if not set
```

The `[project]` section defines:
- `name` - Project name used for tmux sessions, paths, etc.
- `repos` - List of repository paths belonging to the project
- `primary_repo` - The main repo used for the daemon socket and channel

For single-repo projects, only `name` is needed; `repos` and `primary_repo` are inferred from the working directory. This config is auto-created on first `midtown start`.

### Environment Variable Overrides

Daemon settings can be overridden with environment variables:

| Variable | Overrides |
|----------|-----------|
| `MIDTOWN_WEBHOOK_PORT` | `webhook_port` |
| `MIDTOWN_WEBHOOK_SECRET` | `webhook_secret` |
| `MIDTOWN_WEBHOOK_RESTART_INTERVAL` | `webhook_restart_interval_secs` |
| `MIDTOWN_PR_POLL_INTERVAL` | `pr_poll_interval_secs` |
| `MIDTOWN_CHAT_MONITOR` | `chat_monitor_enabled` (set to `0` to disable) |
| `MIDTOWN_MAX_COWORKERS` | `max_coworkers` |

## How It Works

### Coworkers

Each coworker runs in:
- An isolated git worktree (no merge conflicts during development)
- A tmux window within the project session
- With a Stop hook that syncs the channel at natural pause points
- With `--add-dir` worktrees for additional repos in multi-repo projects

### Channel Sync

Coworkers stay synchronized via a Claude Code Stop hook. When Claude pauses, the hook reads new channel messages and checks for unclaimed tasks. This means coworkers automatically receive updates at natural pause points.

### Worktree Lifecycle

When a coworker is spawned, midtown creates a detached git worktree at the current HEAD. The coworker creates a feature branch and works independently. When the coworker shuts down, worktrees with no commits and no uncommitted changes are automatically cleaned up along with their branches. Worktrees with work in progress are preserved.

### Webhook Ports

Each project daemon runs its own webhook server for GitHub integration. Port 47022 is reserved for the shared multi-project webserver. Per-project daemons auto-assign ports starting at 47023, persisting the assignment in the project's `config.toml` for stability across restarts.

## License

MIT