Metadata-Version: 2.4
Name: regatta
Version: 0.1.0
Summary: tmux-backed mission control for parallel AI coding agents
Author-email: Sebastian Widlund-Stone <swidlundstone@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Sebastian Widlund-Stone
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/Someblueman/regatta
Project-URL: Repository, https://github.com/Someblueman/regatta
Project-URL: Issues, https://github.com/Someblueman/regatta/issues
Keywords: tmux,ai,agents,codex,claude,mission-control,orchestration
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Environment :: Console :: Curses
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development
Classifier: Topic :: Terminals
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Requires-Dist: rich>=13.0
Requires-Dist: textual>=0.60
Requires-Dist: discord.py>=2.3
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Dynamic: license-file

# regatta

**Mission control for AI coding agents.**

`regatta` runs many Codex (or Claude) workers in parallel — each on its own task, in its own git worktree, in its own tmux window — and gives you one terminal cockpit to steer them. A foreman agent does the planning, the workers do the coding, and you do the steering.

```
freebird   5 active  ·  2 blocked  ·  1 stale  ·  3 ready   last 8s                       progress
                                                                ▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱  47%

activity ─────────────────────────────────────────────────────────────────────────────────────────
▁▁▂▃▆█▇▅▃▂▂▁▁▂▃▄▆▇█▇▅▄▃▂▁▁▂▃▄▅▆
events · last 30m · 412

lanes ─────────────────────────────────────────────────────────────────────────────────────────────
 READY 3       │ ACTIVE 5         │ BLOCKED 2        │ CHANGED 4        │ DONE 11
 ─ csv-import  │ ─ backend-api    │ ─ frontend-up…   │ ─ migration-fix  │ ─ schema-v2
 ─ retry-flow  │ ─ test-harden    │ ─ s3-creds       │ ─ docs-rewrite   │ ─ ci-cache
 ─ docs-bulk   │ ─ rate-limiter   │                  │ ─ rbac-models    │ +9 more
               │ ─ webhook-sign   │                  │ ─ logging-cleanup│
               │ ─ idle-worker  ●STALE              │                  │
```

This is what a `regatta` session looks like with five things happening at once.

---

## Why use it

- **Real parallelism.** Each task gets its own worktree and its own agent. No more sharing one repo with one conversation. No more rebasing manually.
- **You stay in the loop.** The mission control TUI shows what every worker is doing right now — heartbeat, terminal tail, file changes, blockers — without context-switching across tmux windows.
- **Steer from anywhere.** Same control surface from the TUI, the CLI (`regatta spawn`, `regatta retask`, `regatta pause`), or Discord (`!regatta retask backend-api ...`). Pick whichever is handy.
- **Boring under the hood.** Plain tmux, plain SQLite, plain Python. No daemons, no servers, no cloud. If you can read a `.regatta/runs/<id>/state.db` file you can debug anything.

---

## Install

```bash
pip install regatta          # once published
# or, from a checkout:
pip install -e .
```

Requires `tmux`, `git`, Python 3.10+, and a working `codex` CLI on your `$PATH`. Optional: `claude` CLI for tasks you want Claude to run.

Run `regatta doctor` to check your environment in one shot.

---

## 30-second quickstart

```bash
cd ~/Code                 # or any directory containing repos you want to work on
regatta start                # creates a tmux session called `regatta`, opens mission control
```

That's it. You're now in a tmux session with:

- a **foreman pane** running Codex — talk to it like a colleague who can dispatch work
- a **mission window** — the cockpit pictured above
- compact **summary / focus** panes that stay glanceable
- an **ops shell** for whatever you'd usually do in a terminal
- one **worker window per task** once you spawn them

To switch to mission control: `Ctrl-b` then `2` (or `tmux select-window -t regatta:mission`).

To add work, just tell the foreman in plain English:

> "Three things to do: add CSV bulk import to the backend, harden upload validation, document the new flow. Spawn workers for the first two and leave the docs as ready."

The foreman files the tasks into SQLite, spins up worktrees, opens worker windows, and the mission view updates live.

---

## Mission control

The mission window is the operator surface. It updates live — the activity sparkline ticks, heartbeats decay, lane cards move between columns as workers progress.

### Keys

| key | action |
|-----|--------|
| `↑` `↓` | move selection between tasks |
| `f` | share selection as the run-wide focus |
| `s` | spawn the selected task |
| `p` | pause the selected task |
| `e` | resume the selected task |
| `w` | jump to the selected worker's tmux window |
| `t` | toggle between **lane board** (default) and **table view** |
| `d` | toggle the **dependency tree** overlay |
| `/` | focus the filter input |
| `;` | focus the command input |
| `c` | clear filter |
| `r` | force refresh |
| `1`–`7` | bucket filters: all / ready / active / blocked / paused / todo / done |
| `q` | quit |

