---
title: "Agents"
description: "Agents in HUD: built-in agents like Claude, OpenAI, and Gemini, the HUD gateway for routing models, and how to wire your own agent into a task run."
icon: "robot"
mode: "wide"
---

An **agent** is what acts inside an [environment](/v6/reference/environment): it works a
[task](/v6/reference/tasks) through the environment's [capabilities](/v6/reference/capabilities) and produces the
answer that gets graded. Concretely it's a **model** wrapped in a **harness** - the loop that feeds the
model observations and turns its output into actions. In the framework an agent is anything callable as
`await agent(run)`, where the `run` is the live handle for one task: its prompt, its connection to the
environment, and the trace it fills.

Because an environment only exposes capabilities, the agent isn't baked in - use a built-in agent for a
standard model, or [bring your own harness](/v6/advanced/extending#bring-your-own-harness) for a custom
loop.

## Built-in agents

The SDK ships one agent per major provider, reached two ways:

- **`create_agent(model)`** - the preferred path. It selects the matching provider agent for a model id
  and routes every call through the **HUD gateway**.
- **a provider agent directly** (e.g. `ClaudeAgent(ClaudeConfig(...))`) - the same class constructed
  yourself, for full config control or to call the provider with your own key instead of the gateway.

```python
from hud.agents import create_agent

agent = create_agent("claude-sonnet-4-5")   # routed through the gateway
```

The HUD gateway is an OpenAI-compatible endpoint (`settings.hud_gateway_url`, default
`https://inference.beta.hud.ai`) that fronts every provider behind your single `HUD_API_KEY`, so you
switch between Claude, GPT, and Gemini by name alone, with unified tracing. `create_agent` accepts any id
the gateway knows (`claude-...`, `gpt-...`, `gemini-...`); extra kwargs pass through to the agent's
config.

Built-in agents are **catalog-driven**: each run they read the environment's manifest, open the
capabilities they support, build the matching provider tools, and loop against `run.prompt_messages`.
Declaring a capability on the environment is enough; you never wire tools.

### Provider agents

Each model maps to a provider agent - the class that speaks that provider's API. Construct one directly
to set its full config or use your own provider key:

```python
from hud.agents import ClaudeAgent
from hud.agents.types import ClaudeConfig

agent = ClaudeAgent(ClaudeConfig(model="claude-sonnet-4-5", max_steps=30))
```

| Agent | Config | Default model |
|-------|--------|---------------|
| `ClaudeAgent` | `ClaudeConfig` | `claude-sonnet-4-6` |
| `OpenAIAgent` | `OpenAIConfig` | `gpt-5.5` |
| `GeminiAgent` | `GeminiConfig` | `gemini-3-pro-preview` |
| `OpenAIChatAgent` | `OpenAIChatConfig` | `gpt-5.4-mini` |
| `ClaudeSDKAgent` | `ClaudeSDKConfig` | `claude-sonnet-4-6` |

Each config lives in `hud.agents.types`. `OpenAIChatAgent` speaks the OpenAI Chat Completions API, so it
points at any compatible server (vLLM, a local model) via `base_url`; `ClaudeSDKAgent` runs the `claude`
CLI over an `ssh` capability, against the env's filesystem. Every knob (`model`, `max_steps`,
`system_prompt`, `citations_enabled`) lives on the config; `__call__(run)` takes only the run.

## create_agent {#create-agent}

```python
create_agent(model: str, **kwargs) -> GatewayAgent
```

The `create_agent` function resolves `model` to a gateway agent type and returns that provider agent
wired to the gateway. Extra `kwargs` forward to the matched provider config (the `*Config` for the
resolved type), with `model` and a gateway `model_client` filled in. Passing `completion_kwargs` only
works when `model` resolves to `OpenAIChatAgent`, since `completion_kwargs` lives only on
`OpenAIChatConfig`.

A model id maps to one of four gateway agent types (`AgentType`), each a provider agent:

| `AgentType` | Agent class |
|-------------|-------------|
| `claude` | `ClaudeAgent` |
| `openai` | `OpenAIAgent` |
| `gemini` | `GeminiAgent` |
| `openai_compatible` | `OpenAIChatAgent` |

For a provider key instead of the gateway, or for `ClaudeSDKAgent` (not a gateway type), construct the
provider agent directly.

## Agent

Every agent implements the `Agent` base class (`hud.agents.base`): one abstract method,
`__call__(run: Run) -> None`. An agent drives the live [`Run`](/v6/reference/types#run) to completion,
filling `run.trace` in place; the graded answer is `run.trace.content`. An agent is stateless per run -
everything comes from `run` - so one instance drives many concurrent rollouts.

## Running an agent

Run a task with an agent two ways. **Programmatically**, pass the agent to `Task.run` or `Taskset.run`
with a [runtime](/v6/reference/runtime):

```python
from hud.agents import create_agent
from hud.eval import LocalRuntime, Taskset

agent = create_agent("claude-sonnet-4-5")
taskset = Taskset.from_file("tasks.py")        # scaffolded tasks.py exports a list of tasks
job = await taskset.run(agent, runtime=LocalRuntime("env.py"))
print(job.reward)
```

**From the CLI**, `hud eval` takes a task source and an agent name (`claude`, `openai`, `gemini`,
`openai_compatible`); see [running an eval](/v6/guides/running-an-eval) for the walkthrough and the
[CLI reference](/v6/reference/cli#hud-eval) for the full flag set.

## Bring your own harness

Any loop or framework can be an agent: subclass `Agent`, drive the environment off the `run`, and write
the final answer to `run.trace.content` (what gets graded). Since this is outside the standard workflow,
the seam, the `Run` object you work with, the step types you record, and worked examples live in
[Extending HUD](/v6/advanced/extending#bring-your-own-harness).

To run an agent end to end see [running an eval](/v6/guides/running-an-eval); for where each rollout runs
see [runtimes](/v6/reference/runtime), and for the [`Run`](/v6/reference/types#run) an agent fills see
[types](/v6/reference/types).
