Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
125bbf2
example tool
drogovozDP May 12, 2026
9fb39eb
update exec and add python example
drogovozDP May 13, 2026
07dd6e4
update
drogovozDP May 14, 2026
468f48e
add FileTool
drogovozDP May 14, 2026
f54f7bb
update tools
drogovozDP May 18, 2026
eff667e
update readme
drogovozDP May 18, 2026
02070aa
update file_tool
drogovozDP May 26, 2026
925a4bd
add sandbox_claim attribute
drogovozDP May 26, 2026
7e447be
export K8sBaseTool
drogovozDP May 26, 2026
c809ed1
fix K8sExecTool
drogovozDP May 26, 2026
d77b976
add tests
drogovozDP Jun 2, 2026
d2f7386
add test for base tool
drogovozDP Jun 2, 2026
5fdf6a8
update base tool
drogovozDP Jun 9, 2026
3c502f7
refactor tools, add lifecycle manager
ArthurKamalov Jun 17, 2026
e68a0cd
reformat
ArthurKamalov Jun 25, 2026
cbf51ee
update readme, small fixes
ArthurKamalov Jul 8, 2026
2a8cfe2
remove append instruction
ArthurKamalov Jul 13, 2026
c31b305
run python tools codein tmp file
ArthurKamalov Jul 13, 2026
a5faa4e
Add timings note in the Ephemeral mode readme
ArthurKamalov Jul 13, 2026
eff8ebd
check path of file tool delete action
ArthurKamalov Jul 13, 2026
3e7c1fa
remove info action from file tool
ArthurKamalov Jul 13, 2026
a7d63e4
replace tool dict output with pydantic models. Typo fixes
ArthurKamalov Jul 13, 2026
1d33af4
Add note about syncronization lock in readme
ArthurKamalov Jul 13, 2026
5f3a30a
remove info action literal
ArthurKamalov Jul 20, 2026
8c7e9fe
add additional checks for path
ArthurKamalov Jul 20, 2026
163d070
add lazy import
ArthurKamalov Jul 20, 2026
b2faeed
make apend use tmp file
ArthurKamalov Jul 20, 2026
6f7f8a7
fix tools readme and descriptions
ArthurKamalov Jul 20, 2026
db14cdc
use uuid instead of timestapm for tmp files
ArthurKamalov Jul 20, 2026
89fcd5e
Fix schema class name case
ArthurKamalov Jul 20, 2026
858dd1f
Set sadnbox acquired to False on release
ArthurKamalov Jul 20, 2026
dcd816e
fix timeout tracker
ArthurKamalov Jul 20, 2026
5b747ab
fix README
ArthurKamalov Jul 20, 2026
b47eb97
fix file append action
ArthurKamalov Jul 23, 2026
3786406
add timeout on close
ArthurKamalov Jul 23, 2026
546587b
remove commented code from README
ArthurKamalov Jul 23, 2026
5561039
remove tmp file for python tool
ArthurKamalov Jul 23, 2026
41ecd4d
delete metadata info action from description
ArthurKamalov Jul 23, 2026
972b757
fix tmp file extension
ArthurKamalov Jul 23, 2026
d407003
fix release sandbox
ArthurKamalov Jul 27, 2026
da3c91d
fix acquire sandbox
ArthurKamalov Jul 27, 2026
406c9f4
update uv.lock
ArthurKamalov Jul 28, 2026
d787fd1
reformat
ArthurKamalov Jul 28, 2026
a1e741f
fix lint errors, return back py.typed
ArthurKamalov Jul 28, 2026
90a2358
reformat
ArthurKamalov Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/crewai-tools/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ e2b = [
"e2b-code-interpreter~=2.6.0",
]

k8s_agent_sandbox = [
"k8s-agent-sandbox~=0.5.0",
]
Comment on lines +151 to +153

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether the k8s_agent_sandbox extra is wired into test/dev dependency groups.
rg -n -A5 'k8s_agent_sandbox' lib/crewai-tools/pyproject.toml
rg -n -B2 -A10 '\[dependency-groups\]|\[tool\.uv\]|extra ==' lib/crewai-tools/pyproject.toml

Repository: crewAIInc/crewAI