### Command line (`;`)

Anything you can do by hotkey, you can do with arguments. Some things only work here.

```
spawn  backend-api
pause  backend-api  waiting on API contract
resume backend-api  contract is stable now
retask backend-api  defer caching, focus on validation + tests
focus  test-hardening
worker frontend-upload
filter csv
bucket blocked
```

If you omit the task id, the currently-selected row is the target.

---

## From the CLI

You don't have to be in the TUI to drive a run. Every action has a CLI form:

```bash
regatta status                                  # one-frame overview, pretty in any pane
regatta tasks                                   # list tasks
regatta spawn  backend-api                      # start a worker
regatta pause  backend-api  "waiting on contract"
regatta resume backend-api  "contract is stable"
regatta retask backend-api  "tighten scope, add tests"
regatta done   backend-api  "shipped"
regatta inspect backend-api                     # full focused view of one task
regatta events --limit 30                       # raw event stream
regatta where                                   # which run/workspace am I in?
regatta runs                                    # list recent runs
regatta logs   backend-api --follow             # tail a worker's output
regatta note   add "API contract is frozen"     # append to the shared knowledge base
regatta ship   backend-api                      # open a PR from the task's branch
regatta export <run-id>                         # archive a run (state.db + logs) for sharing
```

For the deterministic low-level surface (adding tasks programmatically, etc.):

```bash
regatta ctl add-task \
  --task-id docs \
  --title  "Update docs" \
  --repo-root ~/Code/my-repo \
  --prompt "Document the new flow."
```

---

## Workspace config

For a workspace you orchestrate repeatedly, drop a `regatta.yaml` at the workspace root:

```bash
regatta init-config --objective "Coordinate active work across my local repos"
```

```yaml
workspace_root: .
run_root: .regatta/runs
session_name: regatta
objective: Coordinate active work across my local repos
mission_ui: auto         # auto | textual | rich
pane_refresh: 5          # seconds, compact panes
mission_refresh: 1       # seconds, mission window
max_active_workers: 8    # cap on simultaneously-active workers; 0/negative = unlimited
discord: false
```

`max_active_workers` caps how many workers can be `active` at once. When you are at
the cap, `regatta spawn <task>` refuses with an actionable error; pass `--force` to bypass
it once, or `--max-active-workers N` to raise the cap and spawn in one command. The
status/mission header shows the current count as `active N/M`.

`regatta` searches upward for `regatta.yaml`, `regatta.yml`, `.regatta.yaml`, or `.regatta.yml`. Paths inside the config resolve relative to the config file.

---

## Discord bridge (optional)

Steer a run from your phone. The bridge is a small bot that reads one Discord channel and calls the same control actions the TUI uses.

```bash
export DISCORD_BOT_TOKEN='...'                    # required (env only; never argv)
export DISCORD_CHANNEL_ID='123456789012345678'    # required: scope the bot to one channel
export DISCORD_ALLOWED_USER_IDS='111,222'         # required: only these user IDs may issue commands
export DISCORD_COMMAND_PREFIX='!regatta'             # optional

regatta start --discord
```

