Condukt is a framework for building AI agents in Elixir. Agents are OTP processes that can reason with an LLM, call tools, and orchestrate workflows.

This guide walks through installing Condukt, defining your first agent, and running a prompt end to end.

Install

Add :condukt to your dependencies in mix.exs:

def deps do
  [
    {:condukt, "~> 0.13"}
  ]
end

Then fetch dependencies:

mix deps.get

Configure an API key

Condukt uses ReqLLM, which auto discovers provider keys from the environment:

export ANTHROPIC_API_KEY="sk-ant-..."

You can also pass :api_key per agent or set it in config :condukt. See the Providers guide for the full list of supported backends.

Define an agent

defmodule MyApp.CodingAgent do
  use Condukt

  @impl true
  def tools do
    Condukt.Tools.coding_tools()
  end
end

use Condukt wires the module to a GenServer backed by Condukt.Session and provides defaults for system_prompt/0, model/0, thinking_level/0, init/1, and handle_event/2. Override what you need.

Start the agent

{:ok, agent} =
  MyApp.CodingAgent.start_link(
    api_key: System.fetch_env!("ANTHROPIC_API_KEY"),
    system_prompt: "You are an expert software engineer."
  )

Common options to start_link/1:

  • :api_key overrides config :condukt, :api_key
  • :model accepts the ReqLLM provider:model format
  • :cwd sets the working directory used by file and shell tools
  • :session_store enables conversation persistence (see Sessions and Persistence)
  • :compactor keeps context bounded over long runs (see Compaction)
  • :redactor strips secrets from outbound messages (see Redaction)

Run a prompt

{:ok, response} = Condukt.run(agent, "Create a GenServer that manages a counter.")

Condukt.run/3 runs the agent loop until the model stops calling tools and returns the final assistant message.

Stream events

agent
|> Condukt.stream("Add docs to the counter module.")
|> Stream.each(fn
  {:text, chunk} -> IO.write(chunk)
  {:tool_call, name, _id, _args} -> IO.puts("\nUsing tool: #{name}")
  :done -> IO.puts("\nDone")
  _ -> :ok
end)
|> Stream.run()

The full event vocabulary is described in Streaming and Events.

Add it to a supervision tree

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      {MyApp.CodingAgent,
        api_key: System.fetch_env!("ANTHROPIC_API_KEY"),
        system_prompt: "You are a helpful coding assistant."}
    ]

    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

From here, browse the rest of the guides for deeper coverage of each feature.