Skip to main content
AG-Kit’s Bash tool gives your agents the power to execute shell commands, run scripts, and interact with the operating system. It’s a versatile tool for automation, system administration, and development tasks, with built-in support for both local and secure sandboxed execution.

What You Can Do

  • Run Any Shell Command: Execute standard commands like ls, grep, curl, or git.
  • Execute Scripts: Run shell scripts (.sh) or other command-line scripts.
  • Manage System Processes: Check running processes, manage services, or gather system information.
  • Choose Your Environment: Run commands directly on the local machine for speed or in a secure sandbox for safety.

Core Concepts

  1. BashTool: The main tool you provide to your agent. It takes a shell command as input and executes it.
  2. BashOperator (Backend): The engine that runs the command. You can choose from two backends:
    • LocalBashOperator: Executes commands directly on the host machine. It’s fast but should only be used in trusted environments.
    • SandboxBashOperator: Executes commands inside a secure, isolated E2B container. It’s the safe choice for handling commands generated by LLMs or users.

Quick Start

from agkit.tools import create_bash_tool, LocalBashOperator

# 1. Choose a backend and create the context
bash_operator = LocalBashOperator()
context = {"bash_operator": bash_operator}

# 2. Create the tool
bash_tool = create_bash_tool(context)

# 3. Use the tool to run a command
result = await bash_tool.invoke({
    "command": 'echo "Hello from the command line!"'
})

print(result.data.stdout)

Choosing the Right Backend

BackendUse CaseKey Benefit
LocalBashOperatorTrusted Scripts & DevPerformance & Local Access
SandboxBashOperatorUntrusted Commands (LLMs)Security & Isolation

Core Operations & Examples

Running a Simple Command

Execute any standard shell command and get the stdout, stderr, and exitCode.
result = await bash_tool.invoke({'command': 'ls -la'})
# result.data: { 
#   'stdout': 'total 48\ndrwxr-xr-x  12 user  staff   384 Jan 15 10:30 .\n...',
#   'stderr': '',
#   'exit_code': 0
# }

if result.success:
    print('Directory listing:', result.data.stdout)

Piping Commands

Chain commands together using pipes, just like in a regular shell.
# First, create a file using the Filesystem tool
await fs_toolkit.get_tool('write_file').invoke({
    'file_path': 'data.txt',
    'content': 'This is a test.'
})

# Now, use the bash tool to read it
result = await bash_tool.invoke({'command': 'cat data.txt'})
# result.data: { 'stdout': 'This is a test.', 'stderr': '', 'exit_code': 0 }
print(result.data.stdout)  # "This is a test."

Streaming Output

For long-running commands like npm install or a development server, you can stream stdout and stderr in real-time instead of waiting for the command to finish. This is done by providing onStdout and onStderr handlers when creating the operator.
from agkit.tools import create_bash_tool, SandboxBashOperator
import os

# Create an operator with streaming handlers
streaming_operator = SandboxBashOperator(
    api_key=os.getenv('E2B_API_KEY'),
    on_stdout=lambda data: print(f"[STDOUT] {data.line}"),
    on_stderr=lambda data: print(f"[STDERR] {data.line}"),
)

bash_tool = create_bash_tool(bash_operator=streaming_operator)

# Run a long-running command
await bash_tool.invoke({
    'command': 'for i in {1..5}; do echo "Step $i"; sleep 1; done'
})

# The output will be logged to the console in real-time.

Best Practices & Troubleshooting

  • Prefer Specific Tools: If a dedicated tool exists (like the ls or grep tools in FilesystemToolkit), prefer it over the raw bash command. Dedicated tools often provide structured output and better error handling.
  • Security: Never use the LocalBashOperator with commands generated by an LLM or external users. Always use the SandboxBashOperator for untrusted input.
  • Error Handling: Always check the exitCode and stderr from the result to know if a command failed and why.
  • Working Directory: Be mindful of the current working directory (cwd). Commands are executed relative to it. You can set the cwd when creating the BashOperator.

Next Steps