Length of output: 487


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pyproject relevant sections =="
sed -n '1,220p' lib/crewai-tools/pyproject.toml | nl -ba | sed -n '130,220p'

echo
echo "== candidate test files importing k8s_agent_sandbox =="
rg -n "k8s_agent_sandbox|k8s-agent-sandbox|SandboxNotFoundError" lib/crewai-tools/src lib/crewai-tools/tests lib/crewai-tools -g '*.py' | head -200 || true

echo
echo "== dependency groups / pytest uv scripts =="
rg -n "dependency-groups|pytest|k8s" lib/crewai-tools/pyproject.toml -C 3 || true

Repository: crewAIInc/crewAI

Length of output: 228


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pyproject relevant sections =="
python3 - <<'PY'
from pathlib import Path
p = Path("lib/crewai-tools/pyproject.toml")
lines = p.read_text().splitlines()
for i in range(130, min(220, len(lines))+1):
    print(f"{i:4}: {lines[i-1]}")
PY

echo
echo "== candidate test files importing k8s_agent_sandbox =="
rg -n "k8s_agent_sandbox|k8s-agent-sandbox|SandboxNotFoundError" lib/crewai-tools/src lib/crewai-tools/tests lib/crewai-tools -g '*.py' | head -200 || true

echo
echo "== dependency groups / pytest uv scripts =="
rg -n "dependency-groups|pytest|k8s" lib/crewai-tools/pyproject.toml -C 3 || true

Repository: crewAIInc/crewAI

Length of output: 14424


Wire k8s_agent_sandbox into the test environment.

The package extra is only defined, so these new K8s tool tests that directly import k8s_agent_sandbox can fail with ModuleNotFoundError when installed without k8s_agent_sandbox. Add the extra to the test/dev dependency group and/or use lazy imports like the production tools.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai-tools/pyproject.toml` around lines 151 - 153, Update the test/dev
dependency configuration in pyproject.toml to include the existing
k8s_agent_sandbox extra, ensuring tests that import k8s_agent_sandbox have the
package installed in the test environment; alternatively, convert the affected
test imports to lazy imports consistent with the production tools.


[tool.uv]
exclude-newer = "3 days"
Expand Down
16 changes: 16 additions & 0 deletions lib/crewai-tools/src/crewai_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@
YoutubeVideoSearchTool,
)
from crewai_tools.tools.zapier_action_tool.zapier_action_tool import ZapierActionTools
from crewai_tools.tools.k8s_agent_sandbox import (
K8sAgentSandboxToolClientSettings,
K8sAgentSandboxToolSandboxSettings,
K8sAgentSandboxToolset,
K8sAgentSandboxBaseTool,
K8sAgentSandboxExecTool,
K8sAgentSandboxPythonTool,
K8sAgentSandboxFileTool,
)


__all__ = [
Expand Down Expand Up @@ -272,6 +281,13 @@
"InvokeCrewAIAutomationTool",
"JSONSearchTool",
"JinaScrapeWebsiteTool",
"K8sAgentSandboxToolClientSettings",
"K8sAgentSandboxToolSandboxSettings",
"K8sAgentSandboxToolset",
"K8sAgentSandboxBaseTool",
"K8sAgentSandboxExecTool",
"K8sAgentSandboxFileTool",
"K8sAgentSandboxPythonTool",
"LinkupSearchTool",
"LlamaIndexTool",
"MCPServerAdapter",
Expand Down
16 changes: 16 additions & 0 deletions lib/crewai-tools/src/crewai_tools/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@
YoutubeVideoSearchTool,
)
from crewai_tools.tools.zapier_action_tool.zapier_action_tool import ZapierActionTools
from crewai_tools.tools.k8s_agent_sandbox import (
K8sAgentSandboxToolClientSettings,
K8sAgentSandboxToolSandboxSettings,
K8sAgentSandboxToolset,
K8sAgentSandboxBaseTool,
K8sAgentSandboxExecTool,
K8sAgentSandboxPythonTool,
K8sAgentSandboxFileTool,
)


__all__ = [
Expand Down Expand Up @@ -256,6 +265,13 @@
"InvokeCrewAIAutomationTool",
"JSONSearchTool",
"JinaScrapeWebsiteTool",
"K8sAgentSandboxToolClientSettings",
"K8sAgentSandboxToolSandboxSettings",
"K8sAgentSandboxToolset",
"K8sAgentSandboxBaseTool",
"K8sAgentSandboxExecTool",
"K8sAgentSandboxFileTool",
"K8sAgentSandboxPythonTool",
"LinkupSearchTool",
"LlamaIndexTool",
"MDXSearchTool",
Expand Down
262 changes: 262 additions & 0 deletions lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
# K8s Agent Sandbox Tools

Run shell commands, execute Python, and manage files inside a [Kubernetes Agent Sandbox](https://github.com/kubernetes-sigs/agent-sandbox). K8s Agent Sandbox enables easy management of isolated, stateful, singleton workloads, ideal for use cases like AI agent runtimes.

Three tools are provided so you can pick what the agent actually needs:

- **`K8sAgentSandboxExecTool`** — run a shell command.
- **`K8sAgentSandboxFileTool`** — read / write / list / delete files.
- **`K8sAgentSandboxPythonTool`** — run Python code.

## Installation

```shell
uv add "crewai-tools[k8s_agent_sandbox]"
# or
pip install "crewai-tools[k8s_agent_sandbox]"
```

## Sandbox toolset

Instead of configuring sandbox-related settings for each of the tools separately, the `K8sAgentSandboxToolset` class must be used.

All tools that are meant to share the same sandbox settings and sandbox lifecycle have to be added to the same instance of the
`K8sAgentSandboxToolset` class.

### Toolset example

This example expects that you have a cluster with the Agent Sandbox installed and all remaining prerequisites like sandbox router, sandbox template and a sandbox warmpool deployed. Learn more [here](https://github.com/kubernetes-sigs/agent-sandbox/tree/main#installation).

```python
from crewai_tools import (
K8sAgentSandboxToolSandboxSettings as SandboxSettings,
K8sAgentSandboxToolset,
K8sAgentSandboxExecTool,
K8sAgentSandboxFileTool,
)

