Skip to content

feat(tools): add OpenSandbox sandbox tool#5756

Open
iris-clawd wants to merge 4 commits into
mainfrom
feat/open-sandbox-tool
Open

feat(tools): add OpenSandbox sandbox tool#5756
iris-clawd wants to merge 4 commits into
mainfrom
feat/open-sandbox-tool

Conversation

@iris-clawd
Copy link
Copy Markdown
Contributor

@iris-clawd iris-clawd commented May 8, 2026

Summary

Adds OpenSandboxExecTool and OpenSandboxFileTool to crewai-tools, following the exact same pattern as the Daytona sandbox tool.

What's new

  • crewai_tools.tools.open_sandbox_tool package with three classes:
    • OpenSandboxBaseTool — base class with lazy SDK import, ConnectionConfigSync client, SandboxSync lifecycle (create/connect/delete), atexit cleanup for persistent sandboxes, threading lock for thread safety
    • OpenSandboxExecTool — runs shell commands, returns {exit_code, result, artifacts}
    • OpenSandboxFileTool — read/write/append/list/delete/mkdir/info file actions

Optional dependency

opensandbox is declared as an optional dep in pyproject.toml:

[project.optional-dependencies]
opensandbox = ["opensandbox>=0.1.8"]

Install with: pip install crewai-tools[opensandbox]

The module is fully importable without opensandbox installed — the ImportError only fires when a tool method is actually called, matching the Daytona pattern.

Env vars

Var Purpose
OPEN_SANDBOX_API_KEY API key (optional depending on server config)
OPEN_SANDBOX_DOMAIN Server host:port (e.g. localhost:8080)

Pattern reference

Modelled directly on daytona_sandbox_tool — same base class structure, same _acquire_sandbox / _release_sandbox lifecycle, same lazy import guard, same persistent / sandbox_id / sandbox_timeout fields.

Testing

  • Import smoke test passes without opensandbox installed
  • ruff check + ruff format clean

Requested by: Lorenze Jay lorenze@crewai.com

Summary by CodeRabbit

  • New Features

    • Added OpenSandbox integration with three tools: sandbox lifecycle management, command execution inside sandboxes, and filesystem operations.
    • Filesystem tool supports read/write/append/list/delete/mkdir/info, binary/text handling, recursion, modes, and metadata.
  • Chores

    • Added optional opensandbox dependency to enable sandbox features.

Review Change Stack

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4072bcf9-4c39-41a2-8078-7bc43b091689

📥 Commits

Reviewing files that changed from the base of the PR and between 812468e and ff2fd74.

📒 Files selected for processing (3)
  • lib/crewai-tools/pyproject.toml
  • lib/crewai-tools/src/crewai_tools/__init__.py
  • lib/crewai-tools/tool.specs.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai-tools/pyproject.toml

📝 Walkthrough

Walkthrough

Adds an optional opensandbox dependency and three new OpenSandbox-backed tools: OpenSandboxBaseTool (SDK lifecycle/connection), OpenSandboxExecTool (run shell commands), and OpenSandboxFileTool (filesystem actions). Updates tool specs JSON and exposes the tools via package-level all across module hierarchy.

Changes

OpenSandbox Tool Integration

Layer / File(s) Summary
Dependencies
lib/crewai-tools/pyproject.toml
Adds opensandbox>=0.1.8 as an optional dependency group.
Base Tool & SDK Integration
lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_base_tool.py
OpenSandboxBaseTool with lazy SDK import, connection config caching, and three sandbox lifecycle modes: ephemeral, persistent (cached + atexit cleanup), and external (attach by sandbox_id). Includes thread-safe cleanup and timedelta utility.
Command Execution Tool
lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_exec_tool.py
OpenSandboxExecTool executes shell commands with optional cwd, env, and timeout; returns exit code, combined output, and structured artifacts; always releases sandbox in finally.
Filesystem Operations Tool
lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_file_tool.py
OpenSandboxFileTool dispatches read/write/append/list/delete/mkdir/info actions; handles binary via base64, ensures parent directories, appends safely, and normalizes metadata (ISO datetimes).
Tool Specs JSON
lib/crewai-tools/tool.specs.json
Adds OpenSandboxBaseTool, OpenSandboxExecTool, and OpenSandboxFileTool spec entries with init_params_schema and run parameter schemas; declares env vars and opensandbox dependency.
Package Exports
lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/__init__.py, lib/crewai-tools/src/crewai_tools/tools/__init__.py, lib/crewai-tools/src/crewai_tools/__init__.py
Re-exports the three OpenSandbox tool classes in module __all__ at subpackage, tools package, and root package levels.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • greysonlalonde

