lock family docs GitHub

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 dev and reviewer agents with agents_spawn and stops its own with agents_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's asyncRewake) 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 shows woken by lea during that turn;
  • an agent asks another a question and waits for the answer with ask (the other answers with msg_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 board shows who waits on whom;
  • an agent started by a lead is told to report to it with msg_send when it is done or blocked;
  • board_read shows an agent every task of its lea, as lea board shows them to you;
  • every agent reports on its task with task_update: its row shows it, and lea board --md prints every task as markdown;
  • before editing files another agent may touch, an agent claims them with lease_acquire and lets go with lease_release (advisory, shown in lea 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 ~/.claude that 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 ~/.claude is 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.json names 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, then lea). Remove the statusLine entry to get lea's line back.