toolset = K8sAgentSandboxToolset.create(
# Sandbox settings for all tools in this toolset.
sandbox_settings=SandboxSettings(
warmpool="my-warmpool",
namespace="my-namespace",
),
)

# Adding the tools to the toolset.
exec_tool = K8sAgentSandboxExecTool(toolset=toolset)
file_tool = K8sAgentSandboxFileTool(toolset=toolset)
```

### Lifecycle modes

The `K8sAgentSandboxToolset` supports three sandbox lifecycle modes and they can be set on creation of the toolset instance
with the `K8sAgentSandboxToolset.create` factory method:

| Mode | When the sandbox is created | When it is killed |
| --- | --- | --- |
| **Ephemeral** (default, `persistent=False`) | On every `_run` call of the tool | At the end of that same call |
| **Persistent** (`persistent=True`) | Lazily on first use | At process exit (via `atexit`), or manually via `toolset.close()` |
| **Attach** (`claim_name="…"`) | Never — the tool attaches to an existing sandbox | Never — the tool will not kill a sandbox it did not create |

Ephemeral mode is the safe default: nothing leaks if the agent forgets to clean up, but since it has to create a new sandbox on each new run, the increased execution time is expected. Use persistent mode when you want filesystem state or installed packages to carry across steps.

K8s agent sandboxes also auto-expire via an absolute TTL from creation. Tune it via `sandbox_timeout` (seconds, default `300`).

All tool operations to a sandbox are synchronized with a lock to prevent races between different tools.

### Sandbox client settings

By default the `K8sAgentSandboxToolset.create` creates a client in the "Local Tunnel" configuration. To specify another configurations,
the `client_settings` keyword argument has to be used.

The following example shows setting up the sandbox client to use the "Gateway" configuration (learn more about all configurations [here](https://github.com/kubernetes-sigs/agent-sandbox/tree/main/clients/python/agentic-sandbox-client#usage-examples)):

```python
from crewai_tools import (
K8sAgentSandboxToolClientSettings as ClientSettings, # <- import this.
K8sAgentSandboxToolSandboxSettings as SandboxSettings,
K8sAgentSandboxToolset,
K8sAgentSandboxExecTool,
K8sAgentSandboxFileTool,
)
from k8s_agent_sandbox.models import SandboxGatewayConnectionConfig