Poem

🐰 In sandbox meadows code will play,
Base, Exec, and File hop along the way,
Commands and files they now can tend,
Clean exits, safe writes, and paths that mend,
A rabbit cheers: new tools at hand — hooray!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding OpenSandbox sandbox tool to the crewai-tools package with three new tool classes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/open-sandbox-tool

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_file_tool.py (2)

146-162: 💤 Low value

Append is non-atomic (read-modify-write).

The append operation reads the entire file, concatenates, and writes back. For large files this is memory-intensive, and concurrent appends could race. This is acceptable for the documented use case (chunked file uploads), but worth noting in the docstring.

🤖 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/open_sandbox_tool/open_sandbox_file_tool.py`
around lines 146 - 162, The _append method performs a read-modify-write
(sandbox.files.read_bytes -> concat -> sandbox.files.write_file) which is
non-atomic and can be memory-intensive or race-prone for large files or
concurrent appends; update the method's docstring (near _append in
open_sandbox_file_tool.py) to explicitly state this limitation and recommend its
intended usage (chunked uploads) and/or mention that callers should handle
concurrency or use a more atomic mechanism if needed, referencing
_ensure_parent_dir, sandbox.files.read_bytes, and sandbox.files.write_file so
readers can locate the related operations.

4-4: 💤 Low value

Same unnecessary builtins import as in exec_tool.

See comment on open_sandbox_exec_tool.py — this import can be removed.

🤖 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/open_sandbox_tool/open_sandbox_file_tool.py`
at line 4, Remove the unnecessary import "from builtins import type as type_"
from open_sandbox_file_tool.py; if the module references the alias type_ (search
for "type_"), replace those uses with the built-in type or appropriate
isinstance/type calls (e.g., use type(...) or isinstance(..., type)) and delete
the import line entirely.
lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_exec_tool.py (1)

3-3: 💤 Low value

Unnecessary import from builtins.

from builtins import type as type_ is redundant — type is already a builtin available in all Python versions. For the type annotation on line 39, you can use type[BaseModel] directly (Python 3.9+).

♻️ Suggested simplification
-from builtins import type as type_

Then on line 39:

