> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hud.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate to v6

> Migrate v5 HUD environments (scenarios, tools, and MCP serving) to the leaner v6 spec built around tasks and capabilities, with side-by-side examples.

v6 is a leaner spec. The environment is no longer an MCP server that hands tools to the agent - it's a small control channel that exposes **capabilities** (connections the agent drives itself) and **tasks** (prompt then reward). The agent's harness owns the tools, so the environment side gets noticeably smaller.

## What stays compatible

**Environments are mostly backwards compatible.** The v6 SDK still runs environments written against the v5 surface: `@env.scenario`, `@env.tool` / `env.add_tool`, `env("scenario")`, and `env.run(...)` all keep working - each emits a `DeprecationWarning` and adapts to v6 under the hood. New (v6) agents can evaluate your existing environments unchanged.

<Warning>
  **The break is on the agent side.** v6 serves a new control channel instead of MCP stdio/http, so **old (v5) agents cannot run old or new environments** - once an environment is served by the v6 SDK (whether authored in the v5 or v6 style), only a v6 client can drive it. Upgrade the side that *runs* agents to v6.
</Warning>

So you can upgrade the SDK first and keep your environments as-is, then convert at your own pace. Converting is worth it: the v6 spec removes most of the tool-wiring boilerplate.

## At a glance

| v5                                           | v6                                                         | Notes                                                             |
| -------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------- |
| `Environment("name")`                        | `Environment(name="name", capabilities=[...])`             | positional name still works; declare capabilities up front        |
| `@env.scenario("count")`                     | `@env.template()`                                          | same `yield prompt` then `yield reward` generator                 |
| `@env.tool` / `env.add_tool(ComputerTool())` | a **capability** (`ssh` / `mcp` / `cdp` / `rfb` / `robot`) | the agent's harness brings the tools now                          |
| `env("count", word=...)`                     | `count(word=...)`                                          | keep the `@env.template` return value; calling it builds a `Task` |
| `task.run("claude")` / `hud.eval(task)`      | `await task.run(agent)`                                    | or just `hud eval tasks.py claude`                                |
| `env.run(transport=...)`                     | `await env.serve()` / `hud serve` / `hud deploy`           | v6 serves a control channel, not MCP                              |
| `.slug`, `.columns` on a task                | `.slug`, `.columns` on the `Task`                          | unchanged                                                         |

The CLI you already use is stable: `hud init`, `hud deploy`, `hud eval`, and `hud sync tasks` all carry over. `hud dev` is now `hud serve` (the old name remains as a deprecated alias).

## Walk through a conversion

Here's a small v5 coding environment - a couple of tools and one scenario:

```python title="env.py (v5)" theme={"dark"}
from hud import Environment
from hud.tools import BashTool, EditTool
from hud.native import BashGrader

env = Environment("coder")
env.add_tool(BashTool())
env.add_tool(EditTool())

@env.scenario("fix-tests")
async def fix_tests(target: str = "tests/"):
    answer = yield f"Make the tests in {target} pass."
    yield await BashGrader.grade(command=f"pytest {target} -q")
```

<Steps>
  <Step title="Replace tools with a capability">
    This is the biggest change. In v5 you registered tools and the environment forwarded them, translating per provider. In v6 you declare a **capability** - a connection - and the agent's harness attaches its own tools to it. Shell and file tools become a `Workspace`: the environment starts the sandboxed workspace and publishes its `ssh` capability when it serves:

    ```python title="env.py (v6)" theme={"dark"}
    from hud.environment import Environment

    env = Environment(name="coder")
    env.workspace("/workspace")
    ```

    Other tool kinds map the same way: a browser becomes `cdp`, full computer-use becomes `rfb`, a robot becomes `robot`, and any custom MCP tools become an `mcp` capability via `Capability.mcp(name=..., url=...)`. You no longer hand-wire `ComputerTool()` / `BashTool()` or call `env.as_claude_tools()` - the harness does that.
  </Step>

  <Step title="Rename @env.scenario to @env.template">
    The generator body is identical - `yield` a prompt, receive the answer, `yield` a reward. Just swap the decorator and keep a reference to the returned `Task`:

    ```python title="env.py (v6)" theme={"dark"}
    from hud.graders import BashGrader

    @env.template()
    async def fix_tests(target: str = "tests/"):
        answer = yield f"Make the tests in {target} pass."
        yield await BashGrader.grade(command=f"pytest {target} -q")
    ```

    `@env.template()` also accepts `id=`, `description=`, and optional `input=` / `returns=` types (surfaced as JSON schemas in the manifest). The decorated function is a *template* that mints `Task` rows when called. The v5 scenario options (`chat`, `returns`, `exclude_tools`, ...) still parse through the compatibility layer if you keep `@env.scenario`.
  </Step>

  <Step title="Build tasks by calling the task function">
    `env("fix-tests", target="tests/")` becomes a direct call on the task function. It returns a `Task` - the runnable unit - and `.slug` / `.columns` work exactly as before:

    ```python title="tasks.py (v6)" theme={"dark"}
    from env import fix_tests

    easy = fix_tests(target="tests/unit")
    easy.slug = "fix-unit-tests"
    easy.columns = {"suite": "unit"}
    ```
  </Step>

  <Step title="Run it">
    Locally, `hud eval` is unchanged:

    ```bash theme={"dark"}
    hud eval tasks.py claude
    ```

    Programmatically, the `hud.eval(task)` context manager and `task.run(model)` are replaced by handing an agent to the task - it returns a `Job` holding the graded runs:

    ```python theme={"dark"}
    from hud.agents import create_agent

    agent = create_agent("claude-sonnet-4-5")
    job = await fix_tests(target="tests/").run(agent)
    print(job.reward)
    ```

    `create_agent` routes any model (`claude-...`, `gpt-...`, `gemini-...`, `grok-...`) through the HUD gateway and wires the tools for whichever capabilities the environment exposes.
  </Step>

  <Step title="Serve and deploy">
    v5 served an MCP server via `env.run(transport=...)`. v6 serves its control channel - use `hud serve` while iterating and `hud deploy` to publish (it builds and publishes in one step). `await env.serve(host, port)` is the in-code equivalent.
  </Step>
