# ExAI
ExAI is a lightweight, graph-first runtime for building agent systems on the
BEAM in Elixir.
## Development
### Start the app
```bash
iex -S mix
```
### Run tests
```bash
mix test
```
### Run Dialyzer
```bash
mix dialyzer
```
### Feature flags
Feature flags are configured under `config/config.exs`:
```elixir
config :ex_ai,
web_enabled: false,
remote_execution_enabled: false,
extism_enabled: false,
delegate_cli_enabled: false
```
Use `ExAI.feature_enabled?/1` to query them at runtime.
### Mermaid graph export
```elixir
graph =
ExAI.Graph.new(id: :sample)
|> ExAI.Graph.step(:fetch, &{:ok, &1})
|> ExAI.Graph.edge(:start, :fetch)
|> ExAI.Graph.edge(:fetch, :end)
ExAI.Graph.mermaid(graph, direction: :TD)
```
### Graph runtime examples
```bash
mix run examples/graph/simple_flow.exs
mix run examples/graph/fanout_join.exs
mix run examples/graph/cancelled_run.exs
```
### Agent quickstart
```elixir
agent =
ExAI.Agent.new(
name: :support,
instructions: "Answer using available context",
model: fn request -> %{content: "Echo: #{request.input}"} end
)
{:ok, context} = ExAI.Agent.run(agent, "hello")
context.result.output
```
### Direct provider adapters
```elixir
transport = fn _request ->
{:ok, %{status: 200, body: %{"choices" => [%{"message" => %{"content" => "ok"}}]}}}
end
agent =
ExAI.Agent.new(
name: :provider_agent,
model:
{:provider, :openai_compatible,
api_key: {:env, "OPENAI_API_KEY"}, transport: transport}
)
```
Supported direct providers:
- `:openai_compatible`
- `:anthropic`
### Delegate CLI adapters
```elixir
agent =
ExAI.Agent.new(
name: :delegate_agent,
model: {:delegate, :codex_cli, command: "codex", args: ["exec"]}
)
```
Supported delegate adapters:
- `:codex_cli`
- `:claude_code`
Missing executables, timeouts, and parse failures are normalized into typed
`ExAI.Error` values.
### Agent runtime examples
```bash
mix run examples/agent/simple_agent.exs
mix run examples/agent/tool_agent.exs
mix run examples/agent/validated_json_agent.exs
```
### End-to-end examples
```bash
mix run examples/e2e/provider_backed_agent.exs
mix run examples/e2e/delegate_cli_backed_agent.exs
mix run examples/e2e/remote_worker_graph.exs
mix run examples/e2e/just_bash_graph.exs
```
### Assistant-facing CLI docs
- Codex CLI usage: `docs/codex_cli_usage.md`
- Codex examples: `examples/codex_cli/`
- Claude Code usage: `docs/claude_code_usage.md`
- Claude examples: `examples/claude_code/`
- Model adapter usage (provider vs delegate): `docs/model_adapter_usage.md`
- JSON/JSONL contract: `docs/cli_contract.md`
- Release checklist and operational notes: `docs/release_checklist.md`
### Local web shell (minimal)
```elixir
{:ok, _pid} = ExAI.Web.Shell.start(port: 4007)
```
Then open:
- `http://127.0.0.1:4007/runs`
- `http://127.0.0.1:4007/api/runs`
- `http://127.0.0.1:4007/runs/<run_id>/stream` (SSE view)