-    args_schema: type_[BaseModel] = OpenSandboxExecToolSchema
+    args_schema: type[BaseModel] = OpenSandboxExecToolSchema
🤖 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/open_sandbox_tool/open_sandbox_exec_tool.py`
at line 3, Remove the unnecessary import "from builtins import type as type_"
and update any usage of the alias type_ (e.g., the type annotation currently
written using type_) to the builtin typing form type[BaseModel] (or simply
type[YourModelClass]) as applicable—specifically replace the annotation that
uses type_ on the function/method where BaseModel is referenced with the native
Python 3.9+ generic builtin type and delete the imported symbol type_ from the
module.
🤖 Prompt for all review comments with 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.

Inline comments:
In
`@lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_file_tool.py`:
- Around line 55-58: The default Unix permission for the Pydantic Field named
mode is currently set as decimal 755; change the default to octal 0o755 and
update every usage that constructs or applies permissions from this field (e.g.,
the code path handling action="mkdir" and any os.chmod/os.makedirs or
permission-bit computations that consume mode) so they treat mode as an octal
permission integer; ensure the Field declaration remains mode: int =
Field(default=0o755, ...) and adjust any tests or comparisons that assumed
decimal 755 accordingly.

---

Nitpick comments:
In
`@lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_exec_tool.py`:
- Line 3: Remove the unnecessary import "from builtins import type as type_" and
update any usage of the alias type_ (e.g., the type annotation currently written
using type_) to the builtin typing form type[BaseModel] (or simply
type[YourModelClass]) as applicable—specifically replace the annotation that
uses type_ on the function/method where BaseModel is referenced with the native
Python 3.9+ generic builtin type and delete the imported symbol type_ from the
module.

In
`@lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_file_tool.py`:
- Around line 146-162: The _append method performs a read-modify-write
(sandbox.files.read_bytes -> concat -> sandbox.files.write_file) which is
non-atomic and can be memory-intensive or race-prone for large files or
concurrent appends; update the method's docstring (near _append in
open_sandbox_file_tool.py) to explicitly state this limitation and recommend its
intended usage (chunked uploads) and/or mention that callers should handle
concurrency or use a more atomic mechanism if needed, referencing
_ensure_parent_dir, sandbox.files.read_bytes, and sandbox.files.write_file so
readers can locate the related operations.
- Line 4: Remove the unnecessary import "from builtins import type as type_"
from open_sandbox_file_tool.py; if the module references the alias type_ (search
for "type_"), replace those uses with the built-in type or appropriate
isinstance/type calls (e.g., use type(...) or isinstance(..., type)) and delete
the import line entirely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 111d41e9-4ba2-49e0-a795-f8c9c1ff74bd

📥 Commits

Reviewing files that changed from the base of the PR and between e4a91cd and 9c981e1.

📒 Files selected for processing (7)
  • lib/crewai-tools/pyproject.toml
  • lib/crewai-tools/src/crewai_tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_base_tool.py
  • lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_exec_tool.py
  • lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/open_sandbox_file_tool.py

Comment on lines +55 to +58
mode: int = Field(
default=755,
description="For action='mkdir': Unix file mode as an integer (default 755).",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

opensandbox python SDK WriteEntry mode parameter documentation

💡 Result:

In the OpenSandbox Python SDK, WriteEntry.mode is the Unix file permission bits (octal integer). It’s passed as an integer like 644 or 755 when creating a WriteEntry for sandbox.files.write_files. [1][2] Documented usage (examples): - mode=644 creates a normal data file with rw-r--r-- permissions. [1] - mode=755 creates an executable script with rwxr-xr-x permissions. [1] - Common recommended values include 600 (rw-------) for sensitive files. [1] Permission meanings (octal): - 755 => rwxr-xr-x (owner read/write/execute; group/others read/execute) [3] - 644 => rw-r--r-- (owner read/write; group/others read only) [3] - 600 => rw------- (only owner read/write) [3] Therefore, WriteEntry.mode expects a numeric octal Unix mode/permission value (e.g., 644, 755, 600), and it controls the file’s permission bits inside the sandbox. [1][3]

Citations:


Fix Unix file mode to use octal notation.

mode: int = 755 is the decimal value 755, not octal. Unix file permissions should be specified in octal: 0o755 (octal) = 493 (decimal) = rwxr-xr-x permissions. The SDK interprets mode as octal Unix permission bits; passing 755 decimal would set permissions to 0o1363 instead of 0o755, resulting in incorrect file permissions.

Update the default value and all usages:

Suggested fixes
     mode: int = Field(
-        default=755,
+        default=0o755,
         description="For action='mkdir': Unix file mode as an integer (default 755).",
     )

And update line 96 and line 175:

-        mode: int = 755,
+        mode: int = 0o755,
-            sandbox.files.create_directories([sdk["WriteEntry"](path=parent, mode=755)])
+            sandbox.files.create_directories([sdk["WriteEntry"](path=parent, mode=0o755)])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mode: int = Field(
default=755,
description="For action='mkdir': Unix file mode as an integer (default 755).",
)
mode: int = Field(
default=0o755,
description="For action='mkdir': Unix file mode as an integer (default 755).",
)
🤖 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/open_sandbox_tool/open_sandbox_file_tool.py`
around lines 55 - 58, The default Unix permission for the Pydantic Field named
mode is currently set as decimal 755; change the default to octal 0o755 and
update every usage that constructs or applies permissions from this field (e.g.,
the code path handling action="mkdir" and any os.chmod/os.makedirs or
permission-bit computations that consume mode) so they treat mode as an octal
permission integer; ensure the Field declaration remains mode: int =
Field(default=0o755, ...) and adjust any tests or comparisons that assumed
decimal 755 accordingly.

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

4 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

5 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@lorenzejay lorenzejay self-assigned this May 11, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with 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.