See the [Security and trust model](#security-and-trust-model) section for why every one of those should be set, not just `DISCORD_BOT_TOKEN`.

```text
!regatta status
!regatta tasks [all|ready|active|blocked|paused|todo|done|failed]
!regatta inspect [task_id]
!regatta events  [limit]
!regatta focus  <task_id>
!regatta spawn  <task_id> [--force]
!regatta pause  <task_id> [message]
!regatta resume <task_id> [message] [--force]
!regatta retask <task_id> <message>
```

Enable the bot's **Message Content Intent** in the Discord developer portal first.

---

## Task plans (optional)

Preload a task board from YAML — useful when you know up-front what work needs to ship:

```bash
regatta start \
  --plan plans/example_plan.yaml \
  --objective "Ship CSV bulk import safely with parallel workers"
```

See `plans/` for examples.

---

## What's where

The package lives under `src/regatta/`:

| module | role |
|--------|------|
| `regatta.regatta_cli` | the `regatta` CLI front door |
| `regatta.orchestrator` | session bootstrap (tmux windows, panes, foreman) |
| `regatta.tmux` | tmux helpers (windows, panes, send-keys) |
| `regatta.git_ops` | git / worktree helpers |
| `regatta.plans` | YAML plan loader |
| `regatta.actions` | spawn / retask / pause / resume / focus business logic |
| `regatta.cli` | deterministic CLI surface (used by `regatta ctl …`) |
| `regatta.regattactl` | aggregated re-exports of the split control modules |
| `regatta.state` | SQLite schema, migrations, and queries |
| `regatta.doctor` | environment health checks for `regatta doctor` |
| `regatta.mission_textual` | the Textual mission control app |
| `regatta.mission_widgets` | native Textual widgets (lane board, heartbeat, etc.) |
| `regatta.mission_cache` | TTL cache for git / tmux IO |
| `regatta.ui_render` | Rich rendering — shared by mission view and dashboard panes |
| `regatta.ui_snapshot` | builds the unified snapshot every UI consumes |
| `regatta.dashboard` | one-frame and `--watch` Rich views, plus `mission` full-screen mode |
| `regatta.control_room` | thin deprecation shim — folded into `dashboard` |
| `regatta.discord_bridge` | Discord bot |
| `regatta.hooks` | user-defined lifecycle event hooks (`task.spawned` / `done` / `failed` / `worker.stale`) |
| `regatta.plans/` (package data) | starter plans for preloading a board |
| `regatta.prompts/` (package data) | foreman/system prompts |

State lives under `.regatta/runs/<run-id>/`. Tasks, focus, events, and worker metadata are all in `state.db`. Worker code lives in per-task worktrees alongside.

---

## Design notes

- **The foreman is for planning, the mission view is for piloting.** The foreman pane is where you discuss what work to do and why. The mission view is the fast lane for spawning / pausing / retasking once the work exists.
- **Selection is local; focus is shared.** Browsing tasks in the mission view doesn't disturb the rest of the control room. Press `f` (or `Enter`) when you want to commit a selection as the run-wide focus.
- **The lane board is the primary view.** It shows movement — who's moving, who's stuck, who's queued — at a glance. The table is still there (`t`) for when you want sortable density.
- **Visualisations are live.** The activity sparkline shows events-per-minute over the last 30 minutes. Heartbeat decay bars per active worker turn magenta when stale (no heartbeat in 10 min). Dependency overlay (`d`) shows what's blocking what.
- **No daemon.** SQLite is the source of truth. The TUI, the CLI, and the Discord bridge all read and write the same store.

---

## Requirements

- Python 3.10+
- `tmux`
- `git`
- `codex` CLI on `$PATH` (and optionally `claude`)
- Python deps: `textual`, `rich`, `PyYAML`, `discord.py` (auto-installed by `pip install -e .`)

---

## Security and trust model

`regatta` is a developer tool, not a sandbox. Before pointing it at anything sensitive, read this section.

### Privacy

Every task prompt is sent to whichever model your provider CLI is configured for (`codex`, `claude`, …). If you are running on a private repository, assume the contents of your task prompt and any code the worker reads have left your machine. If your provider relationship doesn't permit that, do not run `regatta` against that repo.

`.regatta/runs/<run-id>/` contains task prompts, worker transcripts, logs, and any output the agents produced. It is gitignored — do not commit it. The directory may contain secrets the agents surfaced; treat it the way you would treat a shell history file.

### Discord bridge

The Discord bridge is a remote-control surface. Anyone able to post in the configured channel can spawn or retask workers, which means they can run arbitrary AI agents inside your worktrees. Configure it defensively:

- `DISCORD_ALLOWED_USER_IDS` (comma-separated numeric user IDs) is **required**: the bridge fails closed and refuses to start unless at least one trusted operator id is set, so an empty allowlist can never leave commands open to everyone.
- **Always** set `DISCORD_CHANNEL_ID` so the bot also ignores messages from other channels.
- `DISCORD_BOT_TOKEN` is read from the environment only. It is never accepted on the command line; that would leak it via `ps`.

### Plans

`PlanLoader` trusts the YAML author. A plan file prescribes prompts, repos, and metadata that drive what workers do. **Only load plans you wrote or fully reviewed.** Loading an untrusted plan is the rough equivalent of running someone else's shell script — the prompts may be hostile, and the metadata can route writes into repos you didn't expect.

### `.regatta/runs/` is gitignored on purpose

Run directories accumulate task prompts, model output, log files, and SQLite databases. They are large, low-signal, and may contain secrets that agents accidentally echoed. The default `.gitignore` excludes them; please keep it that way.

---

## License

[MIT](LICENSE). See also `SECURITY.md` for reporting vulnerabilities and `CONTRIBUTING.md` for how to help.
