# GenAgentClaude
[](https://github.com/genagent/gen_agent_claude/actions/workflows/ci.yml)
[](https://hex.pm/packages/gen_agent_claude)
[](https://hexdocs.pm/gen_agent_claude)
Claude backend for [GenAgent](https://github.com/genagent/gen_agent),
built on top of [claude_wrapper](https://hex.pm/packages/claude_wrapper).
Provides `GenAgent.Backends.Claude`, which wraps the `claude` CLI and
translates its stream-json output into the normalized `GenAgent.Event`
values the state machine consumes.
## Prerequisites
The `claude` CLI must be installed and on your `PATH` (or set `CLAUDE_CLI`
to point at it). See the [Claude Code docs](https://docs.anthropic.com/en/docs/claude-code)
for install instructions.
## Installation
```elixir
def deps do
[
{:gen_agent, "~> 0.2.0"},
{:gen_agent_claude, "~> 0.1.0"}
]
end
```
## Quick start
```elixir
defmodule MyApp.Coder do
use GenAgent
defmodule State do
defstruct [:path, responses: []]
end
@impl true
def init_agent(opts) do
path = Keyword.fetch!(opts, :cwd)
backend_opts = [
cwd: path,
system_prompt: "You are a coding assistant.",
permission_mode: :accept_edits
]
{:ok, backend_opts, %State{path: path}}
end
@impl true
def handle_response(_ref, response, state) do
{:noreply, %{state | responses: state.responses ++ [response.text]}}
end
end
{:ok, _pid} = GenAgent.start_agent(MyApp.Coder,
name: "my-coder",
backend: GenAgent.Backends.Claude,
cwd: "/path/to/project"
)
{:ok, response} = GenAgent.ask("my-coder", "What does lib/foo.ex do?")
IO.puts(response.text)
```
## Session continuation
Claude CLI tracks multi-turn state via a server-side `session_id`. The
backend captures it from the terminal `:result` event and threads it
through `--resume` on subsequent turns -- transparently, no caller code
required.
```elixir
# Turn 1: fresh conversation
{:ok, r1} = GenAgent.ask("my-coder", "Remember the number 42")
# Turn 2: same thread, same agent
{:ok, r2} = GenAgent.ask("my-coder", "What number did I ask you to remember?")
# r2.text == "42"
```
## Backend options
`start_session/1` accepts any option supported by `ClaudeWrapper.stream/2`:
**Config:**
- `:binary`, `:working_dir` (aliased as `:cwd`), `:env`, `:timeout`,
`:verbose`, `:debug`
**Query:**
- `:model`, `:system_prompt`, `:append_system_prompt`, `:max_turns`,
`:max_budget_usd`, `:permission_mode`, `:dangerously_skip_permissions`,
`:effort`, `:json_schema`, `:agent`, `:brief`
**Backend-only:**
- `:stream_fn` -- a 2-arity function `(prompt, opts) -> Enumerable.t()`
that replaces the default `&ClaudeWrapper.stream/2`. Intended for tests
that want to stub out the subprocess.
See `GenAgent.Backends.Claude` for the full module docs.
## Event translation
Claude CLI's stream-json output is translated into `GenAgent.Event`
values by `GenAgent.Backends.Claude.EventTranslator`:
| Claude event | GenAgent event |
|---|---|
| `"system"` | filtered |
| `"assistant"` | `:text` (from text content blocks) |
| `"content_block_delta"` | `:text` (from delta text) |
| `"tool_use"` | `:tool_use` |
| `"tool_result"` | `:tool_result` |
| `"result"` | `:usage` + terminal `:result` |
| `"error"` | terminal `:error` |
| anything else | filtered |
Token counts from `data["usage"]` are pulled out into a separate
`:usage` event so `GenAgent.Response.usage` is populated.
## Testing
```bash
# Unit tests only (default, no CLI invocation)
mix test
# Include live integration tests that actually call the claude CLI
mix test --only integration
```
Integration tests are tagged `:integration` so they do not run by
default. They burn real tokens -- keep them cheap.
## License
MIT. See [LICENSE](LICENSE).