Agents that find their own work
"The agent finds work itself." No human dispatcher needed - it pulls tasks from the board on its own.
From 'being awakened' to 'finding work'
s09/s10 teammates are reactive: someone has to send them a message before they start; they finish and go idle, waiting to be called again.
s11's autonomous teammate is proactive: even when idle it doesn't truly stop. It scans .tasks/ every 5 seconds, and when it spots an unclaimed task it calls claim_task and gets to work.
Teammate lifecycle:
+-------+
| spawn |
+---+---+
|
v
+-------+
| WORK | <-- LLM tool_use loop
+---+---+
|
| stop_reason != tool_use OR tool_use("idle")
v
+-------+
| IDLE | poll every 5s, up to 12x = 60s timeout
+---+---+
|
+--> inbox has new messages? -> resume WORK
|
+--> scan .tasks/, find unclaimed task -> claim -> resume WORK
|
+--> 60s with nothing -> status = shutdown, thread exits
Auto-claim: pulling tasks off the board
The core function:
def scan_unclaimed_tasks() -> list: unclaimed = [] for f in sorted(TASKS_DIR.glob("task_*.json")): task = json.loads(f.read_text()) if (task.get("status") == "pending" and not task.get("owner") and not task.get("blockedBy")): unclaimed.append(task) return unclaimed
Three filters = pending + no owner + no blockedBy. All three are required.
The claim action itself holds a lock (_claim_lock) to prevent two agents simultaneously spotting the same unclaimed task and both trying to grab it. Inside the lock: re-read, check owner is still empty, then write in_progress + owner to disk.
Simulate multiple agents scanning the task board
3 teammates in idle state, 3 tasks waiting. Click "Next poll" and see who claims what first.
Identity reinjection: knows who it is after compaction
s06 showed that auto_compact replaces messages with a summary. An autonomous agent running for an hour easily triggers this - after compaction the model doesn't know its own name or role.
s11's fix: when claiming a new task, if len(messages) <= 3 (indicating recent compaction), automatically prepend an identity block:
if len(messages) <= 3: messages.insert(0, { "role": "user", "content": f"<identity>You are 'alice', role: coder, team: my-team. Continue your work.</identity>", }) messages.insert(1, {"role":"assistant", "content": f"I am alice. Continuing."})
This pattern is called identity reinjection - a synthetically constructed exchange that tells the model who it is, restoring its sense of role.