Topology
One ensemble process owning one sub-agent owning one backend session. The simplest useful ensemble.
+-------+ +---------+ +----------+
| E.* | -> | Solo | -> | agent | -> backend
+-------+ +---------+ +----------+When to reach for it
- You want a single LLM session you can talk to by name.
- You want the conversation history to persist across turns.
- You're prototyping before adding coordination.
- You have a "REPL-for-task-X" shape: "ask the Elixir reviewer", "ask the docs writer", "ask the SQL coach".
For anything with concurrency or multi-stage logic, reach for Pool, Pipeline, or Supervisor instead.
Config
config :gen_agent_ensemble,
ensembles: [
[
name: "solo",
strategy: GenAgentEnsemble.Strategies.Solo,
opts: [
agent:
{"w", GenAgentEnsemble.Agents.Simple,
backend: GenAgent.Backends.Anthropic,
system: "You are a pragmatic Elixir reviewer.",
model: "claude-sonnet-4-6"}
]
]
]Canonical workflow
One-shot synchronous turn
iex> E.ask!("solo", "what's wrong with Enum.map(list, &(&1 + 1))?")
"Nothing -- that's idiomatic Elixir..."
iex> E.ask!("solo", "now rewrite that as a Stream pipeline")
"Stream.map(list, &(&1 + 1)) |> Enum.to_list()"The second call sees the first as conversation history. Token usage grows each turn because the backend resends the full message array.
Async (fire-and-check-later)
iex> {:ok, token} = E.tell("solo", "explain ETS in one paragraph")
{:ok, "tok-5"}
iex> # ...do other work...
iex> E.await("solo", token) |> E.puts()
ETS (Erlang Term Storage) is an in-memory key-value store...
:okInspect
iex> E.status("solo")
{:ok, %{
session: "solo",
strategy: GenAgentEnsemble.Strategies.Solo,
agent: "w",
queued_tokens: 0,
agents: ["w"],
in_flight: 0,
pending_tokens: []
}}Variations
Swap backends. Change
backend:to anyGenAgent.Backendimplementation (Anthropic,Claude,OpenAI,Codex,GenAgentEnsemble.Backends.Echo, your own).Pass cwd for file-aware backends. Claude CLI honours
:cwd:agent: {"w", GenAgentEnsemble.Agents.Simple, backend: GenAgent.Backends.Claude, cwd: "/path/to/project", permission_mode: :plan, system_prompt: "You are a code reviewer."}Custom callback module. Replace
GenAgentEnsemble.Agents.Simplewith your ownuse GenAgentmodule when you want richer state or prompt-engineered behaviour between turns.
Gotchas
- Conversation accumulates. Each turn's input-token count grows
because the full history is replayed to the backend. Stop and
restart the ensemble to reset the session. (
E.stop("solo")followed by re-declaring in config orE.start_link/1for ad hoc.) - One in-flight turn at a time. A second
tellwhile a turn is processing is queued inGenAgent's mailbox and runs after the first completes, not in parallel. Use Pool if you want parallelism.