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

# Self-Hosted Agent (Docker)

> Run the whole agent — model calls, loop and tools — inside a local Docker container you own

Run the whole agent — model calls, loop and tools — inside a local Docker container you own.

> [!NOTE]
>
> `docker` is one of **eight** places `run_on=` can host the whole loop — see [Placement](https://praison.ai/docs/features/placement.md#where-run-on-and-compute-can-point) for the full list (`anthropic`, `docker`, `e2b`, `modal`, `daytona`, `flyio`, `tenki`, `novita`). `docker` now routes through the same generic backend as every other cloud place — one code path for every runtime. Its own bespoke backend was retired in [PR #4077](https://github.com/MervinPraison/PraisonAI/pull/4077) because its containers could be listed but not stopped: they were named in a shape `DockerCompute`'s lookup did not recognise.

> [!NOTE]
>
> **What changed (PR #4077).** `docker` and the cloud places now share one implementation. Behaviour for existing `run_on="docker"` code is unchanged; the container-lookup bug that made `praisonai managed stop` fail on it is fixed.

> [!NOTE]
>
> As of [PR #4092](https://github.com/MervinPraison/PraisonAI/pull/4092), the vendor compute providers live in the standalone `praisonai-sandbox` package (same names, same behaviour; old `praisonai.integrations.compute.*` imports still work through a shim).

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "run_on=docker"
        A[🤖 Agent] --> B[🐳 Docker container]
        B --> C[☁️ LLM API]
        B --> D[🔧 Tools inside container]
    end

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef container fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef api fill:#10B981,stroke:#7C90A0,color:#fff
    classDef tool fill:#F59E0B,stroke:#7C90A0,color:#fff

    class A agent
    class B container
    class C api
    class D tool
```

## Quick Start

**1. Minimal**

One line moves the whole agent into a container.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(
    name="builder",
    instructions="You build things.",
    run_on="docker",
)
agent.start("Write a Python script that prints the first 10 primes, then run it")
```

**2. With a prebuilt image**

Supply your own image with `praisonaiagents` baked in to skip the \~1 min first-run install.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai import HostedAgent, HostedAgentConfig
from praisonaiagents import Agent

hosted = HostedAgent(
    provider="docker",
    config=HostedAgentConfig(model="gpt-4o-mini", system="Be brief."),
    image="my-org/praisonai-agent:latest",
)
agent = Agent(name="builder", backend=hosted)
agent.start("Summarise the README in three bullets")
```

**3. Extra environment and packages**

Pass extra environment variables and packages, and disable container reuse.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai import HostedAgent, HostedAgentConfig
from praisonaiagents import Agent

hosted = HostedAgent(
    provider="docker",
    config=HostedAgentConfig(model="gpt-4o-mini"),
    env={"MY_FLAG": "1"},
    pip_packages=["praisonaiagents", "httpx"],
    keep_alive=False,
)
agent = Agent(name="builder", backend=hosted)
agent.start("Fetch example.com and count the words")
```

***

## How It Works

The agent on your machine ships its serialisable config into the container, which rebuilds the agent, calls the LLM and runs the tools — then returns the answer.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent as Agent (host)
    participant Container as Docker container

    User->>Agent: agent.start(request)
    Agent->>Container: write config + prompt as JSON
    Note over Container: rebuild Agent from JSON
    Note over Container: call LLM + run tools
    Container-->>Agent: one line of JSON result
    Agent-->>User: response
```

The model API key travels *into* the container via `-e KEY` — the value is read from your host environment, never placed on the command line, so it never shows up in `docker inspect` or a process listing.

***

## `run_on="docker"` vs `tools_run_on="docker"`

Both spellings name the same place. What differs is what crosses the boundary — the parameter name carries the scope.

| | `tools_run_on="docker"` | `run_on="docker"` |
| - | - | - |
| The loop runs | your process | **in the container** |
| The model is called from | your machine | **the container** |
| Needs the API key where | your machine | **the container** |
| Your files reachable | yes | only what you mounted |

The object reports which scope you chose:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
>>> from praisonaiagents import Agent
>>> Agent(name="x", instructions="i", run_on="docker")
Agent(name='x', thinks_on='a Docker container', tools_run_on='a Docker container')

>>> Agent(name="x", instructions="i", tools_run_on="docker")
Agent(name='x', thinks_on='this machine', tools_run_on='a Docker container')
```

Which one do you want?

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Q{Where should the<br/>model call happen?}
    Q -->|In the container| A[run_on=docker<br/>whole agent inside]
    Q -->|On my machine| B[tools_run_on=docker<br/>only tools inside]

    classDef question fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef answer fill:#10B981,stroke:#7C90A0,color:#fff

    class Q question
    class A,B answer
```

***

## Configuration Options

Pass these to `HostedAgent(provider="docker", ...)`.

| Option | Type | Default | Description |
| - | - | - | - |
| `config` | `HostedAgentConfig \| dict \| None` | `None` | Agent config (instructions, llm, name, etc.). Only JSON-safe fields cross into the container. |
| `image` | `str` | `"python:3.12-slim"` | Container image. Supply your own with `praisonaiagents` baked in to skip the first-run install. |
| `env` | `dict[str, str]` | `{}` | Extra environment variables passed into the container. |
| `keep_alive` | `bool` | `True` | Reuse one container across calls so a follow-up turn does not pay start-up again. |
| `pip_packages` | `list[str]` | `["praisonaiagents"]` | Packages installed inside the container on first run. |

Since [PR #4077](https://github.com/MervinPraison/PraisonAI/pull/4077) the generic backend honours `image=` too, so `HostedAgent(provider="docker", image="my-org/agent:latest")` behaves the same across the compute-backed places.

### Model keys forwarded automatically

These variables are forwarded into the container when set in your host environment, passed with `-e KEY` (value read from your env), so they never appear in `docker inspect` or a process listing:

`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `GOOGLE_API_KEY`, `GROQ_API_KEY`, `MISTRAL_API_KEY`, `COHERE_API_KEY`, `OPENROUTER_API_KEY`, `DEEPSEEK_API_KEY`, `XAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_API_BASE`.

***

## Limitations

> [!WARNING]
>
> These are real. Hit them with eyes open.
>
> * **Python callables in `tools=` do not cross into the container.** A function defined in your process cannot be reconstructed remotely; the container rebuilds the agent from its serialisable config only. This is the same limitation the hosted runtimes have.
> * **The container needs the model API key.** Moving the loop is the point, so the key is forwarded from your host environment.
> * **First run installs `praisonaiagents` (\~1 min)** unless `image=` supplies one that already has it.

***

## Troubleshooting

When Docker is not running, `run_on="docker"` fails fast and points you at the daemon-free alternative:

```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
RuntimeError: run_on='docker' cannot start: docker is not available on this machine.
  For docker, check the daemon is running (`docker info`).
  For a cloud place, check its credential is set.
  To keep the loop here and move only the tools, use tools_run_on='docker' instead.
```

***

## Best Practices

> [accordion] Supply your own image= for production
>
> Bake `praisonaiagents` into a custom image and pass it as `image=`. The first-run install (\~1 min) disappears and start-up becomes predictable.

> [accordion] Leave keep\_alive=True for multi-turn conversations
>
> One container is reused across calls, so a follow-up turn does not pay start-up again. The default is already `True`.

> [accordion] Prefer tools\_run\_on='docker' to keep the model call local
>
> When you want the loop on your machine — cheaper, and no API key inside the container — move only the tools with `tools_run_on="docker"`.

> [accordion] Call .shutdown() when you disable keep\_alive
>
> With `keep_alive=False`, tear the container down with `.shutdown()` or use the backend as a context manager (`with HostedAgent(...) as hosted:`).

> [accordion] With keep\_alive=True, the container is still cleaned up automatically
>
> Since [PR #4109](https://github.com/MervinPraison/PraisonAI/pull/4109), a `weakref.finalize` on the backend reclaims the container when the backend is collected or the process exits — so a `keep_alive=True` container no longer outlives your script.
>
> `.shutdown()` still exists: call it when you want teardown to happen **now** rather than whenever GC runs.
>
> > [!NOTE]
> >
> > On an older version? Reclaim any leftover containers with `praisonai managed ps` / `managed stop`. See [the `run_on=` finalizer](https://praison.ai/docs/features/reclaim-stray-sandboxes#and-the-run-on-finalizer-that-was-never-registered-pr-4109).

***

## Related

> [card] [Hosted Agent](https://praison.ai/docs/features/hosted-agent.md)
>
> `run_on="anthropic"` — the vendor-hosted sibling.

> [card] [Placement](https://praison.ai/docs/features/placement.md)
>
> One vocabulary for where the whole agent and its tools run.

> [card] [Where It Runs](https://praison.ai/docs/features/where-does-it-run.md)
>
> Ask the object where the model thinks and the tools run.

> [card] [Shared Sandbox](https://praison.ai/docs/features/shared-sandbox.md)
>
> For the `tools_run_on="docker"` case across a flow.

> [card] [Reclaim Stray Sandboxes](https://praison.ai/docs/features/reclaim-stray-sandboxes.md)
>
> Find and stop containers left behind by an older version.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.