Skip to main content

Bash Tools (Python)

Execute bash commands using either local system execution or secure sandboxed environments with comprehensive command management capabilities.

Overview

The Bash Tools provide a unified interface for executing bash commands across different environments:
  • Local Execution: Direct execution on the local system
  • Sandbox Execution: Secure execution in isolated E2B containers
  • Multi-Command Support: Execute multiple commands in sequence
  • Real-time Streaming: Live output monitoring with callbacks

Quick Start

Local Execution

from ag_kit_py.tools.bash import create_local_bash_context, create_bash_tool

context = create_local_bash_context(
    cwd='/path/to/working/directory',
    env={'CUSTOM_VAR': 'value'}
)

bash_tool = create_bash_tool(context)
result = await bash_tool.invoke({'command': 'echo "Hello World!"'})

Sandbox Execution

from ag_kit_py.tools.bash import create_sandbox_bash_context, create_bash_tool
from e2b_code_interpreter import Sandbox

# Note: Sandbox.create() is synchronous in Python SDK
sandbox = Sandbox.create()
context = create_sandbox_bash_context(
    sandbox=sandbox,
    cwd='/home/user'
)

bash_tool = create_bash_tool(context)
result = await bash_tool.invoke({'command': 'ls -la'})

Core Features

Single Command Execution

result = await bash_tool.invoke({
    'command': 'find . -name "*.py" | head -5',
    'cwd': '/project/src',
    'env': {'NODE_ENV': 'development'},
    'timeout': 10000
})

Multi-Command Execution

from ag_kit_py.tools.bash import create_multi_command_tool

multi_tool = create_multi_command_tool(context)
result = await multi_tool.invoke({
    'commands': [
        'mkdir -p /tmp/test',
        'echo "Hello" > /tmp/test/file.txt',
        'cat /tmp/test/file.txt'
    ],
    'continue_on_error': False
})

Real-time Output Streaming

def on_stdout(data: str):
    print(f"OUT: {data}", end="")

def on_stderr(data: str):
    print(f"ERR: {data}", end="")

result = await bash_tool.invoke({
    'command': 'for i in {1..5}; do echo "Step $i"; sleep 1; done',
    'on_stdout': on_stdout,
    'on_stderr': on_stderr
})

Interactive Commands

result = await bash_tool.invoke({
    'command': 'python3 -c "name = input(\'Name: \'); print(f\'Hello {name}!\')"',
    'input': 'Alice\n',
    'timeout': 5000
})

Command Builders

Pre-built command generators for common operations:
from ag_kit_py.tools.bash import CommandBuilders

# File operations
list_command = CommandBuilders.list_files('/home/user', all=True, long=True, human=True)
find_command = CommandBuilders.find_files('*.py', './src')
grep_command = CommandBuilders.grep('TODO', '*.js', recursive=True, ignore_case=True)

# Directory operations
mkdir_command = CommandBuilders.mkdir('/path/to/dir', parents=True)
copy_command = CommandBuilders.copy('source', 'dest', recursive=True)
remove_command = CommandBuilders.remove('/tmp/file', force=True)

# Execute built commands
result = await bash_tool.invoke({'command': list_command})

Security Features

Command Validation

from ag_kit_py.tools.bash import validate_command

validation = validate_command('rm -rf /')
if not validation.is_valid:
    print(f"Dangerous command: {validation.reason}")

Argument Escaping

from ag_kit_py.tools.bash import escape_shell_arg, build_command

user_input = "file with spaces & special chars"
command = build_command('ls', ['-la', user_input])
# Result: "ls '-la' 'file with spaces & special chars'"

API Reference

Context Creation

# Local context
create_local_bash_context(
    cwd: Optional[str] = None,
    env: Optional[Dict[str, str]] = None,
    default_timeout: int = 30000
) -> BashExecutionContext

# Sandbox context
create_sandbox_bash_context(
    sandbox: Sandbox,
    cwd: Optional[str] = None,
    env: Optional[Dict[str, str]] = None,
    default_timeout: int = 30000
) -> BashExecutionContext

Tool Creation

# Create bash tool
create_bash_tool(context: BashExecutionContext) -> Tool

# Create multi-command tool
create_multi_command_tool(context: BashExecutionContext) -> Tool

Operator Classes

BaseBashOperator (Abstract)

class BaseBashOperator:
    async def execute_command(
        self,
        command: str,
        options: Optional[CommandOptions] = None
    ) -> CommandResult
    
    async def get_current_directory(self) -> str
    
    async def change_directory(self, path: str) -> None
    
    async def get_environment_variables(self) -> Dict[str, str]
    
    async def set_environment_variable(self, key: str, value: str) -> None
    
    async def cleanup(self) -> None

LocalBashOperator

operator = LocalBashOperator(
    cwd: Optional[str] = None,
    env: Optional[Dict[str, str]] = None
)

result = await operator.execute_command('echo "Hello"')

SandboxBashOperator

operator = SandboxBashOperator(
    sandbox: Sandbox,
    cwd: Optional[str] = None,
    env: Optional[Dict[str, str]] = None
)

result = await operator.execute_command('ls -la')

Data Models

CommandOptions

@dataclass
class CommandOptions:
    cwd: Optional[str] = None
    env: Optional[Dict[str, str]] = None
    timeout: Optional[int] = None  # milliseconds
    input: Optional[str] = None
    shell: Optional[bool] = True
    on_stdout: Optional[Callable[[str], None]] = None
    on_stderr: Optional[Callable[[str], None]] = None

