Current section
Files
Jump to
Current section
Files
README.md
# Normandy
> Build production-ready AI agents in Elixir β structured schemas, tool calling, multi-agent coordination, streaming, and distributed sessions, with first-class Anthropic Claude support.
[](https://hex.pm/packages/normandy)
[](https://hexdocs.pm/normandy)
[](https://github.com/thetonymaster/normandy/actions/workflows/ci.yml)
[](https://github.com/thetonymaster/normandy/blob/main/LICENSE)
**Normandy** is an Elixir framework for building reliable LLM agents on the BEAM. It gives you type-safe input/output schemas with automatic JSON Schema generation, tool/function calling, conversational memory, and OTP-native primitives for multi-agent coordination and distributed, fault-tolerant sessions. It ships with a built-in adapter for [Anthropic Claude](https://www.anthropic.com) and a clean protocol for any other LLM provider.
## Features
- **π§ Agent system** β conversational agents with memory, state, and turn-based history.
- **π Schema DSL** β typed, validated structs with JSON Schema generation (nested schemas, `anyOf`/`oneOf`/`allOf`, conditional `if`/`then`/`else`, virtual fields, introspection).
- **π§ Tool calling** β LLM tool/function calling with automatic execution loops.
- **π€ Multi-agent coordination** β reactive patterns (`race`/`all`/`some`), agent pools, and supervised agent processes.
- **π Distributed sessions** β single-node to multi-node, fault-tolerant sessions across Tiers 0/1/2 (in-memory/ETS, Postgres, Mnesia, Redis) with eager resume on node loss.
- **π‘οΈ Guardrails** β input/output admission control with fail-open/closed policies and semantic scope checks.
- **π Streaming** β real-time response streaming with callback-based event processing.
- **π° Prompt caching** β up to 90% cost reduction via automatic Anthropic prompt caching.
- **π Resilience** β built-in retry (exponential backoff + jitter) and circuit breaker patterns.
- **π¦ Batch processing** β concurrent processing of many inputs with progress tracking.
- **π Context management** β token counting, automatic truncation, and LLM-based summarization.
- **π Protocol support** β interoperate via Model Context Protocol (MCP) and Agent-to-Agent (A2A).
- **π Observability** β Telemetry events, structured lifecycle logging, and OpenTelemetry-compatible spans.
- **π― Type safety** β comprehensive type system with Dialyzer support, backed by 900+ tests including property-based testing.
## Installation
Add `normandy` to your dependencies in `mix.exs`:
```elixir
def deps do
[
{:normandy, "~> 2.0"}
]
end
```
Upgrading from 1.x? See [MIGRATING-2.0.md](MIGRATING-2.0.md).
Then fetch dependencies:
```bash
mix deps.get
```
## Quick Start
Define structured data, then run an agent against Anthropic Claude:
```elixir
# 1. Configure an LLM client (built-in Anthropic Claude adapter; prompt caching is on
# by default)
client = %Normandy.LLM.ClaudioAdapter{api_key: System.get_env("ANTHROPIC_API_KEY")}
# 2. Initialize an agent
agent =
Normandy.Agents.BaseAgent.init(%{
client: client,
model: "claude-opus-5-5"
})
# 3. Run a turn: {:ok, agent, response} with the updated agent (it holds the
# conversation), or {:error, exception}, e.g. a %Normandy.LLMError{}
input = %{chat_message: "Explain Elixir's actor model in one sentence."}
case Normandy.Agents.BaseAgent.run(agent, input) do
{:ok, _agent, response} -> IO.puts(response.chat_message)
{:error, error} -> IO.puts("Turn failed: " <> Exception.message(error))
end
```
Defining a typed schema is just as direct:
```elixir
defmodule User do
use Normandy.Schema
io_schema "User profile" do
field(:name, :string, description: "Full name", required: true)
field(:age, :integer, description: "Age", minimum: 0, maximum: 150)
end
end
# Export as JSON Schema for LLM prompts / structured output
schema = User.get_json_schema()
```
Bring your own LLM by implementing the `Normandy.Agents.Model` protocol β Claude is supported out of the box, but nothing is hard-wired to it.
## Documentation
Full API reference and guides are published on HexDocs:
- **π [API documentation](https://hexdocs.pm/normandy)** β every public module, grouped by area: Core, Agents, Durable turns, Session stores and registries, Memory, Hooks, Behaviours, DSL, Coordination, Components, Tools, Context Management, Resilience, Guardrails, Batch Processing, MCP, A2A, LLM Adapters, Testing, Errors and Telemetry.
- **π [Distributed sessions guide](docs/guides/distributed_sessions.md)** β Tiers 0/1/2, durable stores, and multi-node setup.
- **πͺ [Hooks guide](docs/guides/hooks.md)** β lifecycle hooks: rewrite, halt, inject, audit.
- **π§ [Agent memory guide](docs/guides/agent-memory.md)** β the memory tool and its stores.
- **π§ͺ [Testing guide](docs/guides/testing.md)** β offline tests with `Normandy.Test.FakeClient`, durable sessions, telemetry, and the store contracts for your own backends.
- **π [CHANGELOG](CHANGELOG.md)** β release notes and migration guidance.
- **πΊοΈ [ROADMAP](ROADMAP.md)** β phased development history and direction.
Generate the docs locally with `mix docs` and open `doc/index.html`.
## Development
```bash
mix precommit # compile (warnings as errors), unused deps, format, credo, dialyzer, test
mix test # run the default suite (integration tests skipped)
mix test --cover # run with coverage
mix credo --strict # lint
mix dialyzer # static type analysis
mix format # format code
```
Run the live-API integration suite with an Anthropic key:
```bash
export ANTHROPIC_API_KEY="your-api-key"
mix test --include integration --include normandy_integration
```
## Contributing
Contributions are welcome β please open an issue or submit a pull request.
## License
Released under the [MIT License](LICENSE).
## Acknowledgments
The schema system is inspired by [Ecto](https://github.com/elixir-ecto/ecto)'s approach to data definition, validation, and changesets.
---
**Made with Elixir** π