Inline comments:
In `@lib/crewai-tools/tool.specs.json`:
- Around line 7429-7493: The schema currently makes path, paths, pattern,
replacement nullable and only requires action, so add JSON Schema conditional
validation blocks (if/then) keyed on the "action" property to enforce
action-specific required properties and types: e.g. add an if:
{properties:{action:{const:"move"}}} then: {required:["path","destination"],
properties:{path:{type:"string"}, destination:{type:"string"}}}; for "find"
require path and pattern (pattern as string); for "search" require path and
pattern (pattern as string); for "replace" require paths (array of strings) and
replacement (string) and pattern (string); for "delete" require path and
recursive (boolean optional) as needed; ensure each then block also tightens
types (no null) for the referenced properties and use else/elseif blocks for
other actions to reject missing/nullable fields so invalid payloads (e.g.
{"action":"move","path":"/tmp/a"} or {"action":"find"}) fail schema validation
up front.
- Around line 16636-16640: OpenSandboxFileTool's schema currently defines "mode"
as a decimal integer (default 755); change its schema to use type "string",
description "Octal permission string", and default null to match the
DaytonaFileTool pattern, and then update the Python implementation of
OpenSandboxFileTool where WriteEntry(mode=mode) is called to accept a string
mode (or null) and convert it to an int with base-8 (e.g., int(mode, 8)) before
passing to WriteEntry, handling null/None by omitting the mode or passing None;
ensure the conversion and null-check occur inside the OpenSandboxFileTool method
that constructs the WriteEntry call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 71e30e3f-97fe-4af1-b9b6-4ddd919aad17

📥 Commits

Reviewing files that changed from the base of the PR and between 9c981e1 and 812468e.

📒 Files selected for processing (4)
  • lib/crewai-tools/pyproject.toml
  • lib/crewai-tools/src/crewai_tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/__init__.py
  • lib/crewai-tools/tool.specs.json
✅ Files skipped from review due to trivial changes (1)
  • lib/crewai-tools/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/crewai-tools/src/crewai_tools/tools/init.py
  • lib/crewai-tools/src/crewai_tools/init.py