toolset = K8sAgentSandboxToolset.create(
sandbox_settings=SandboxSettings(
warmpool="my-warmpool",
namespace="my-namespace",
),
client_settings=ClientSettings(
connection_config=SandboxGatewayConnectionConfig(
gateway_name="external-http-gateway", # Name of the Gateway resource
)
)
)

```

## Examples

### Ephemeral sandboxes

```python
from crewai_tools import (
K8sAgentSandboxToolSandboxSettings as SandboxSettings,
K8sAgentSandboxToolset,
)
Comment on lines +105 to +108

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Import the tools used by each lifecycle example. Each snippet instantiates K8sAgentSandboxExecTool and K8sAgentSandboxFileTool without importing them.

  • lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md#L105-L108: import K8sAgentSandboxExecTool and K8sAgentSandboxFileTool.
  • lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md#L124-L127: import K8sAgentSandboxExecTool and K8sAgentSandboxFileTool.
  • lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md#L144-L147: import K8sAgentSandboxExecTool and K8sAgentSandboxFileTool.
📍 Affects 1 file
  • lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md#L105-L108 (this comment)
  • lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md#L124-L127
  • lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md#L144-L147
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md` around
lines 105 - 108, Update each lifecycle example import block in
lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md at lines
105-108, 124-127, and 144-147 to import K8sAgentSandboxExecTool and
K8sAgentSandboxFileTool alongside the existing K8sAgentSandboxToolset and
SandboxSettings imports, so every snippet can instantiate the tools it uses.


toolset = K8sAgentSandboxToolset.create(
sandbox_settings=SandboxSettings(
warmpool="my-warmpool",
namespace="my-namespace",
),
)

exec_tool = K8sAgentSandboxExecTool(toolset=toolset)
file_tool = K8sAgentSandboxFileTool(toolset=toolset)
```

### Persistent sandboxes

```python
from crewai_tools import (
K8sAgentSandboxToolSandboxSettings as SandboxSettings,
K8sAgentSandboxToolset,
)

toolset = K8sAgentSandboxToolset.create(
sandbox_settings=SandboxSettings(
warmpool="my-warmpool",
namespace="my-namespace",
),
persistent=True # <-- Add this.
)

exec_tool = K8sAgentSandboxExecTool(toolset=toolset)
file_tool = K8sAgentSandboxFileTool(toolset=toolset)
```

### Attach to an existing sandbox

```python
from crewai_tools import (
K8sAgentSandboxToolSandboxSettings as SandboxSettings,
K8sAgentSandboxToolset,
)

toolset = K8sAgentSandboxToolset.create(
sandbox_settings=SandboxSettings(
warmpool="my-warmpool",
namespace="my-namespace",
),
claim_name="<claim_name>" # <-- Add this.
)

exec_tool = K8sAgentSandboxExecTool(toolset=toolset)
file_tool = K8sAgentSandboxFileTool(toolset=toolset)
```

## Tool arguments

### `K8sAgentSandboxExecTool`
- `command: str` — shell command to run.
- `timeout: float | None` — seconds.

### `K8sAgentSandboxFileTool`
- `action: "read" | "write" | "append" | "list" | "delete" | "mkdir" | "info" | "exists"`
- `path: str` — relative path inside the sandbox.
- `content: str | None` — required for `append`; optional for `write`.
- `binary: bool` — if `True`, `content` is base64 on write / returned as base64 on read.

### `K8sAgentSandboxPythonTool`
- `code: str` — source to execute.
- `timeout: float | None` — seconds.
Comment on lines +163 to +175

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Synchronize the argument reference with the schemas.

