Skip to content

Devail1/chelamux

Repository files navigation

chela

License: MIT Python 3.11+ uv-managed tmux-native

chelamux

A tiny control plane that puts a fleet of Claude Code agents to work — unattended.

chela runs as a small daemon over a single tmux session. It does two things:

  • Schedules long-lived agents — poke an agent's pane on an interval or cron (every 1h, 0 */8 * * *, a one-shot timestamp).
  • Dispatches work — turn a markdown TODO.md (or GitHub issues) into one git worktree per task, spawn an agent in it, and let it open a PR.

Most tmux + Claude Code tools help you talk to and supervise agents; chela is for putting them to work and walking away. You watch them however you already watch tmux — tmux attach, Mosh, or the live terminal-wall dashboard.

chela on desktop — the live terminal wall plus the Dispatch board, Kanban and Schedules
Desktop — the live wall, Dispatch, Kanban & Schedules
chela on a phone — single-pane wall, agent pill switcher and keybar
Phone — single-pane, pill switcher, keybar

The dashboard, live — see it at chela.pages.dev.

Status: early. Core (scheduler + dispatcher + messaging) is solid and tested. The dashboard + live terminal wall is a first-class feature, shipped as a separate install (--extra dashboard) to keep the core lean for headless use. The wall streams live ttyd sessions and is on by default but loopback-guarded: it serves writable shells, so the dashboard only serves it on a 127.0.0.1 bind (the documented model — front it with a tailnet/SSH tunnel). A non-loopback bind refuses the wall unless you set CHELA_TERMINALS_EXPOSE=true.


Features

  • Schedule agents — poke any agent's tmux pane on an interval (every 45m), a cron expression (0 */6 * * *), or a one-shot timestamp. No human in the loop.
  • Dispatch TODOs → PRs — turn each - [ ] task in a WORKFLOW.md / TODO.md (or a GitHub issue) into a git worktree on a fresh branch, spawn an agent to implement it, and let it open a PR.
  • Live terminal wall — a web dashboard that streams every agent's pane (ttyd) into one grid, so you can watch the whole fleet work in real time.
  • Per-agent monitoring — context-window usage, session cost, liveness (alive / working / waiting), latest recap, and next scheduled run, per agent.
  • Account-wide rate-limit pills — the fleet shares one Claude account; the dashboard tracks the 5h / 7d limits so you can see headroom at a glance.
  • Needs-input alerts — when an agent blocks on a prompt, chela fires a one-shot push (ntfy / Telegram / webhook) so you're not babysitting.
  • tmux-native discovery — windows are agents; tmux list-windows is the single source of truth. No external registry, no heartbeat daemon.
  • Lean core, optional dashboard — a two-dependency headless core; the Flask dashboard + terminal wall is a separate --extra dashboard install.

Install

chela uses uv. The core has two small deps (croniter, pyyaml); the dashboard + live terminal wall ships as a separate install (adds Flask) — same feature, kept out of the core so a headless/CLI-only setup stays lean.

git clone https://github.com/Devail1/chelamux && cd chelamux
uv sync                       # core only — no Flask
uv run chela status

# dashboard + live terminal wall (separate install — keeps the core lean):
uv sync --extra dashboard

Requirements: Python ≥ 3.11, tmux, git, the claude CLI on PATH (plus gh for the dispatcher's PR flow).

Authenticate Claude once. chela doesn't manage credentials — it drives the claude CLI inside your tmux windows. Log in once on the machine (claude, then /login — or claude setup-token for a headless/long-lived token); every agent window reuses the cached ~/.claude credentials. The whole fleet therefore runs as one Claude account and shares its 5h / 7d rate limits (which is exactly what the dashboard's rate-limit pills track).


Run

# 1. Make a tmux session whose windows are your agents (the window name is the
#    agent's display name). Override the session name with CHELA_TMUX_SESSION.
tmux new-session -d -s chela -n researcher

# 2. See what chela can see:
uv run chela status

# 3. Schedule an agent:
uv run chela schedule add researcher --every 1h --prompt "Run your research cycle."

# 4. Start the daemon (scheduler + optional dispatcher + needs-input notify):
uv run chela run

# 5. Dispatch work items from a repo's WORKFLOW.md (see examples/):
uv run chela dispatch /path/to/repo/WORKFLOW.md --once    # one pass
uv run chela dispatch /path/to/repo/WORKFLOW.md           # poll

The dispatcher is the headline feature. Drop a WORKFLOW.md + TODO.md in a repo (copy examples/), and each - [ ] task becomes: a worktree on a fresh branch → an agent that implements it, strikes the line, and opens a PR → a run that flips to done when you merge. See examples/WORKFLOW.md.

Prefer to have an agent set it up? Copy skills/chela-setup into ~/.claude/skills/ and a Claude Code agent can install chela and seed a starter WORKFLOW.md + TODO.md for the current repo for you.


