README.md

# 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

```elixir
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"}
  ]
end
```

## Quick start

```
$ iex -S mix
```

```elixir
import 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`:

```elixir
# .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

```elixir
# 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 everyone
```

## Coordination

```elixir
# 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 take
```

## Mixed backends

Different LLMs for different roles:

```elixir
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:

```elixir
# Start MCP server (or use mcp: [port: 4222] in configure)
mcp_server(port: 4222)
```

Then in `.mcp.json`:

```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

```elixir
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 number
```

## Lifecycle

```elixir
reset(:impl)     # clear conversation, keep config
dismiss(:impl)   # remove agent entirely
reset_all()      # stop everything
load("other.exs") # load a different setup
```

## Backends

| 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 agent
- `pair.exs` -- implement + review
- `team.exs` -- impl, reviewer, tests, docs
- `mixed.exs` -- Claude + Codex agents together

## License

MIT -- see [LICENSE](LICENSE).