● draining  trust the queue, not the agent

Run a fleet of AI coding agents unattended, and know which ones to trust.

WatchTower is a CLI-first queue and fleet manager. You drop work into named queues. Workers drain them one ticket at a time: claim, fix, verify, commit, next. One command, wt wait, blocks until the open backlog is empty. Check active tickets separately before deploying.

wait for the open backlog to drain
wt add -q LAUNCH --title "ship the release notes" --type feature
filed LAUNCH-42

wt wait -q LAUNCH --timeout 1800
# waits until no tickets remain in open status
LAUNCH: 3 open  -> 1 open  -> 0 open, drained.
✓ open backlog drained; check work in progress before deploying

wt wait checks open tickets only. Tickets already claimed, awaiting review, or blocked for an answer do not keep it waiting. Inspect those states before treating work as complete.

CCC0 openLIVE BYM2 open, drainingLIVE OPS14 open, 41m idleSTUCK HERMES0 openLIVE

wt status in one glance: green means draining, red means a queue has open tickets and no worker making progress. Detection is keyed to queue ground-truth, never to what an agent claims about itself.

What it is

A list that empties itself, and turns red when something is wrong.

WatchTower makes background agent work legible. No new IDE to live in, no habits to learn. The engine is a durable local queue: file-locked, stdlib-only Python, zero runtime dependencies.

□ Named queues

One namespaced store of tickets per project (CCC, BYM, OPS, and so on), behind a backend-agnostic API. File work with the CLI, a dashboard, or a browser widget.

▶ Autonomous workers

A worker session drains one queue: claim, fix, verify, commit, next. Idle workers are pushed new tickets the instant they land, with no polling loop.

◉ Queue-health watcher

Open tickets plus no progress equals STUCK. The watcher trusts the queue, not the agent, and can wake a stuck worker automatically.

The one rule that defines it. A worker can swear it is done while 14 tickets sit open. The watcher catches that, because health is measured against the queue, never against the agent's own report.

Install

Two commands, then the wt CLI is on your path.

Requirements: Python 3.11 or newer, macOS or Linux. An agent CLI (Claude Code or Codex) is only needed once you want WatchTower to spawn real AI workers instead of draining tickets yourself.

install
git clone https://github.com/amirfish1/watchtower.git
cd watchtower && pip install -e .
wt --version
wt 0.8.3
Prefer to see it first? ./examples/quickstart-demo.sh files a ticket, starts wt wait in the background, then claims and closes the ticket to stand in for a real worker, so you watch wt wait unblock the instant the queue empties. No agent CLI required.

Quickstart

From zero to a self-draining queue in three steps.

Point a queue at your repo

Create the queue and tell it which repo and engine to use. Turning auto-drain on also starts the background service.

wt config -q MYAPP --engine claude --repo-path /path/to/your/repo --auto-drain on

File your first ticket

A Claude worker spawns automatically in your repo and starts draining. Tickets get a stable ref like MYAPP-1.

wt add -q MYAPP --title "Fix the login page" --type bug
filed MYAPP-1

Watch it empty itself

Glance at the strip: green means draining, red means stuck. Open the dashboard, or wait for the open backlog to reach zero.

wt status
MYAPP   1 open   draining   LIVE
wt dashboard          # opens http://127.0.0.1:8787
wt wait -q MYAPP --cmd "say done"

That is the whole loop: file work, a worker drains it, the watcher reports queue health. You do not manage agents. You manage a queue, and watch it empty itself.

Honest scope

What WatchTower is, and what it is not.

WatchTower is a standalone product. It does not require Claude Command Center or any desktop app to run: every command works from a plain terminal. It is CLI-first and local-first by design.

In the box today

Named queues and a durable ledger. Autonomous claim/fix/verify/commit workers. The queue-health watcher and auto-nudge. wt wait gating. Document import into tickets. Cross-agent messaging (send, ask, group chats). A local dashboard on 127.0.0.1. Claude, Codex, Kimi and Devin worker engines.

Deliberately out of scope for v1

Cross-machine federation (the delegate URL is the seam, nothing more). An MCP server (skill-first instead). LLM-driven chat moderation (targeting stays deterministic). A native macOS keystroke adapter (deferred, not rejected: busy-hold covers the need in v1).

Engine reach, stated plainly

Without any delegate, WatchTower covers Claude sessions with at-most-idle-lag delivery and sends to Codex through its private fallback. This is the honest v1 matrix.

Engine / sessionsend & askgroup chat
Claude (WatchTower worker)native fifoyes
Claude (idle session)native resumeyes
Claude (live terminal, no CCC)busy-hold, resume on idleyes, lands on idle
Claude (live terminal, CCC present)instant keystroke injectyes, instant
Codex (CCC present)through CCC brokeryes
Codex (standalone WatchTower)send only, ask unsupportedyes

A successful private app-server send to Codex requires a receipt backed by the thread's durable rollout. An acknowledgement without that proof path is reported as failure, not delivery.