Skip to main content
Every Agent, AgentTeam, and AgentFlow now tells you — from repr() alone or via where_does_it_run() — where the model runs and where the tools run.

Quick Start

1

Ask an agent where it runs

2

A workflow with a shared sandbox

3

Read the answer as a dictionary


Three topologies at a glance

tools_run_on= moves the tools out but keeps the model call local. A whole-loop backend moves both off this machine — hosted on a vendor’s cloud, or self-hosted in a container you own. The repr names both places, so you can tell them apart at a glance.
There is no HostedAgent class to import today. When a backend= object reports its provider as anthropic (its class name contains Hosted or Anthropic and it exposes a .provider), both places become Anthropic's cloud. You can see the exact phrasing without any backend using say_place:

How the object knows

repr() asks a single shared helper — describe() — which reads three attributes off the object and turns provider names into plain phrases. describe() never raises — if a property throws, thinks_on falls back to this machine so that describing where something runs can never break the thing it describes. _backend_places() now asks the backend via provider_name rather than name-matching the class. A self-hosted backend (like run_on="docker") used to be misreported as thinking on this machine because its class name did not contain Hosted or Anthropic; asking it what it is fixes that — the whole-loop container is now reported as a Docker container for both places.

What each place name means

Provider names map to phrases a non-developer can read. These are the exact strings the object returns. Two public aliases resolve to the backend that actually runs — the alias name never appears in the output: An unknown provider falls back to its own name: say_place("some-new-cloud") returns "some-new-cloud". local means two different backends depending on which parameter carried it, so the phrase depends on where the word came from. run_in="local" collapses to the subprocess backend; tools_run_on="local" is a plain shell with no policy. Pass via="compute" for the tools_run_on= reading:

The subprocess warning

A sandbox=True agent runs tools in a separate process — but a separate process is not a security boundary.
Note: a separate process is not a security boundary — it can still reach the network and read your files. Use docker or a cloud provider for untrusted code.
The network stays reachable and ~/.ssh stays readable under a subprocess. A real container (run_on="docker") is a real boundary, so it does not trigger this note. See Sandbox for the same warning in depth.

Configuration Options

This page adds no new knobs — where things run comes from sandbox=, run_on=, and backend=, documented on the sandbox pages below. The only new vocabulary is the field names the object returns: The field is thinks_on / tools_run_on, never loop — that word already means the workflow loop() primitive, asyncio’s event loop, and agent-loop jargon, so it was deliberately rejected.

Sandbox

Per-agent sandbox= and the explicit execute_code() API

Shared Sandbox

run_on= gives a whole flow one shared sandbox

Common Patterns

Check where things run before a paid run, log it at startup, or assert it in a test.

Best Practices

Under a subprocess the network is reachable and ~/.ssh is readable. Use docker or a cloud provider for untrusted code — the note appears precisely because that isolation is bypassable.
run_on= moves the tools out and shares one sandbox across steps. A hosted backend= moves the whole loop off this machine. The two shapes solve different problems — the repr tells them apart.
The string format is for humans. For the raw dict, call describe(obj) from praisonaiagents.agent.execution_location — it returns {thinks_on, tools_run_on, code_runs_on?} and never raises.

Sandbox

Per-agent sandbox=

Shared Sandbox

One shared sandbox with run_on=

Sandboxed Agent

Local loop, sandboxed tools

Self-Hosted Agent (Docker)

run_on="docker" — the whole loop self-hosted