info is not a supported file action. Also, the execution and Python timeouts are int fields with a default of 60, not float | None; document the file tool timeout as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai-tools/src/crewai_tools/tools/k8s_agent_sandbox/README.md` around
lines 163 - 175, Update the K8sAgentSandboxFileTool action list to remove the
unsupported "info" value, and synchronize timeout documentation for
K8sAgentSandboxExecTool and K8sAgentSandboxPythonTool with the schemas as int
values defaulting to 60. Add the file tool’s timeout argument and document its
matching schema type and default.



## Security considerations

These tools hand the LLM arbitrary shell, Python, and filesystem access inside sandbox. The threat model to keep in mind:

- **Prompt-injection is a code-execution vector.** If the agent ingests untrusted content (web pages, scraped documents, user-supplied files, emails, search results), a malicious instruction hidden in that content can coerce the agent into issuing commands to `K8sAgentSandboxExecTool` / `K8sAgentSandboxPythonTool`. Treat any pipeline that feeds untrusted text into an agent that also has these tools as equivalent to remote code execution — the LLM is the attacker's shell.
- **Ephemeral mode (the default) is the main blast-radius control.** A fresh sandbox is created per call and killed at the end, so injected commands cannot persist state, exfiltrate long-lived secrets, or build up tooling across turns. Leave `persistent=False` unless you have a concrete reason to change it.
- **Avoid this specific combination:**
- untrusted content in the agent's context, **plus**
- `persistent=True` or an explicit long-lived `claim_name`, **plus**
- a large `sandbox_timeout`.


## Full Example

```python
import os
from crewai import Agent, Task, Crew, Process
from crewai_tools import (
K8sAgentSandboxToolSandboxSettings as SandboxSettings,
K8sAgentSandboxToolset,
K8sAgentSandboxPythonTool,
K8sAgentSandboxExecTool,
K8sAgentSandboxFileTool,
)

# Create your toolset
toolset = K8sAgentSandboxToolset.create(
sandbox_settings=SandboxSettings(
warmpool="your-warmpool",
namespace="default",
),
persistent=True,
)

# Instantiate your tools
exec_tool = K8sAgentSandboxExecTool(toolset=toolset)
file_tool = K8sAgentSandboxFileTool(toolset=toolset)
python_tool = K8sAgentSandboxPythonTool(toolset=toolset)

# Define the Agent
devops_agent = Agent(
role='Kubernetes DevOps Engineer',
goal='Execute commands in a secure sandbox to inspect the environment safely.',
backstory=(
"You are a senior DevOps engineer specializing in Kubernetes. "
"You use isolated pod sandboxes to run scripts, check system details, "
"and securely verify environments without risking the host system."
),
verbose=True,
allow_delegation=False,
tools=[exec_tool, file_tool, python_tool]
)

# Define the Task
inspect_task = Task(
description=(
"Use your K8s sandbox execution tool to find out what operating system "
"the sandbox pod is running. Run a command like 'cat /etc/os-release' "
"and summarize the results."
),
expected_output="A brief summary of the sandbox pod's operating system based on the command output.",
agent=devops_agent,
)

# Assemble the Crew
k8s_crew = Crew(
agents=[devops_agent],
tasks=[inspect_task],
process=Process.sequential
)

# Run the Crew
if __name__ == "__main__":
if not os.environ.get("OPENAI_API_KEY"):
print("WARNING: OPENAI_API_KEY environment variable is not set.")

print("Starting the CrewAI execution...")
result = k8s_crew.kickoff()

print("\n================================================")
print("FINAL RESULT FROM THE AGENT:")
print("================================================")
print(result)
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from crewai_tools.tools.k8s_agent_sandbox.settings import (
K8sAgentSandboxToolClientSettings,
K8sAgentSandboxToolSandboxSettings,
)
from crewai_tools.tools.k8s_agent_sandbox.toolset import K8sAgentSandboxToolset
from crewai_tools.tools.k8s_agent_sandbox.base_tool import K8sAgentSandboxBaseTool
from crewai_tools.tools.k8s_agent_sandbox.exec_tool import K8sAgentSandboxExecTool
from crewai_tools.tools.k8s_agent_sandbox.python_tool import K8sAgentSandboxPythonTool
from crewai_tools.tools.k8s_agent_sandbox.file_tool import K8sAgentSandboxFileTool


__all__ = [
"K8sAgentSandboxToolClientSettings",
"K8sAgentSandboxToolSandboxSettings",
"K8sAgentSandboxToolset",
"K8sAgentSandboxBaseTool",
"K8sAgentSandboxExecTool",
"K8sAgentSandboxPythonTool",
"K8sAgentSandboxFileTool",
]
Loading