Overview
codeagent supports running multiple independent sub-agents in parallel for tasks that can be divided and executed concurrently.
Coordination at a glance
team_run(tasks) FIXED FAN-OUT (worker i = task i)
crew / mirai: run_one(task) = codeagent_client() + codeagent(task)
-> collect results in order
team_coordinate(tasks, blocked_by) WORK-STEALING over a SQLite board
board_create(): tasks + deps (DAG) + messages tables
seed tasks (add, then wire blocked_by by index) + toposort (reject cycles)
N workers, each: repeat {
board_claim() -- BEGIN IMMEDIATE: lowest pending id whose blockers are done
| none claimable
+- pending == 0 -> all done, break
+- board_reclaim_stale() -> reclaim a crashed worker's task
+- stalled (dead-end) -> break
+- else Sys.sleep(backoff) -> retry (a blocker still running)
run codeagent(task) -> board_complete(result) -> board_send_message()
}
-> board_status() data.frame (id, prompt, owner, status, result)
team_lead(goal, max_rounds) LLM-LEAD loop
decompose (chat_structured -> tasks + DAG)
-> team_coordinate(...) (runs the work-stealing board above)
-> review (chat_structured: done? follow-up tasks?)
-> replan -> next round (until done or max_rounds)
Fixed fan-out: team_run()
team_run() assigns one task per worker and collects all
results:
library(codeagent)
# Review multiple files in parallel
results <- team_run(c(
"Review R/tool_display.R for any issues",
"Review R/permissions.R for any issues",
"Review R/compaction.R for any issues"
))
# Each element of results is the agent's response for that task
cat(results[[1]])Worker count defaults to
min(#tasks, parallelly::availableCores()) to respect
container CPU limits.
Work-stealing: team_coordinate()
team_coordinate() uses a shared SQLite task board where
workers claim tasks dynamically – faster workers take more tasks:
results_df <- team_coordinate(
tasks = c("task 1", "task 2", "task 3", "task 4", "task 5"),
n_workers = 2
)
# Returns a data.frame with columns: id, prompt, owner, status, result
print(results_df[, c("prompt", "status", "owner")])Inter-agent messaging
The shared board also supports messages between agents:
db <- board_create()
board_add_task(db, "analyse the sales data")
board_add_task(db, "generate the summary report")
# Worker 1 claims a task
task <- board_claim(db, worker_id = "w1")
board_send_message(db, sender = "w1", body = "Starting analysis...",
recipient = "coordinator")
# Complete with result
board_complete(db, task$id, result = "Analysis complete: 3 trends found")Sub-agents in the Shiny app
The agent can invoke sub-agents via the Agent tool
directly from the chat. Enable it by registering the agent tool:
client <- codeagent_client(chat,
permission_mode = "bypass",
worktree_isolation = TRUE # each sub-agent in its own git worktree
)