# `ExAthena.Loop`
[🔗](https://github.com/udin-io/ex_athena/blob/v0.7.1/lib/ex_athena/loop.ex#L1)

Agent-loop kernel. Dispatches to a `ExAthena.Loop.Mode` implementation
and handles everything around it: caps, budget, hooks, counters, events,
and termination accounting.

Public entry point: `run/2`, returning `{:ok, %ExAthena.Result{}} |
{:error, reason}`.

## v0.3 breaking change

The return shape is now an `ExAthena.Result` struct instead of a loose
map. Every termination — success or error — produces a Result with the
typed `finish_reason` (see `ExAthena.Loop.Terminations` for the
enumeration). Callers can dispatch on `Result.category/1`
(`:success | :retryable | :capacity | :fatal`) instead of pattern-matching
individual atoms.

## Options

  * `:provider` — required. Provider atom (`:ollama`, `:openai`,
    `:claude`, `:mock`, `:req_llm`) or a module implementing
    `ExAthena.Provider`.
  * `:model`, `:system_prompt`, `:messages`, `:temperature`, `:top_p`,
    `:max_tokens`, `:stop`, `:timeout_ms`, `:tool_choice`,
    `:response_format`, `:provider_opts`, `:metadata` — forwarded to
    `ExAthena.Request.new/2`.
  * `:tools` — list of modules implementing `ExAthena.Tool` or `:all`
    (default — all builtins). `nil` falls back to `config :ex_athena,
    tools: …`.
  * `:mode` — atom (`:react`, `:plan_and_solve`, `:reflexion`) or module.
    Defaults to `:react`.
  * `:cwd`, `:phase`, `:assigns` — threaded into every tool's
    `ExAthena.ToolContext`.
  * `:allowed_tools`, `:disallowed_tools`, `:can_use_tool` — see
    `ExAthena.Permissions`.
  * `:hooks` — see `ExAthena.Hooks`.
  * `:max_iterations` (default 25) — hard iteration cap.
  * `:max_consecutive_mistakes` (default 3) — counter threshold at
    which the loop terminates with `:error_consecutive_mistakes`.
  * `:max_budget_usd` — optional float. Trips
    `:error_max_budget_usd` when cumulative cost crosses it.
  * `:tool_timeout_ms` (default 60_000) — per-call timeout for parallel
    tool execution.
  * `:max_concurrency` (default 4) — `Task.async_stream` concurrency
    cap for parallel-safe tool calls in a single iteration.
  * `:on_event` — `(ExAthena.Loop.Events.t -> term)` callback for
    streaming. Events are flat tuples (`{:content, text}`,
    `{:tool_call, tc}`, `{:tool_result, tr}`, `{:iteration, n}`,
    `{:usage, u}`, `{:error, reason}`, `{:done, Result}`).
  * `:session_id` — stable identifier for this run. Threaded into the
    `ToolContext` and used by hooks / storage / sidechain transcripts.
    Auto-generated when omitted.
  * `:parent_session_id` — when this run is a subagent of another run,
    the parent's `session_id`. `nil` for top-level runs. Used by
    `ExAthena.Sessions.Stores.Jsonl` (PR5) to write subagent
    sidechains and by `ExAthena.Agents` (PR4) to scope worktrees.
  * `:memory` — `:auto` (default — discover `AGENTS.md`/`CLAUDE.md`
    from `cwd` and `~/.config/ex_athena/`), `false` (skip memory
    entirely), or an explicit list of `Message.t()` to prepend.
  * `:skills` — `:auto` (default — discover skills from
    `<cwd>/.exathena/skills/` and `~/.config/ex_athena/skills/`),
    `false` (skip), or an explicit `%{name => %Skill{}}` map.
  * `:preload_skills` — list of skill names whose bodies should be
    activated up-front (skips the `[skill: name]` sentinel
    round-trip).

## Returns

  * `{:ok, Result.t()}` — ran to termination (possibly with an error
    subtype like `:error_max_turns`; the Result contains the
    classification).
  * `{:error, reason}` — unexpected failure before the loop started
    (e.g. unknown provider, bad tool module).

# `run`

```elixir
@spec run(
  String.t() | nil,
  keyword()
) :: {:ok, ExAthena.Result.t()} | {:error, term()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