Agent autonomy (permission modes)

chela never manages permissions itself — it just launches claude, so the agent's autonomy is set by the claude --permission-mode <mode> it's started with. The modes (claude --help):

Mode Behaviour Good for
default Asks before every non-trivial action Watching closely / untrusted repo
plan Read-only; proposes a plan, changes nothing Scoping before you let it run
acceptEdits Auto-accepts file edits, still gates the rest (commands, etc.) "Accept edits on" — light supervision
auto A classifier auto-approves safe ops and gates dangerous ones chela's dispatcher default — rarely hangs, still gated
dontAsk / bypassPermissions No gating at all Zero-hang autonomy on a repo you fully trust

Two launch paths set the mode independently — this is the part to know:

  • Dispatcher agents read agent.cmd from each repo's WORKFLOW.md (version-controlled, per-repo). Default: claude --permission-mode auto.
  • Dashboard Start button / launcher use the CHELA_AGENT_CMD env (global). Default: plain claude, i.e. default mode — it asks on every action, so a launched agent you're not watching will sit waiting on a prompt.

To change the launcher/Start default, set the full command, e.g. export CHELA_AGENT_CMD="claude --permission-mode acceptEdits" (or auto), then restart the daemon. Prefer auto or acceptEdits for agents on a wall you don't babysit; reserve bypassPermissions for repos you fully trust.


CLI

Command What it does
chela status List the agent windows chela sees in the tmux session
chela run The daemon loop: scheduler tick + dispatcher + needs-input notify
chela schedule add <agent> --every/--cron/--once --prompt ... Add a scheduled poke
chela schedule list / remove <id> Manage scheduled tasks
chela dispatch <WORKFLOW.md> [--once] [--interval N] [--dry-run] Run the work-item dispatcher
chela dispatch-runs List dispatcher runs and their status
chela task-finished <task_id> (agent uses this) mark a run awaiting-review + kill its window
chela msg <agent> <text> [--from] [--priority] Message a live agent over tmux
chela broadcast <text> Message every other live agent
chela install-statusline [--write] Print/install the Claude Code statusLine hook for the context bar
chela dashboard [--host] [--port] Launch the dashboard + live terminal wall (needs the [dashboard] install)

Config (environment)

Variable Default Purpose
CHELA_TMUX_SESSION chela tmux session chela orchestrates
CHELA_DIR ~/.chela State dir (scheduler.db, worktrees, context)
CHELA_SCHEDULER_POLL_INTERVAL 30 Daemon loop interval (s)
CHELA_DISPATCH_WORKFLOWS Colon-separated WORKFLOW.md paths the daemon dispatches
CHELA_DISPATCH_TICK_INTERVAL 60 Dispatcher tick interval in the daemon (s)
CHELA_AGENT_CMD claude Launch command for the dashboard Start button
CHELA_PROJECTS_DIR ~/projects Folder scanned for git repos to suggest in the Launch sidebar (also settable in dashboard Settings → Projects folder, which wins)
CHELA_NOTIFY_URL Needs-input notification target (ntfy / Telegram / webhook)
CHELA_NOTIFY_KIND auto Force ntfy | telegram | webhook
CHELA_NOTIFY_CHAT_ID Telegram chat id (if not in the URL)
CHELA_NOTIFY_INTERVAL 20 Pane-state scan interval (s)
CHELA_DASH_HOST / CHELA_DASHBOARD_PORT 127.0.0.1 / 5001 Dashboard bind
CHELA_TERMINALS_ENABLED true Embedded ttyd terminal wall (streams live; loopback-guarded — see below)
CHELA_TERMINALS_EXPOSE false Serve the writable wall on a non-loopback bind too (RCE risk — opt-in)
CHELA_DEFAULT_CONTEXT_WINDOW 200000 Window size assumed by the transcript-based context estimate (fallback only)

Needs-input notifications

When an agent's pane enters the waiting state (blocked on a permission prompt or a question), chela fires a one-shot notification — so you don't have to babysit.

export CHELA_NOTIFY_URL=https://ntfy.sh/my-chela-topic              # ntfy
export CHELA_NOTIFY_URL="https://api.telegram.org/bot<token>/sendMessage?chat_id=<id>"  # Telegram
export CHELA_NOTIFY_URL=https://example.com/hook                    # generic JSON webhook

Transport is auto-detected from the URL; it's edge-triggered (one ping per entry into waiting, not per tick). Pair it with ntfy on your phone for a push-to-pocket "your agent needs you" alert.


Context & rate-limit tracking

