lea · Teams of agents
Teams of agents
Every agent has a role: lead, dev (the default) or reviewer. The first agent is a lead: a
Control Tower (see below).
Only you change a role (r in the deck, lea role <agent> <role>, lea new -r reviewer).
Agents get lea's tools through MCP:
- a lead starts
devandrevieweragents withagents_spawnand stops its own withagents_stop(at most 20 children at a time); - any other agent asks a lead with
agents_request_spawn; without a lead the request comes to you (lea requests,lea request accept <id>,lea request decline <id> [reason]); - agents message each other (
msg_send,msg_reply); a message waits in the inbox until the agent's next turn. An agent whose turn is over is woken when a message arrives: its Stop hook (and its SessionStart hook, so a session resumed after a restart is woken too) starts a background job (Claude Code'sasyncRewake) that ends with the unread notice, and Claude Code starts a turn; the job waits for days and outlives a restart of lea's daemon. A working agent, or one waiting on a permission dialog, is not interrupted; a paused one, or one stopped on its usage limit, waits; only the newest job of an agent stays, so one message wakes it once, and an agent is woken at most 10 times in 10 minutes. The deck showswoken by leaduring that turn; - an agent asks another a question and waits for the answer with
ask(the other answers withmsg_reply; works with any agent that has lea's MCP tools). The answer is data, never instructions. Only a reply from the asked agent counts; an agent's container is checked (its bus socket), but its name inside a container is what the agent declares (LEA_AGENT), so agents of one container can answer for one another. One ask at a time per agent, at most 4 questions waiting on one agent, 5 asks a minute, a 1–600 s timeout (300 by default; a late answer lands in the inbox), and no loop: an ask that would make agents wait on one another in a circle, or in a chain longer than 3, is refused. The question and its answer show in the deck's thread view;lea boardshows who waits on whom; - an agent started by a lead is told to report to it with
msg_sendwhen it is done or blocked; board_readshows an agent every task of its lea, aslea boardshows them to you;- every agent reports on its task with
task_update: its row shows it, andlea board --mdprints every task as markdown; - before editing files another agent may touch, an agent claims them with
lease_acquireand lets go withlease_release(advisory, shown inlea board --md).
Your own status line #
lea draws the agents' status line itself (lea statusline: model, context and 5-hour/7-day
usage), since it reports each agent's context use to the deck and feeds limit auto-resume. When
your ~/.claude/settings.json has a statusLine command, lea runs it after its report and shows
its output instead (#374):
- Your command gets the same JSON on stdin as on your host, and runs inside the container, in
the agent's directory: no host-only tool or path. A script below
~/.claudethat the command names (~/.claude/statusline.sh,bash ~/.claude/bin/line.py...) is mounted read-only, when it is a real file (no symbolic link on its path) and executable or named as a script. Nothing outside~/.claudeis mounted: such a command fails and lea's own line shows. - When the command exits non-zero, prints nothing or takes more than 1.5 s (it is killed, with what it started), lea prints its own line. The context report is sent whatever it does.
- The command is read from the container's copy of your settings, at every refresh; the script
is mounted when lea starts, as your host's
settings.jsonnames it (never as an agent's copy does, so an agent cannot get another host file mounted), and never one of Claude Code's own state directories (projects,shell-snapshots,todos...). After adding one, restart lea (lea stop, thenlea). Remove thestatusLineentry to get lea's line back.