AgentWorkshop
Multi-agent orchestration for IEx. Backend-agnostic, MCP-enabled.
Run multiple LLM agents side by side, coordinate them with simple commands, and expose them as MCP tools. Works with Claude, Codex, or any CLI-based LLM through a pluggable backend.
Installation
def deps do
[
{:agent_workshop, "~> 0.1.0"},
# Pick your backend(s):
{:claude_wrapper, "~> 0.5"}, # for Claude Code CLI
{:codex_wrapper, "~> 0.1"}, # for OpenAI Codex CLI
# Optional, for MCP server:
{:anubis_mcp, "~> 1.0"},
{:bandit, "~> 1.0"},
{:plug, "~> 1.16"}
]
endQuick start
$ iex -S miximport AgentWorkshop.Workshop
# Configure with your backend
configure(
backend: AgentWorkshop.Backends.Claude,
backend_config: ClaudeWrapper.Config.new(working_dir: "."),
model: "sonnet",
permission_mode: :bypass_permissions,
context: "Elixir project. Run mix test before committing."
)
# Create agents
agent(:impl, "You write clean, well-tested code.", max_turns: 15)
agent(:reviewer, "You review code. Do not modify files.",
model: "opus", allowed_tools: ["Read", "Bash"])
# Talk to them
ask(:impl, "Implement caching for the user lookup")
|> pipe(:reviewer, "Review for correctness")
# Check on things
status()
total_cost()Setup files
Put agent configuration in .workshop.exs and it auto-loads on iex -S mix:
# .workshop.exs
configure(
backend: AgentWorkshop.Backends.Claude,
backend_config: ClaudeWrapper.Config.new(working_dir: "."),
model: "sonnet",
permission_mode: :bypass_permissions,
context: "My project description.",
mcp: [port: 4222] # auto-start MCP server
)
agent(:impl, "You write clean code.", max_turns: 15)
agent(:reviewer, "Review only.", model: "opus", allowed_tools: ["Read", "Bash"])Sync vs async
# Synchronous -- blocks until done
ask(:impl, "Implement the retry logic")
# Asynchronous -- returns immediately
cast(:impl, "Implement the caching layer")
cast(:tests, "Write tests for lib/encoder.ex")
status() # see who's done
await(:impl) # wait for one
await_all() # wait for everyoneCoordination
# Pipe: chain agents together
ask(:impl, "Implement caching")
|> pipe(:reviewer, "Review for edge cases")
|> pipe(:tests, "Write tests for this")
# Fan: same question to multiple agents
fan("What issues do you see in lib/retry.ex?", [:impl, :reviewer])
await_all()
result(:impl) # impl's take
result(:reviewer) # reviewer's takeMixed backends
Different LLMs for different roles:
configure(
backend: AgentWorkshop.Backends.Claude,
backend_config: ClaudeWrapper.Config.new(working_dir: ".")
)
agent(:impl, "You write code.", model: "sonnet")
agent(:reviewer, "You review code.",
backend: AgentWorkshop.Backends.Codex,
backend_config: CodexWrapper.Config.new(working_dir: "."),
model: "o3"
)MCP server
Expose Workshop as MCP tools so Claude Code can orchestrate agents:
# Start MCP server (or use mcp: [port: 4222] in configure)
mcp_server(port: 4222)
Then in .mcp.json:
{
"mcpServers": {
"workshop": {
"type": "http",
"url": "http://localhost:4222/mcp"
}
}
}
15 tools available: configure, create_agent, ask, cast, await,
await_all, status, result, pipe, fan, info, agents,
reset, dismiss, cost.
Observability
status() # dashboard table
info(:impl) # detailed map (model, cost, turns, ...)
result(:impl) # last response text
result(:impl, :full) # full result map
history(:impl) # print conversation
history(:impl, last: 3) # last 3 turns
cost() # itemized by agent
total_cost() # one numberLifecycle
reset(:impl) # clear conversation, keep config
dismiss(:impl) # remove agent entirely
reset_all() # stop everything
load("other.exs") # load a different setupBackends
| Backend | Package | CLI |
|---|---|---|
AgentWorkshop.Backends.Claude | claude_wrapper | Claude Code |
AgentWorkshop.Backends.Codex | codex_wrapper | OpenAI Codex |
Implement AgentWorkshop.Backend to add your own. See the behaviour
module for the 8 required callbacks.
Examples
See examples/ for ready-to-use .workshop.exs configs:
solo.exs-- single agentpair.exs-- implement + reviewteam.exs-- impl, reviewer, tests, docsmixed.exs-- Claude + Codex agents together
License
MIT -- see LICENSE.