---
title: "Run Google ADK agents in a Promigence sandbox"
description: "Point a Google ADK agent's environment tools or code executor at a Promigence sandbox, so its commands and code run there."
url: "https://www.promigence.ai/docs/guides/google-adk"
site: "Promigence"
---

# Run Google ADK agents in a Promigence sandbox

Point a Google ADK agent's environment tools or code executor at a Promigence sandbox, so its commands and code run there.

Google ADK runs an agent's work in two places: environment tools that execute commands and edit
files, and a code executor that runs the code blocks a model writes. The `promigence-google-adk`
package covers both. `PromigenceEnvironment` backs `EnvironmentToolset`, and `PromigenceCodeExecutor`
backs `LlmAgent(code_executor=...)`. Either way the work happens in a Promigence sandbox instead of on
the machine serving the agent.

## What you need

- A Promigence API key in `PROMIGENCE_API_KEY`.
- Python 3.10 or newer.
- `google-adk` 2.9.1. `BaseEnvironment` is marked experimental upstream, so the package pins
  `>=2.9,<3`.

## Install

```bash
pip install promigence-google-adk
export PROMIGENCE_API_KEY=prom_api_...
export PROMIGENCE_SPEND_CAP=5
```

## Environment tools

```python
from google.adk.agents import LlmAgent
from google.adk.tools.environment import EnvironmentToolset
from promigence_google_adk import PromigenceEnvironment

agent = LlmAgent(
    name="coder",
    model="gemini-2.5-pro",
    tools=[EnvironmentToolset(environment=PromigenceEnvironment(image="python:3.12-slim", spend_cap=1))],
)
```

The toolset hands the model Execute, ReadFile, EditFile and WriteFile tools, all acting on the
sandbox. `EnvironmentToolset` initializes the environment before it hands out the tools and closes
it when the toolset closes, so the sandbox lives exactly as long as the toolset. To manage it by
hand, use `async with PromigenceEnvironment(...) as env:`.

## Code executor

```python
from google.adk.agents import LlmAgent
from promigence_google_adk import PromigenceCodeExecutor

executor = PromigenceCodeExecutor(image="python:3.12-slim", spend_cap=1)
agent = LlmAgent(name="analyst", model="gemini-2.5-pro", code_executor=executor)
# ... run the agent ...
executor.close()
```

Each code block is written to a file in the sandbox and run with `python3` (change it with
`interpreter`). Input files from ADK are written into the working directory first.

Both classes take the environment the same way: pass exactly one of `image` or `snapshot`. The first
time you name an image, Promigence pins its tag to a digest, builds a snapshot from it and checks it,
and later sandboxes reuse that snapshot: a saved, verified environment that each sandbox starts as a
fresh copy of. That build is billed per second while it runs, whether it verifies or not, up to $0.17
at the default small size ([quickstart](https://www.promigence.ai/docs/quickstart)), and the sandboxes that reuse the snapshot
pay no further build charge. Both also take `tier`, `working_dir`, `env_vars`,
`allow_internet_access=False` and `registry_secret` for a private image. `user` and the snapshot
inputs `setup`, `verify` and `start` belong to `PromigenceEnvironment` only; the code executor
ignores them. Only the code executor takes `interpreter`.

## How sandboxes map to ADK

An environment is one sandbox. The code executor is stateful, with one sandbox per ADK session: a
session's blocks see each other's files and installed packages, and two sessions never share one. One
app process can serve many users without one user's code seeing another's files. The executor keeps
the sandbox id in session state, so a restarted process reconnects to the running sandbox instead of
starting another.

## Setting a spend cap

`spend_cap` is the most one sandbox may spend, in US dollars. It falls back to
`PROMIGENCE_SPEND_CAP`, then to your organization's default; with none of them, the adapter raises a
configuration error before anything starts. `sandbox_timeout_sec` (3600 by default) bounds each
sandbox's lifetime.

## Cleaning up

The toolset closes its environment for you. The code executor has no shutdown hook in ADK, so call
`executor.close()` yourself or use it as a context manager. It ends every session's sandbox. Each one
also ends on its own when `sandbox_timeout_sec` runs out.

A command that exits non-zero comes back as an `ExecutionResult` with its exit code, the way ADK
expects. A failure on the Promigence side raises `PromigenceAdapterError` with
`failure_class == "env"`, so it never looks like the agent's command failed.

## What is not supported yet

- Streaming output. A command's output arrives when it finishes.
- `output_files` from the code executor. It is always empty; read generated files with `read_file`.
- The code executor cannot tell a timeout from a kill. `PromigenceEnvironment.execute` can.
- The image needs `/bin/sh`, plus the interpreter you name for the code executor.

## Next

Read [the agent briefing](https://www.promigence.ai/agents) for what a sandbox gives an agent, or start with
[the quickstart](https://www.promigence.ai/docs/quickstart).

