python-executor
Secure Remote Python Code Execution Sandbox for AI Agents & Automation

A high-performance, self-hosted remote Python execution service designed for secure, isolated, and reproducible execution of untrusted or ad-hoc Python code β from single scripts to multi-gigabyte ML projects. Perfect as a code interpreter for LLMs, AI agents, and automation workflows.
Features
- π Secure Execution - Docker-in-Docker isolation with strict resource limits
- π¦ Multi-file Projects - Support for entire project directories via uncompressed tar archives
- β‘ Sync & Async - Both synchronous and asynchronous execution modes
- π Multiple Interfaces - REST API, Go client, Python client, and CLI tool
- π Consul Integration - Optional distributed state storage with in-memory fallback
- π API Documentation - Complete API reference with Swagger UI at
/docs
- π Custom Requirements - Install dependencies via requirements.txt
- π€ Auto-detect Imports - Automatically detects and installs third-party packages
- βοΈ Pre-execution Commands - Run setup commands (apt install, etc.)
- π― Resource Limits - Configurable memory, CPU, disk, and timeout limits
- π« Network Isolation - Network disabled by default for security
- π Environment Variables - Pass environment variables with
--env
- π Script Arguments - Pass arguments to scripts with
-- separator
LLM & AI Agent Integration
Designed as a code interpreter and Python sandbox for AI systems. Supports LLM tool-calling, function calling, and is MCP server compatible.
Three integration approaches are available:
Option A: Simple JSON API (Recommended for most AI agents)
Use POST /api/v1/eval with plain JSON β no tar archives or multipart encoding needed.
# Single script
curl -X POST http://localhost:8080/api/v1/eval \
-H "Content-Type: application/json" \
-d '{"code": "print(\"Hello, World!\")"}'
# With specific Python version
curl -X POST http://localhost:8080/api/v1/eval \
-H "Content-Type: application/json" \
-d '{"code": "import sys; print(sys.version)", "python_version": "3.11"}'
# With timeout configuration
curl -X POST http://localhost:8080/api/v1/eval \
-H "Content-Type: application/json" \
-d '{"code": "print(\"Hello\")", "config": {"timeout_seconds": 30}}'
# Multiple files
curl -X POST http://localhost:8080/api/v1/eval \
-H "Content-Type: application/json" \
-d '{
"files": [
{"name": "main.py", "content": "from helper import greet\ngreet()"},
{"name": "helper.py", "content": "def greet(): print(\"Hello!\")"}
],
"entrypoint": "main.py"
}'
Supported Python versions: 3.10, 3.11, 3.12 (default), 3.13
Auto-detect imports: The /api/v1/eval endpoint automatically detects third-party imports and installs them. This works out-of-the-box for packages like numpy, pandas, requests, sympy, etc.
# This automatically detects and installs numpy
curl -X POST http://localhost:8080/api/v1/eval \
-H "Content-Type: application/json" \
-d '{"code": "import numpy as np; print(np.array([1,2,3]))"}'
Best for: Simple scripts, quick evaluations, LLM tool-calling
Limitation: 100KB total code size
Option B: Client Libraries
For large projects or complex file structures, use the client libraries which handle tar archives automatically.
Python:
pip install git+https://github.com/geraldthewes/python-executor.git#subdirectory=python
Go:
go get github.com/geraldthewes/python-executor/pkg/client
Best for: Large projects, complex file structures, multi-MB codebases
Option C: Command-Line Interface
Use the CLI for shell-based workflows, scripts, and AI agents that can execute commands.
# Install
go install github.com/geraldthewes/python-executor/cmd/python-executor@latest
# Pipe code via stdin (perfect for AI agents)
echo 'print("Hello from AI")' | python-executor run -q
# Run with specific server
echo 'print("result:", 42)' | python-executor --server http://pyexec.cluster:9999 run -q
# Async execution for long-running tasks
EXEC_ID=$(python-executor submit long_task.py)
python-executor follow $EXEC_ID
# With environment variables
python-executor run script.py --env API_KEY --env DEBUG=true
# With script arguments
python-executor run script.py -- --model gpt-4 --temperature 0.7
Configuration:
export PYEXEC_SERVER=http://localhost:8080 # Server URL
Flags: -q (quiet - stdout only), -v (verbose - include metadata)
Best for: Shell scripts, CI/CD pipelines, AI agents with command execution
All approaches return the same response format:
{
"execution_id": "exe_...",
"status": "completed",
"stdout": "Hello, World!\n",
"stderr": "",
"exit_code": 0,
"duration_ms": 150
}
Error responses include structured error information:
{
"execution_id": "exe_...",
"status": "completed",
"stdout": "",
"stderr": "Traceback...\nNameError: name 'x' is not defined",
"exit_code": 1,
"error_type": "NameError",
"error_line": 1,
"duration_ms": 120
}
See API Reference for complete documentation.
Use Cases
- AI agent tool-calling (MCP servers, LLM function calling)
- Secure online judges and education platforms
- Internal automation and data-processing microservices
- CI/CD code generation steps
- Remote script execution for distributed systems
Why python-executor?
- Nomad-native deployment - First-class support for HashiCorp Nomad orchestration
- Self-hosted - No cloud dependency, run on your own infrastructure
- Multiple interfaces - REST API, CLI, Go client, and Python client
- Production-ready - Built-in resource limits, security isolation, and monitoring
- AI-first design - Simple JSON API designed specifically for LLM integration
Quick Start
Using Docker Compose
cd deploy
docker-compose up
The server will be available at http://localhost:8080.
Using the CLI
Install:
go install github.com/geraldthewes/python-executor/cmd/python-executor@latest
Basic usage:
# Run from stdin
echo 'print("Hello, World")' | python-executor run
# Run a single file
python-executor run script.py
# Run a directory
python-executor run ./my-project/ --entrypoint main.py
# Run with custom limits
python-executor run script.py --timeout 600 --memory 2048 --network
# Pass environment variables to the script
python-executor run script.py --env API_KEY --env DEBUG=true
# Pass arguments to the script (after --)
python-executor run script.py -- arg1 arg2 --verbose
# Combined: env vars and script arguments
python-executor run script.py --env SERVICE_HOST -e SERVICE_PORT -- http://host:port
# Async execution
id=$(python-executor submit long-script.py --async)
python-executor follow $id
# Specify server URL via flag
python-executor --server http://my-server:8080 run script.py
# Specify server URL via environment variable
export PYEXEC_SERVER=http://my-server:8080
python-executor run script.py
See Examples for more CLI usage patterns.
Using the Go Client
package main
import (
"context"
"fmt"
"log"
"github.com/geraldthewes/python-executor/pkg/client"
)
func main() {
c := client.New("http://localhost:8080")
tarData, _ := client.TarFromMap(map[string]string{
"main.py": `print("Hello from Go!")`,
})
result, err := c.ExecuteSync(context.Background(), tarData, &client.Metadata{
Entrypoint: "main.py",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Stdout)
}
Using the Python Client
Install from repository:
pip install git+https://github.com/geraldthewes/python-executor.git#subdirectory=python
Usage:
from python_executor_client import PythonExecutorClient
client = PythonExecutorClient("http://localhost:8080")
result = client.execute_sync(
files={"main.py": "print('Hello from Python!')"},
entrypoint="main.py"
)
print(result.stdout)
print(f"Exit code: {result.exit_code}")
API Endpoints
| Method |
Endpoint |
Description |
| POST |
/api/v1/eval |
Execute code via simple JSON (AI-friendly) |
| POST |
/api/v1/exec/sync |
Execute code synchronously |
| POST |
/api/v1/exec/async |
Submit code for async execution |
| GET |
/api/v1/executions/{id} |
Get execution status and result |
| DELETE |
/api/v1/executions/{id} |
Kill a running execution |
| GET |
/health |
Health check endpoint |
See API Documentation for detailed API specs. Note: Use client libraries instead of implementing the HTTP protocol directly.
Building from Source
Requirements:
Build commands:
# Build everything
make build
# Build server only
make build-server
# Build CLI only
make build-cli
# Run unit tests
make test
# Build Docker image
make docker-build
Binaries will be in ./bin/.
Deployment
Local Development
# With in-memory storage
make run-server
# With Consul (requires Consul running)
export PYEXEC_CONSUL_ADDR=localhost:8500
make run-server
Docker
docker build -t python-executor -f deploy/Dockerfile .
docker run -d \
--name python-executor \
--privileged \
-p 8080:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
python-executor
Nomad
See deploy/nomad.hcl for a production-ready Nomad job specification.
nomad job run deploy/nomad.hcl
Configuration
Configuration is via environment variables:
# Server
export PYEXEC_PORT=8080
export PYEXEC_LOG_LEVEL=info
export PYEXEC_SERVER=http://localhost:8080
# Consul (optional)
export PYEXEC_CONSUL_ADDR=consul:8500
# Defaults
export PYEXEC_DEFAULT_TIMEOUT=300
export PYEXEC_DEFAULT_MEMORY_MB=1024
export PYEXEC_AUTO_DETECT_IMPORTS=true # Auto-detect and install packages (default: true)
# Docker network settings
export PYEXEC_NETWORK_MODE=host # or "bridge"
export PYEXEC_DNS_SERVERS=8.8.8.8,8.8.4.4
The PYEXEC_SERVER environment variable specifies the base URL of the python-executor server. This can be overridden with the --server flag when using the CLI tool.
Note on Ports: The python-executor server defaults to port 8080. If your scripts use frameworks like FastAPI/uvicorn (which default to port 8000), ensure your port configuration is explicit to avoid mismatches.
See Configuration Guide for all options.
Security
python-executor uses multiple security layers:
- Docker Isolation - Each execution in separate container
- Non-root User - Code runs as UID 1000
- Resource Limits - Memory, CPU, disk, timeout enforcement
- Network Disabled - No network access by default
- Read-only Root - Filesystem is read-only
- Path Sanitization - Prevents path traversal attacks
Important: This service requires Docker socket access and should be deployed with appropriate security measures. See Security Guide for best practices.
Documentation
- API Reference - Complete API specification (use client libraries instead of raw HTTP)
- Configuration - Environment variables and settings
- Security - Security considerations and best practices
- Examples - Usage examples for all interfaces
- PRD - Product Requirements Document
Project Structure
python-executor/
βββ cmd/
β βββ server/ # API server
β βββ python-executor/ # CLI tool
βββ internal/
β βββ api/ # HTTP handlers
β βββ config/ # Configuration
β βββ executor/ # Docker execution engine
β βββ storage/ # State storage backends
β βββ tar/ # Tar archive handling
βββ pkg/
β βββ client/ # Go client library
βββ python/
β βββ python_executor_client/ # Python client
βββ deploy/
β βββ Dockerfile
β βββ docker-compose.yaml
β βββ nomad.hcl
βββ docs/ # Documentation
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass (
make test)
- Submit a pull request
License
MIT License - see LICENSE for details
Acknowledgments
Inspired by: