# Google ADK (/docs/agents/google-adk)

<!-- agent-signals: reading_time_min: 8 · est_tokens: 3785 · updated: 2026-07-30 -->
Related: [Amp](/docs/agents/amp.md), [Claude Code](/docs/agents/claude-code.md), [Claude Managed Agents](/docs/agents/claude-managed-agents.md), [Codex](/docs/agents/codex.md), [Crabbox with E2B](/docs/agents/crabbox.md), [Devin](/docs/agents/devin.md)

[Google ADK](https://google.github.io/adk-docs/) (Agent Development Kit) is
Google's framework for building agents, with Gemini as the default model. The
[E2B](https://e2b.dev/) integration gives ADK workloads an isolated remote
workspace for running code and commands instead of executing them on your host.

## Choose an integration [#choose-an-integration]

<CardGroup cols="2">
  <Card title="Native ADK environment" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M21 13.6376V10.3624C21 8.71559 21 7.89217 20.6166 7.20744C20.2332 6.52271 19.5317 6.09334 18.1287 5.2346L15.1287 3.39836C13.6056 2.46612 12.8441 2 12 2C11.1559 2 10.3944 2.46612 8.8713 3.39836L5.8713 5.2346C4.46832 6.09334 3.76683 6.52271 3.38341 7.20744C3 7.89217 3 8.71559 3 10.3624V13.6376C3 15.2844 3 16.1078 3.38341 16.7926C3.76683 17.4773 4.46832 17.9067 5.8713 18.7654L8.8713 20.6016C10.3944 21.5339 11.1559 22 12 22C12.8441 22 13.6056 21.5339 15.1287 20.6016L18.1287 18.7654C19.5317 17.9067 20.2332 17.4773 20.6166 16.7926C21 16.1078 21 15.2844 21 13.6376Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M3.5 7L12 12L20.5 7&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M12 12V22&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="#native-google-adk-environment">
    Use Google's built-in E2B environment for direct shell and file operations
  </Card>

  <Card title="Advanced E2B plugin" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M15.5 2V6M8.5 6V2&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M6.00446 7.61331C5.93719 6.74273 6.63957 6 7.53014 6H16.4699C17.3604 6 18.0628 6.74273 17.9955 7.61331L17.8117 9.99197C17.6796 11.7019 17.1011 13.3498 16.132 14.7773L15.5312 15.6622C14.9638 16.4979 14.0077 17 12.9838 17H11.0162C9.99228 17 9.03617 16.4979 8.46881 15.6622L7.86803 14.7773C6.89885 13.3498 6.32041 11.7019 6.18827 9.99197L6.00446 7.61331Z&#x22; stroke=&#x22;currentColor&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M12 17V22&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M11 9H13&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="#advanced-e2b-plugin">
    Give an ADK agent ready-made code, command, file, and background-process tools
  </Card>
</CardGroup>

Choose the **native environment** when your application directly controls the
sandbox. Choose the **advanced plugin** when the agent itself should decide when
to run code, manage files, or start a service.

## Native: Google ADK environment [#native-google-adk-environment]

Google ADK includes the experimental
[`E2BEnvironment`](https://github.com/google/adk-python/tree/main/src/google/adk/integrations/e2b)
for direct command execution and file access through ADK's environment API. No
additional integration package is required.

```bash
pip install "google-adk[e2b]>=2.3.0"
```

Create and close the environment explicitly in your application:

```python
import asyncio

from google.adk.integrations.e2b import E2BEnvironment


async def main() -> None:
    env = E2BEnvironment()
    await env.initialize()
    try:
        await env.write_file("hello.py", 'print("Hello from E2B")\n')
        result = await env.execute("python hello.py")
        print(result.stdout)
    finally:
        await env.close()


asyncio.run(main())
```

This path exposes the sandbox as a low-level workspace: your application calls
`execute`, `read_file`, and `write_file` itself.

## Advanced: E2B plugin [#advanced-e2b-plugin]

The [`e2b-adk`](https://pypi.org/project/e2b-adk/) plugin exposes sandbox
operations as tools the model can call. It adds stateful code execution, shell
commands, file management, and background processes backed by the
[E2B Code Interpreter](/docs). The plugin creates one sandbox lazily, shares it
across tool calls, and closes it with the ADK runner.

To use E2B with ADK:

1. Create an `E2BPlugin`.
2. Hand `plugin.get_tools()` to your `Agent` and register the plugin on the `App`.
3. Run the agent — every tool call executes inside the sandbox, and the plugin
   creates and tears the sandbox down for you.

### Install the dependencies [#install-the-dependencies]

Install the plugin. It pulls in Google ADK and the E2B Code Interpreter SDK.

```bash
pip install e2b-adk
```

You need an E2B API key for the sandbox and a Gemini key for the model.

```bash
export E2B_API_KEY="..."
export GOOGLE_API_KEY="..."
```

## Example: Data analysis agent [#example-data-analysis-agent]

A good fit for a sandbox is analysis the model shouldn't do in its head. Here the
agent is given a raw dataset and a question. Rather than eyeballing the numbers,
it writes the data to a file, runs real pandas against it, and reports figures it
actually computed — the sandbox is a calculator it can't fool.

### Create the plugin and agent [#create-the-plugin-and-agent]

The plugin owns the sandbox. Pass its tools to the `Agent` and register it on the
`App`; the instruction is what makes the agent *run* code rather than guess.

```python
from google.adk.agents import Agent
from google.adk.apps import App

from e2b_adk import E2BPlugin

INSTRUCTION = """You are a data analyst. You never guess numbers — you compute
them. Save any data you are given to a file with write_file, analyse it by
running real pandas with run_code, fix and re-run if the code errors, and report
the figures you computed. Never report a number you have not verified by running
code."""

plugin = E2BPlugin()
agent = Agent(
    model="gemini-2.5-flash",
    name="data_analyst",
    instruction=INSTRUCTION,
    tools=plugin.get_tools(),
)
app = App(name="data_analysis", root_agent=agent, plugins=[plugin])
```

### Run the analysis [#run-the-analysis]

Run the agent inside an `InMemoryRunner`. The sandbox is created lazily on the
first tool call, kept alive while the agent works, and killed when the
`async with` block exits — you never manage it yourself.

```python
from google.adk.runners import InMemoryRunner

DATASET = """month,region,marketing_spend,revenue
2024-01,North,12000,48000
2024-02,North,15000,61000
2024-03,North,9000,37000
2024-04,North,18000,72000
2024-01,South,8000,26000
2024-02,South,11000,30000
2024-03,South,14000,33000
2024-04,South,17000,38000"""

async with InMemoryRunner(app=app) as runner:
    # run_debug prints the conversation as it runs.
    await runner.run_debug(
        f"Here is marketing spend and revenue as CSV:\n\n{DATASET}\n\n"
        "Save it to sales.csv, then tell me which region converts spend into "
        "revenue more efficiently and which month performed best."
    )
```

The agent writes `sales.csv` with `write_file`, then uses `run_code` to load it
with pandas, compute revenue-per-dollar and per-month totals, and answer in
prose — every number backed by an execution in the sandbox:

```text
data_analyst > North converts marketing spend into revenue more efficiently —
about $4.0 of revenue per $1 of spend versus roughly $2.5 for South. The best
single month was 2024-04 in North: $72,000 revenue from $18,000 spend.
```

Pass `verbose=True` to `run_debug` to also print each tool call and its result
as the agent works.

### Full example [#full-example]

```python expandable
import asyncio

from google.adk.agents import Agent
from google.adk.apps import App
from google.adk.runners import InMemoryRunner

from e2b_adk import E2BPlugin

INSTRUCTION = """You are a data analyst. You never guess numbers — you compute
them. Save any data you are given to a file with write_file, analyse it by
running real pandas with run_code, fix and re-run if the code errors, and report
the figures you computed. Never report a number you have not verified by running
code."""

DATASET = """month,region,marketing_spend,revenue
2024-01,North,12000,48000
2024-02,North,15000,61000
2024-03,North,9000,37000
2024-04,North,18000,72000
2024-01,South,8000,26000
2024-02,South,11000,30000
2024-03,South,14000,33000
2024-04,South,17000,38000"""


async def main() -> None:
    plugin = E2BPlugin(metadata={"example": "data-analysis"})
    agent = Agent(
        model="gemini-2.5-flash",
        name="data_analyst",
        instruction=INSTRUCTION,
        tools=plugin.get_tools(),
    )
    app = App(name="data_analysis", root_agent=agent, plugins=[plugin])

    async with InMemoryRunner(app=app) as runner:
        # run_debug prints the conversation as it runs.
        await runner.run_debug(
            f"Here is marketing spend and revenue as CSV:\n\n{DATASET}\n\n"
            "Save it to sales.csv, then tell me which region converts spend "
            "into revenue more efficiently and which month performed best."
        )


asyncio.run(main())
```

## Example: Code generation agent [#example-code-generation-agent]

The same tools support a code generator that verifies its own work. The
instruction tells the agent to execute every snippet in the sandbox before
returning it, so what you get back has already run and passed its tests — no
untested code reaches the user.

```python expandable
import asyncio

from google.adk.agents import Agent
from google.adk.apps import App
from google.adk.runners import InMemoryRunner

from e2b_adk import E2BPlugin

INSTRUCTION = """You are a code generator that returns verified, working code.
For every request: (1) write the function, (2) write tests, (3) EXECUTE in the
sandbox with run_code, (4) if it fails, fix and re-run until tests pass,
(5) return ONLY the final function. Never return code you haven't executed."""


async def main() -> None:
    plugin = E2BPlugin(metadata={"example": "code-generator"})
    agent = Agent(
        model="gemini-2.5-flash",
        name="codegen",
        instruction=INSTRUCTION,
        tools=plugin.get_tools(),
    )
    app = App(name="codegen", root_agent=agent, plugins=[plugin])

    async with InMemoryRunner(app=app) as runner:
        # run_debug prints the conversation as it runs.
        await runner.run_debug(
            "Write a Python function group_by(items, key) that groups a list "
            "by a key function."
        )


asyncio.run(main())
```

## Tools [#tools]

`plugin.get_tools()` returns six tools, all sharing the plugin's single sandbox
so state persists across calls. Each returns a dict with a `success` flag and
reports failures in the result rather than raising, so a bad call never aborts
the agent run. `success` means the tool *ran*: code that raised or a command
that exited non-zero still returns `success: True` with the failure captured in
`error` / `exit_code` — only a call that could not run at all returns
`success: False`.

| Tool                       | Does                                                                  |
| -------------------------- | --------------------------------------------------------------------- |
| `run_code`                 | Run code in a stateful kernel (variables persist across calls)        |
| `run_command`              | Run a shell command                                                   |
| `write_file` / `read_file` | Write and read files in the sandbox                                   |
| `list_files`               | List a directory                                                      |
| `start_background_command` | Start a long-running process, with an optional preview URL for a port |

## Configuration [#configuration]

`E2BPlugin` accepts keyword-only options, all optional. Anything you don't set
falls back to the E2B SDK's own default — the plugin overrides none of them.

```python
plugin = E2BPlugin(
    api_key=None,    # defaults to the E2B_API_KEY env var
    template=None,   # E2B sandbox template
    metadata=None,   # dict[str, str] attached to the sandbox
    envs=None,       # environment variables inside the sandbox
    timeout=None,    # sandbox timeout in seconds (re-applied on every tool call)
    lifecycle=None,  # what happens on timeout — see below
    # ...every other AsyncSandbox.create() option is forwarded verbatim
)
```

The plugin keeps the sandbox alive while the agent is working: every tool call
pushes the expiry window forward by `timeout` (E2B's default is 300s). An idle
gap longer than `timeout` still expires the sandbox under E2B's default
lifecycle — pass
`lifecycle={"on_timeout": {"action": "pause"}, "auto_resume": True}` to pause
and auto-resume across idle gaps instead. See the
[repository README](https://github.com/e2b-dev/e2b-adk-plugin#configuration)
for the full option list.

## Reference examples [#reference-examples]

Complete, runnable scripts live in the plugin repository.

<CardGroup cols="2">
  <Card title="Data analysis agent" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M7 15.2461L9.87381 11.5319C10.1242 11.2082 10.2495 11.0464 10.3862 10.9354C10.7975 10.6017 11.3471 10.5135 11.8368 10.7026C11.9997 10.7654 12.1664 10.8804 12.5 11.1103C12.8336 11.3402 13.0003 11.4552 13.1632 11.518C13.6529 11.7071 14.2025 11.6189 14.6138 11.2852C14.7505 11.1742 14.8757 11.0124 15.1262 10.6887L15.9061 9.68068C16.8833 8.41772 17.3719 7.78624 18.0414 7.7479C18.7109 7.70956 19.264 8.28139 20.3701 9.42505L21 10.0764&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M21 21H10C6.70017 21 5.05025 21 4.02513 19.9749C3 18.9497 3 17.2998 3 14V3&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="https://github.com/e2b-dev/e2b-adk-plugin/blob/main/examples/data_analysis.py">
    Compute real answers from a dataset with pandas in the sandbox
  </Card>

  <Card title="Code generator" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M16 6.99998L19.0664 9.64296C20.3554 10.7541 21 11.3096 21 12C21 12.6903 20.3555 13.2459 19.0664 14.357L16 17&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M8 6.99998L4.93365 9.64296C3.64455 10.7541 3 11.3096 3 12C3 12.6903 3.64455 13.2459 4.93365 14.357L8 17&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="https://github.com/e2b-dev/e2b-adk-plugin/blob/main/examples/code_generator.py">
    Return only code that has been executed and tested
  </Card>
</CardGroup>