CommandResult

@dataclass
class CommandResult:
    success: bool
    exit_code: Optional[int]
    stdout: str
    stderr: str
    execution_time: float  # milliseconds

BashToolResponse

class BashToolResponse(BaseModel):
    command: str
    exit_code: Optional[int]
    stdout: str
    stderr: str
    working_directory: str

MultiCommandResponse

class MultiCommandResponse(BaseModel):
    commands: List[str]
    results: List[CommandResultItem]
    successful_commands: int
    failed_commands: int
    working_directory: str

Utility Functions

from ag_kit_py.tools.bash import (
    validate_command,
    escape_shell_arg,
    build_command,
    parse_command_output,
    format_execution_time,
    CommandBuilders
)

# Validate command
validation = validate_command('echo "safe"')  # CommandValidation

# Escape arguments
escaped = escape_shell_arg("it's a test")  # "'it'\"'\"'s a test'"

# Build command
cmd = build_command('ls', ['-la', '/home'])  # "ls '-la' '/home'"

# Parse output
parsed = parse_command_output(stdout, stderr)  # ParsedOutput

# Format time
time_str = format_execution_time(1500)  # "1.50s"

CommandBuilders Reference

class CommandBuilders:
    @staticmethod
    def list_files(
        path: str = ".",
        all: bool = False,
        long: bool = False,
        human: bool = False
    ) -> str
    
    @staticmethod
    def find_files(pattern: str, path: str = ".") -> str
    
    @staticmethod
    def grep(
        pattern: str,
        files: str = "*",
        recursive: bool = False,
        ignore_case: bool = False,
        line_numbers: bool = False
    ) -> str
    
    @staticmethod
    def exists(path: str) -> str
    
    @staticmethod
    def stat(path: str) -> str
    
    @staticmethod
    def mkdir(path: str, parents: bool = False) -> str
    
    @staticmethod
    def copy(
        source: str,
        destination: str,
        recursive: bool = False,
        preserve: bool = False
    ) -> str
    
    @staticmethod
    def move(source: str, destination: str) -> str
    
    @staticmethod
    def remove(
        path: str,
        recursive: bool = False,
        force: bool = False
    ) -> str

Examples

Development Workflow

build_result = await multi_tool.invoke({
    'commands': [
        'pip install -r requirements.txt',
        'python setup.py build',
        'pytest tests/'
    ],
    'continue_on_error': False,
    'timeout': 120000
})

File System Operations

setup_result = await multi_tool.invoke({
    'commands': [
        'mkdir -p project/{src,tests,docs}',
        'touch project/src/__init__.py',
        'echo "# Project" > project/README.md'
    ]
})

Data Processing Pipeline

pipeline = await multi_tool.invoke({
    'commands': [
        'curl -o data.json https://api.example.com/data',
        'jq ".items[]" data.json > processed.json',
        'wc -l processed.json'
    ],
    'continue_on_error': False
})

Error Handling

try:
    result = await bash_tool.invoke({
        'command': 'risky-command',
        'timeout': 5000
    })
    
    if not result.success:
        print(f"Command failed: {result.data['stderr']}")
        print(f"Exit code: {result.data['exit_code']}")
except Exception as error:
    print(f'Execution error: {error}')

Advanced Usage

Using Operator Directly

from ag_kit_py.tools.bash import LocalBashOperator, CommandOptions

operator = LocalBashOperator(cwd='/project')

# Execute with custom options
result = await operator.execute_command(
    'long-running-command',
    CommandOptions(
        timeout=60000,
        env={'DEBUG': '1'},
        on_stdout=lambda data: print(data, end='')
    )
)

# Directory operations
await operator.change_directory('/tmp')
current = await operator.get_current_directory()

# Environment management
await operator.set_environment_variable('API_KEY', 'secret')
env = await operator.get_environment_variables()

Custom Tool Configuration

from ag_kit_py.tools.bash import BashExecutionContext, create_bash_tool

# Create custom context
context = BashExecutionContext(
    bash_operator=LocalBashOperator(),
    working_directory='/custom/path',
    environment_variables={'ENV': 'production'},
    default_timeout=60000
)

# Create tool with custom context
bash_tool = create_bash_tool(context)

Installation

Basic Installation

pip install ag_kit_py

With E2B Support

pip install ag_kit_py e2b-code-interpreter

Environment Variables

When using sandbox execution, configure E2B:
export AG_KIT_SANDBOX_API_KEY="your-e2b-api-key"
export AG_KIT_SANDBOX_DOMAIN="your-e2b-domain"  # optional

Examples Repository

Find complete working examples at:

Security Considerations

  1. Command Validation: Always validate user-provided commands
  2. Argument Escaping: Use escape_shell_arg() for user input
  3. Sandbox Isolation: Use sandbox execution for untrusted code
  4. Timeout Limits: Set appropriate timeouts for all commands
  5. Environment Variables: Be careful with sensitive data in env vars

Performance Tips

  1. Reuse Operators: Create operator once and reuse for multiple commands
  2. Batch Commands: Use multi-command tool for related operations
  3. Stream Output: Use callbacks for large output to avoid memory issues
  4. Timeout Management: Set realistic timeouts based on expected execution time
  5. Sandbox Lifecycle: Reuse sandbox instances when possible