The dashboard shows each agent's context-window usage and the account-wide 5h / 7d rate-limit pills. Those numbers live only in Claude Code's statusLine payload (they aren't in the transcript), so chela ships a tiny statusLine hook that caches the payload to $CHELA_DIR/context/<window>.json:

chela install-statusline           # prints the snippet to add to settings.json
chela install-statusline --write   # writes it for you (won't clobber an existing one)

It's optional. Without it, the context bar falls back to a coarser estimate derived from the agent's transcript (no rate-limit pills, and the window size is a guess — see CHELA_DEFAULT_CONTEXT_WINDOW). Install the hook for exact numbers.


Remote access & security

chela ships with zero built-in auth, by design. The dashboard and the ttyd terminals bind 127.0.0.1. The terminal wall is a writable shell — exposing it on an untrusted network is remote code execution. The tailnet is the trust boundary, not a password.

For remote access, put the loopback dashboard behind one of:

  • Tailscaletailscale serve 5001 gives you TLS
    • tailnet ACLs for free (recommended).
  • An SSH tunnelssh -L 5001:127.0.0.1:5001 host.
  • A reverse proxy with your own auth.

Watch from your phone without the web UI at all: SSH/Mosh into the box from a mobile terminal — Blink (iOS), Termius, or any Mosh-capable client — then tmux attach -t chela and you've got the live panes. A QR of the connect string makes this one tap.

Pairs well with ccbot — a Telegram ↔ tmux bridge for Claude Code (1 topic = 1 window = 1 session). It shares chela's model — a tmux window per agent — so you can let chela put the fleet to work and drive or supervise any agent from a Telegram topic on your phone (text, images, and file attachments flow both ways). (chela's built-in needs-input notifications just ping you; ccbot is a full two-way bridge.) Independent project, not required by chela.


Dashboard & live terminal wall

A first-class feature, shipped as a separate install to keep the core lean. uv sync --extra dashboard && uv run chela dashboard serves a web UI on 127.0.0.1:5001 with tabs for agents (liveness from claude agents --json: alive / waiting / offline), schedules, the dispatcher, and a Kanban of runs. Liveness is derived live from the native session status — no heartbeat daemon. An embedded ttyd terminal wall (a multi-pane view that streams the live panes) is on by default, but loopback-guarded: because it serves writable shells, the dashboard only serves it on a 127.0.0.1 bind. Bind to a non-loopback interface (e.g. --host 0.0.0.0) and the wall is refused — its routes 404 and its UI is hidden — unless you explicitly set CHELA_TERMINALS_EXPOSE=true. Turn the wall off entirely with CHELA_TERMINALS_ENABLED=false.

Agents view — per-agent context, cost, schedule, recap and liveness
Agents view — context usage, cost, liveness, latest recap and next run, per agent.

Schedules view — interval, cron and one-shot pokes per agent
Schedules — interval, cron, and one-shot pokes that type a prompt into an agent's window.

Keys not reaching the terminal? If Esc (or other keys) never reaches an embedded terminal, a vim-style browser extension such as Vimium is almost certainly capturing them at the page level — it injects into the terminal's iframe too. Fix: exclude the dashboard's URL in the extension's settings (in Vimium, Options → "Excluded URLs and keys" → add the dashboard URL and leave the Keys field blank). Quick workaround: Ctrl+3 (or Ctrl+[) sends a literal Escape.

HTTP API (selected)

Route Returns
GET /api/agents Per-window liveness/health, session status, context, schedules
GET /api/summary Header counts (agents online, schedules)
GET /api/schedules · POST · DELETE/PATCH /<id> Scheduled tasks CRUD
GET /api/dispatcher Open tasks + active/awaiting/recent runs per workflow
POST /api/dispatcher/runs/<id>/merge · /merge-all Squash-merge PRs + clean up
POST /api/agents/{start,stop,restart,msg,broadcast,trigger} Agent controls
GET /api/events Server-Sent Events stream (reactive UI accelerator)

How it works

  • Discovery is tmux-native. tmux list-windows + pane_current_path are the single source of truth — no external state file, no daemon to coordinate with. tmux never lies about what's live right now.
  • The dispatcher keys each task by a stable SHA of its source line, creates ~/.chela/worktrees/<...>/ per task on branch <project_key>-<n>, and tracks runs in ~/.chela/scheduler.db. Dispatched agents default to claude --permission-mode auto (a classifier auto-approves safe ops and gates dangerous ones); set agent.cmd: claude --permission-mode bypassPermissions in WORKFLOW.md for zero-hang autonomy on a repo you trust.

Credits

The work-item dispatcher is an adaptation of OpenAI's Symphony pattern (task-list → isolated git worktree → autonomous agent → PR) — chela does not claim novelty for that shape.

License

MIT — see LICENSE.

About

A tiny control plane that puts a fleet of Claude Code agents to work — unattended: schedule personas, dispatch TODOs to PRs via git worktrees, and watch them on a live web terminal wall.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors