Skip to main content

A lightweight, secure sandbox runtime for AI Agents

Project description

doka

PyPI version Python Version License

Self-hosted. Pluggable. Agent-ready.

Secure, isolated sandboxes for AI Agents — without the cloud dependency.


What is doka?

doka gives AI Agents a safe place to run code. It provides a programmable, isolated execution environment where developers can run commands, move files, and control resources — without being locked into any Agent framework or cloud provider.

Runs entirely on your own infrastructure. No API key. No usage limit. No data leaving your machine.


Quick Start

1. Install

pip install dokapy

2. Start a runtime backend

The default runtime is docker. Make sure Docker Desktop (or Docker Engine) is running, or choose a different runtime — see Pluggable runtime backends.

3. Run your first sandbox

from doka import Sandbox

with Sandbox() as sandbox:
    result = sandbox.commands.run('echo "Hello from Doka!"')
    print(result.stdout)  # Hello from Doka!

4. Run an Agent script inside the sandbox

from doka import Sandbox

agent_code = """
print('Agent started')
print('Agent finished')
"""

with Sandbox() as sandbox:
    sandbox.files.write("/tmp/agent.py", agent_code)
    result = sandbox.commands.run("python /tmp/agent.py")
    print(result.stdout)

Core Features

Command-first — works with any Agent framework

doka does not try to standardize how Agents start. LangChain, AutoGen, CrewAI, custom scripts, compiled binaries — bring your own Agent, run it with a command.

with Sandbox() as sandbox:
    sandbox.files.write("/workspace/main.py", agent_code)
    result = sandbox.commands.run("python /workspace/main.py")
    output = sandbox.files.read("/workspace/output.json")

File I/O

with Sandbox() as sandbox:
    sandbox.files.write("/tmp/input.txt", "hello")
    sandbox.commands.run("cat /tmp/input.txt > /tmp/output.txt")
    output = sandbox.files.read("/tmp/output.txt")

Streaming output for long-running processes

process = sandbox.commands.run("python -u agent.py", background=True)

for chunk in process.stdout.stream():
    print(chunk, end="")

exit_code = process.wait()

Resource controls

from doka import Limits, Sandbox

with Sandbox(limits=Limits(cpu=1, memory="512m", network=False)) as sandbox:
    result = sandbox.commands.run("python agent.py")

Pluggable runtime backends

The runtime parameter accepts a URI of the form <driver>[:<variant>].

URI Status Isolation Requirements
docker Available Container (runc) Docker Engine running locally
docker:gvisor Available Userspace kernel (gVisor Sentry) Docker Engine + gVisor installed (see below)
cube Available KVM MicroVM KVM-enabled x86_64 Linux + CubeSandbox service running locally
kata Available KVM MicroVM KVM-enabled x86_64 Linux + Kata Containers + nerdctl + CNI plugins (see below)

Runtime support (Runtime Parameter)

URI Linux macOS Windows
docker
docker:gvisor
cube ✅ (bare-metal / KVM-enabled VM only)
kata ✅ (bare-metal / KVM-enabled VM only)

Which runtime should I use?

Situation Recommended runtime
Just getting started, or developing on Windows / macOS docker
Linux server, want stronger isolation without setting up a VM stack docker:gvisor
Already running CubeSandbox in your infra (e.g. Tencent Cloud) cube
Bare-metal Linux, want hardware VM isolation independent of Docker kata

As a rule of thumb: start with docker, upgrade to docker:gvisor when you need stronger isolation, and reach for kata when you want full VM-level security on bare metal.

The API stays the same regardless of which backend you use:

# All four work identically from the caller's perspective
Sandbox(runtime="docker",        image="python:3.11-slim")
Sandbox(runtime="docker:gvisor", image="python:3.11-slim")
Sandbox(runtime="cube",          image="tpl-abc123")
Sandbox(runtime="kata",          image="python:3.11-slim")

Installing CubeSandbox

CubeSandbox runs each sandbox in a KVM MicroVM managed by a local service. See the official repository for installation and setup instructions: 👉 TencentCloud/CubeSandbox

Installing gVisor

gVisor intercepts all syscalls inside a userspace kernel (Sentry), so a container exploit cannot reach the real host kernel directly.

# 1. Add the gVisor apt repository
curl -fsSL https://gvisor.dev/archive.key \
    | sudo gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] \
    https://storage.googleapis.com/gvisor/releases release main" \
    | sudo tee /etc/apt/sources.list.d/gvisor.list

# 2. Install and register as a Docker runtime
sudo apt-get update && sudo apt-get install -y runsc
sudo runsc install && sudo systemctl restart docker

# 3. Verify
runsc --version
docker info | grep runsc   # should show "runsc" under Runtimes

Once installed, switch any existing sandbox to gVisor with a one-word change:

# Before
Sandbox(runtime="docker", ...)

# After — stronger isolation, identical API
Sandbox(runtime="docker:gvisor", ...)

Installing Kata Containers

Kata Containers runs each sandbox inside a KVM MicroVM with a dedicated guest kernel (6.x), providing hardware-enforced VM isolation independent of Docker.

# 1. Download and install Kata static bundle
#    https://github.com/kata-containers/kata-containers/releases
#    Choose: kata-static-<version>-amd64.tar.zst
sudo tar -C / -xf kata-static-*-amd64.tar.zst

# 2. Link the containerd shim into PATH
sudo ln -sf /opt/kata/bin/containerd-shim-kata-v2 /usr/local/bin/

# 3. Install nerdctl (Docker-compatible CLI for containerd)
#    https://github.com/containerd/nerdctl/releases  (non-full build, ~20 MB)
sudo tar -C /usr/local/bin -xzf nerdctl-*-linux-amd64.tar.gz nerdctl

# 4. Install CNI network plugins (Linux amd64 version)
#    https://github.com/containernetworking/plugins/releases
sudo mkdir -p /opt/cni/bin
sudo tar -C /opt/cni/bin -xzf cni-plugins-linux-amd64-*.tgz

# 5. Allow nerdctl to run without a password (nerdctl needs root for system containerd)
echo "$USER ALL=(root) NOPASSWD: /usr/local/bin/nerdctl" \
    | sudo tee /etc/sudoers.d/nerdctl

# 6. Verify
sudo nerdctl run --rm --runtime=io.containerd.kata.v2 python:3.11-slim uname -r
# Expected output: 6.x.x  (Kata guest kernel, not the host kernel)

API Reference

Sandbox(runtime="docker", limits=None, image=None)

Creates an isolated sandbox environment.

Parameter Type Default Description
runtime str "docker" Runtime URI: "docker", "docker:gvisor", "cube", or "kata".
limits Limits | None None Resource limits for the sandbox.
image str | None None Container image. Defaults to python:3.11-slim for Docker.

Recommended usage:

with Sandbox() as sandbox:
    result = sandbox.commands.run("python --version")

Manual lifecycle:

sandbox = Sandbox().start()
try:
    result = sandbox.commands.run("python --version")
finally:
    sandbox.close()

sandbox.commands.run(command, background=False, env=None, workdir=None)

Executes a command inside the sandbox.

Parameter Type Default Description
command str required Shell command to execute.
background bool False Run as a background process when True.
env dict | None None Additional environment variables.
workdir str | None None Working directory inside the sandbox.

Blocking mode returns CommandResult:

result = sandbox.commands.run("python --version")
print(result.stdout)
print(result.stderr)
print(result.exit_code)

Background mode returns Process:

process = sandbox.commands.run("python long_running_agent.py", background=True)

for chunk in process.stdout.stream():
    print(chunk)

exit_code = process.wait()

sandbox.files

Simple file operations inside the sandbox.

Method Description
write(path, content) Write text content to a file inside the sandbox.
read(path) Read a file from inside the sandbox.
exists(path) Return whether a path exists inside the sandbox.
sandbox.files.write("/tmp/input.txt", "hello")
exists = sandbox.files.exists("/tmp/input.txt")
content = sandbox.files.read("/tmp/input.txt")

Limits

Resource constraints for the sandbox.

Field Type Default Description
cpu Union[int, float] 1 CPU quota. Supports fractional values, e.g. 0.5, 1, 2.
memory str "512m" Memory limit, e.g. "512m", "1g".
timeout int | None None Command timeout in seconds.
network bool True Whether network access is allowed.
fs_readonly bool False Whether the root filesystem is read-only.

Why doka?

doka is for teams and developers who want a self-hosted sandbox without the overhead of a cloud service:

  • No API key. Runs on your machine or your server.
  • No usage limits. Run as many sandboxes as your hardware allows.
  • No lock-in. Swap the isolation backend as your security requirements grow.
  • No framework assumptions. Works with any Agent, any stack, any language.

doka

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dokapy-0.1.1.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dokapy-0.1.1-py3-none-any.whl (20.8 kB view details)

Uploaded Python 3

File details

Details for the file dokapy-0.1.1.tar.gz.

File metadata

  • Download URL: dokapy-0.1.1.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dokapy-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6d0ff1b25accb103e405fc05422e389648db68b7b7e6a0ae46870bf562e54298
MD5 3c21e0f2e361f0b48ba4d30df7a86a77
BLAKE2b-256 7ab98460ff6dfa1cbf17e99f66335fca30ac292251ec02eadfddeddb6a344e34

See more details on using hashes here.

Provenance

The following attestation bundles were made for dokapy-0.1.1.tar.gz:

Publisher: publish.yml on zhixiangxue/doka-ai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dokapy-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: dokapy-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 20.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dokapy-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ad19793f0253f996170bbb16c985e7428ffa2a5614a2ae4677900d872ca1b8c0
MD5 e16de1d4ddbc4b41929311ae1da3a829
BLAKE2b-256 25d990229b2cbb21da5582d0bcee7017d0303b070416621bdda5d87af28e05d3

See more details on using hashes here.

Provenance

The following attestation bundles were made for dokapy-0.1.1-py3-none-any.whl:

Publisher: publish.yml on zhixiangxue/doka-ai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page