A GPU lease broker for Claude Code sessions.
You tell one agent to train on GPU0 and another to evaluate on GPU1. Neither can see what the other is doing, and you end up holding the whole picture in your head. AgentLoom holds it instead: an agent asks for the card you named, and if that card is busy it queues on that card and gets woken when it frees.
you: train the model on GPU0
claude: [gpu_request device="0"] queued #1 on local/0
blocked by 'eval-sweep' — ~47 min (measured from its step rate)
[runs `agentloom wait T-17` in the background, ends the turn]
...
[woken automatically] export CUDA_VISIBLE_DEVICES=0 AGENTLOOM_LEASE=L-42
[starts training on the card you asked for]
-
agentloom daemon— source of truth for devices, per-card queues and leases. Detects processes it did not put on a card and refuses to schedule there. -
MCP tools — what a session actually calls:
tool what it is for gpu_surveywho holds what, how far along, who is waiting — always live gpu_requestask for a card; returns a lease or a queue position gpu_releasehand the card back as soon as the job ends gpu_extendthe job will overrun; keep other sessions' ETAs honest gpu_reportpush step/total for jobs that write no TensorBoard logs -
The
agentloomskill — teaches every session the loop, including that a busy GPU0 means queue on GPU0, not use GPU1. -
agentloom wait— the wake path. A queued session blocks on it in the background and is re-invoked when the lease lands. No relay process to keep alive, so nothing to fail. -
TUI — per-card queues, live training progress, drain a card, kill a job.
-
agentloom.report()— optional one-liner for training scripts. Never raises, never blocks, does nothing outside a lease.
No hooks. AgentLoom writes nothing to ~/.claude/settings.json and can
never block or rewrite a command. A session learns the GPU state by asking
gpu_survey, which is always live.
- You pick the card; the queue serialises on it. Asking for a busy card queues you there. A free card elsewhere is reported, never silently taken.
- No preemption. Priority reorders the queue; waiting tickets age upward so nothing starves.
- ETAs say where they came from —
measuredfrom a real step rate, ordeclaredfrom someone's own budget guess. Never the same word for both. - Someone else's process wins. A card with a foreign process leaves the pool.
- Agents ask, they do not take. An agent may message the holder of a card to negotiate; killing a job is the operator's action, from the TUI.
Python 3.11+, and nvidia-smi for real cards. See docs/INSTALL.md
for configuration and the TUI keys; short version:
uv venv .venv && uv pip install --python .venv -e .
.venv/bin/agentloom daemon &
claude mcp add --scope user agentloom -- $PWD/.venv/bin/agentloom-mcp
mkdir -p ~/.claude/skills && ln -sf $PWD/skills/agentloom ~/.claude/skills/
.venv/bin/agentloom tuiRuntime state lives in $AGENTLOOM_HOME (default ~/.agentloom), including the
optional config.toml where you give each card a relative weight, since
nothing can measure that for you.
| command | what it does |
|---|---|
agentloom daemon |
run the daemon |
agentloom status |
devices, running leases and per-card queues |
agentloom tui |
the operator view: progress, drain, kill, message |
agentloom events -f |
stream the event log |
agentloom request <job> -d 0 |
request a card from the shell — mostly for testing |
agentloom release <lease> |
give it back |
agentloom wait <ticket> |
block until a queued ticket is granted |
agentloom doctor |
check the daemon, the provider and the config |
uv pip install --python .venv -e ".[dev]"
.venv/bin/python -m pytest -q
AGENTLOOM_FAKE_GPUS=4 .venv/bin/agentloom daemon # no GPU neededAGENTLOOM_FAKE_GPUS swaps in the fake device provider, so the daemon, the TUI
and the whole request/queue/wake path run on a machine with no GPU at all.
docs/ARCHITECTURE.md covers why it is built this way.