</Steps>

## Converting with an agent

The conversion is mechanical, so the fastest path is to let your coding agent do it. Add the HUD docs to your agent - they're available as an MCP server at `docs.hud.ai/mcp`, or use the **Copy / Claude / ChatGPT** buttons at the top of any docs page - then point it at this guide and the [Environment reference](/v6/reference/environment) and ask it to adapt your `env.py`. A prompt like:

> Convert this v5 HUD environment to v6 using the migration guide at docs.hud.ai. Rename scenarios to tasks, replace registered tools with the capability they imply (shell/files → `ssh`, browser → `cdp`, computer-use → `rfb`, custom tools → `mcp`), switch `env("name", ...)` to calling the task, and fix the `hud.tools` imports below.

Because every old import still resolves (the SDK ships shims) and registered tools are auto-promoted to capabilities at serve time, **your environment keeps running throughout** - convert incrementally and let the `DeprecationWarning`s tell you what's left.

### Imports to update

In v6, `hud.tools` was removed entirely - tools are capabilities now - but every old import still resolves with a `DeprecationWarning`:

| v5 import                                                                                                                            | What it resolves to now                                                                                                                                                              | What to do                                                                                                                                                                            |
| ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AgentTool`, `BaseTool`                                                                                                              | **removed** - resolve to a no-op stand-in                                                                                                                                            | drop the class; expose a sub-agent as a plain function on a FastMCP server and attach it as an `mcp` capability - see [Subagents as tools](/v6/advanced/extending#subagents-as-tools) |
| Result types: `EvaluationResult`, `ScenarioResult`, `SubScore`, `AgentAnswer`, `Citation`                                            | redirected to their v6 homes: `hud.graders` (`ScenarioResult` is now `EvaluationResult`), `hud.environment` (`AgentAnswer` is now `Answer`, without `citations`), `hud.agents.types` | change the import to the module the warning names                                                                                                                                     |
| `ContentResult`                                                                                                                      | supported in v6 at `hud.agents.types`                                                                                                                                                | `from hud.agents.types import ContentResult` - `.to_content_blocks()` builds a tool's `list[ContentBlock]` from text + an optional image                                              |
| `ToolError`                                                                                                                          | removed (no v6 counterpart)                                                                                                                                                          | return an error result (`ContentResult(error=...).to_content_blocks()`) or raise an ordinary exception - the loop surfaces it to the agent and continues                              |
| `hud.server.MCPServer`                                                                                                               | **removed** - now plain `fastmcp.FastMCP` (a deprecation shim keeps the old import working and warns)                                                                                | `from fastmcp import FastMCP` (same `@server.tool` / `run_async`); manage its lifecycle with `@env.initialize` / `@env.shutdown`                                                      |
| Shell/edit tools: `BashTool`, `EditTool`, `ShellTool`, `ApplyPatchTool`, ...                                                         | **removed** - resolve to a marker that synthesizes an `ssh` capability at serve                                                                                                      | call `env.workspace(root)` instead                                                                                                                                                    |
| Computer tools: `HudComputerTool`, `AnthropicComputerTool`, `OpenAIComputerTool`, `GeminiComputerTool`, `QwenComputerTool`, ...      | **removed** - resolve to a marker that synthesizes an `rfb` capability at serve                                                                                                      | declare an `rfb` (computer-use) or `cdp` (browser) capability instead                                                                                                                 |
| Anything else under `hud.tools`: `PlaywrightTool`, `JupyterTool`, `MemoryTool`, filesystem tools, executors, `SubmitTool`, `BaseHub` | **no-op stand-in** (silently does nothing)                                                                                                                                           | remove it - declare a capability (`cdp` for browser) or serve your own tool over `mcp`                                                                                                |
| Graders: `hud.native` (`BashGrader`, `LLMJudgeGrader`, `exact_match`, ...)                                                           | aliased to `hud.graders`                                                                                                                                                             | change the import to `from hud.graders import ...`                                                                                                                                    |
| Chat: `hud.services.Chat`                                                                                                            | aliased to `hud.eval.chat` (re-exported as `hud.Chat`)                                                                                                                               | change the import to `from hud import Chat`                                                                                                                                           |
| `hud.services.ChatService`                                                                                                           | **removed** - the A2A executor left the SDK                                                                                                                                          | copy the reference server in `cookbooks/a2a-chat/server.py` (a thin A2A adapter over `Chat`)                                                                                          |
| `hud.shared.*` (`exceptions`, `requests`, ...)                                                                                       | **merged into `hud.utils`** (no alias - no environment imported it)                                                                                                                  | change the import to `from hud.utils... import ...`                                                                                                                                   |

The rule of thumb: **grading types move to `hud.graders`, tools become capabilities, and everything else under `hud.tools` is going away.** When the deprecation log is quiet, the conversion is done.

## Next steps

<CardGroup cols={2}>
  <Card title="Environment reference" icon="cube" href="/v6/reference/environment">
    Define capabilities, lifecycle hooks, and tasks.
  </Card>

  <Card title="Tasks & Tasksets" icon="list-check" href="/v6/reference/tasks">
    Define tasks, collect tasksets, and grade runs.
  </Card>

  <Card title="Package & deploy" icon="rocket" href="/v6/reference/runtime">
    Publish with hud deploy and run at scale.
  </Card>
</CardGroup>