Comment thread lib/crewai-tools/tool.specs.json
Comment on lines +16636 to +16640
"default": null,
"description": "Optional kwargs forwarded to SandboxSync.create when creating a sandbox (e.g. image, env, resource, metadata, entrypoint).",
"title": "Create Params"
},
"domain": {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -p 'open_sandbox_file_tool.py' | while read -r file; do
  echo "== $file =="
  rg -n -C3 '\bmode\b|mkdir|chmod|os\.makedirs|Path\.mkdir' "$file"
done

Repository: crewAIInc/crewAI

Length of output: 3458


🏁 Script executed:

# Find and examine the current specs.json file
fd -p 'tool\.specs\.json' | head -5

Repository: crewAIInc/crewAI

Length of output: 93


🏁 Script executed:

# Look at the specific lines mentioned in the review (16636-16640)
fd -p 'tool\.specs\.json' | while read -r file; do
  echo "=== File: $file ==="
  wc -l "$file"
  echo "=== Lines around 16636-16640 ==="
  sed -n '16630,16650p' "$file"
done

Repository: crewAIInc/crewAI

Length of output: 896


🏁 Script executed:

# Search for "mode" definition in the specs.json file
fd -p 'tool\.specs\.json' | while read -r file; do
  echo "=== Searching for mode in $file ==="
  rg -n '"mode"' "$file" | head -20
done

Repository: crewAIInc/crewAI

Length of output: 200


🏁 Script executed:

# Look at all three mode definitions in the specs.json
fd -p 'tool\.specs\.json' | while read -r file; do
  echo "=== Mode at line 7403 ==="
  sed -n '7400,7415p' "$file"
  echo ""
  echo "=== Mode at line 16736 ==="
  sed -n '16733,16748p' "$file"
  echo ""
  echo "=== Mode at line 24503 ==="
  sed -n '24500,24515p' "$file"
done

Repository: crewAIInc/crewAI

Length of output: 2129


🏁 Script executed:

# Search for which tool has the mode field near line 16736
fd -p 'tool\.specs\.json' | while read -r file; do
  echo "=== Context around line 16736 to identify tool ==="
  sed -n '16700,16760p' "$file" | head -40
done

Repository: crewAIInc/crewAI

Length of output: 1848


🏁 Script executed:

# Identify which tools these mode definitions belong to
fd -p 'tool\.specs\.json' | while read -r file; do
  echo "=== Tool at line 7403 ==="
  sed -n '7300,7410p' "$file" | grep -E '"(name|title|properties)"|"mode"' | head -10
  echo ""
  echo "=== Tool at line 16736 ==="
  sed -n '16650,16750p' "$file" | grep -E '"(name|title|properties)"|"mode"' | head -10
done

Repository: crewAIInc/crewAI

Length of output: 773


🏁 Script executed:

# Look at the actual tool definitions to identify them clearly
fd -p 'tool\.specs\.json' | while read -r file; do
  echo "=== Searching for tool definitions around line 7403 ==="
  sed -n '7100,7150p' "$file" | grep -E '"(name|title|description)"'
  echo ""
  echo "=== Searching for tool definitions around line 16736 ==="
  sed -n '16550,16600p' "$file" | grep -E '"(name|title|description)"'
done

Repository: crewAIInc/crewAI

Length of output: 1613


🏁 Script executed:

# Search for which SDK or lib the code uses for WriteEntry to understand mode handling
fd -p '\.py$' lib/crewai-tools/src/crewai_tools/ | xargs rg -l 'WriteEntry' | head -5

Repository: crewAIInc/crewAI

Length of output: 228


🏁 Script executed:

# Look at the open_sandbox_base_tool.py to see how WriteEntry is used
fd -p 'open_sandbox_base_tool.py' | while read -r file; do
  rg -n -B2 -A5 'WriteEntry|mode' "$file" | head -40
done

Repository: crewAIInc/crewAI

Length of output: 1659


🏁 Script executed:

# Search for SDK or library that provides WriteEntry
rg -n 'WriteEntry' lib/crewai-tools/src/ --type py | head -20

Repository: crewAIInc/crewAI

Length of output: 701


🏁 Script executed:

# Look for import of WriteEntry or opensandbox SDK
fd -p '\.py$' lib/crewai-tools/src/crewai_tools/tools/open_sandbox_tool/ | xargs rg -n 'import|from.*opensandbox|WriteEntry'

Repository: crewAIInc/crewAI

Length of output: 5213


Fix the mode field in OpenSandboxFileTool schema to use octal strings instead of decimal integer.

The current schema at lines 16736-16748 defines mode as a decimal integer with default 755, but the Python implementation passes this value directly to WriteEntry(mode=mode) without conversion. This causes a mismatch: callers expect Unix permissions (where 755 is octal, equivalent to 0o755 = 493 in decimal), but the integer 755 is interpreted as decimal, resulting in invalid permission bits.

The fix should follow the pattern already established in DaytonaFileTool (line 7403), which correctly uses an octal string type with description "Octal permission string" and default null. Update OpenSandboxFileTool to match:

Suggested spec fix
          "mode": {
-           "default": 755,
-           "description": "For action='mkdir': Unix file mode as an integer (default 755).",
-           "title": "Mode",
-           "type": "integer"
+           "anyOf": [
+             {
+               "type": "string"
+             },
+             {
+               "type": "null"
+             }
+           ],
+           "default": null,
+           "description": "For action='mkdir': octal permission string (for example '0755').",
+           "title": "Mode"
          },

Also update the Python implementation to accept string mode and convert it before passing to the SDK.

🤖 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/tool.specs.json` around lines 16636 - 16640,
OpenSandboxFileTool's schema currently defines "mode" as a decimal integer
(default 755); change its schema to use type "string", description "Octal
permission string", and default null to match the DaytonaFileTool pattern, and
then update the Python implementation of OpenSandboxFileTool where
WriteEntry(mode=mode) is called to accept a string mode (or null) and convert it
to an int with base-8 (e.g., int(mode, 8)) before passing to WriteEntry,
handling null/None by omitting the mode or passing None; ensure the conversion
and null-check occur inside the OpenSandboxFileTool method that constructs the
WriteEntry call.

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

3 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

3 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

6 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants