# agents a subagent is a session with a parent. a message is mail. both are daemon primitives; the `mail` and `agents` extensions (on by default) give the model its python surface. ## python ```python m = await agents.models() # required once before spawning kid = await agents.self.spawn("map every wake path", name="scout", model=m[0], deliverable="notes/wakes.md") # returns at once await mail.submit(kid, "also cover schedules") # or "parent", a name, a session id kids = await agents.self.children() # snapshots: running, closed await kid.cancel() # stop its turn, keep everything await kid.close() # done: keep transcript + files, free the kernel await agents.progress("on turn.gleam now") # shows in /agents, starts no turn ``` - spawn never returns the child's answer: the answer arrives later as `` and starts the parent's next turn. a child whose turn ends without answering forwards its last message, marked `unreviewed`. - names resolve inside the family (children, siblings, parent); anything else takes a session id. - cancel and close work on your own children only. the model cannot delete an agent; it asks the user. - limits: 3 deep, 12 open children per parent, 1 MiB per letter, 1000 undelivered letters per session. ## mail delivery a letter is stored first and marked delivered in the same transaction that writes it into the recipient's transcript. an idle recipient starts a turn; a running one reads it at its next step. undelivered letters retry every 15 seconds, so a restart or a session that is not running yet loses nothing. webhook deliveries are letters from outside, and wait for an idle session. ## the orchestrator view `ctrl+o` or `/agents` in a session shows its whole tree live: running agents pulse with their token rate, mail travels the edges as blocks. tab picks an agent, enter opens it (typing there is you, as the user), text + enter sends to it, `/spawn ` starts a child under it. routes: `GET /agents?session=` (the tree), `GET /agents/stream` (batched events), `POST /sessions/:id/children`, `POST /sessions/:id/mail`. ## swarm overhead kernel boots queue behind four slots. each boot owns only its session's composition, and each kernel's host callback captures only its routes, store handle, and session id—not a snapshot of the other agents. bash waits on process-exit notifications, not periodic exit checks; descendant cleanup and deadlines still apply. session replay retains at most 256 events or 4 mib, evicting incrementally rather than copying the full window per token. missing events require a transcript reset. the orchestrator feed batches every 100 ms and skips activity serialization when nobody is watching. bash jobs start at once, at low priority (`nice`, and utility QoS on macOS), so a busy swarm yields to the person at the machine. a job still running after the grace window (5 s) is heavy and needs one of a few daemon-wide slots; without one it is paused (`SIGSTOP`, `job.queued` is true) and resumed when one frees, so waiting costs no cpu and loses no work. quick commands never wait. the timeout counts only time the command ran. `await job.stop()` resumes a paused job so it can exit. slots default to the machine's cores and shrink while the one-minute load average runs past 1.25× the cores, which catches heavy jobs that fan out workers of their own. a freed slot goes to the kernel holding the fewest, oldest request first, so one busy agent cannot starve the rest. a slot is released only after process-group cleanup is confirmed; failed cleanup keeps it held. settings, read when the daemon starts: `ALBEDO_MAX_LOCAL_JOBS` fixes the slot count (1–256), `ALBEDO_JOB_GRACE_SECONDS` sets the grace window, `ALBEDO_JOB_LOAD=0` turns off the load adjustment. this bounds sustained shell work, not agent/model concurrency, remote kernels, or python computed directly in a cell.