Skip to main content

Sandbox security, workspace, and harness primitives for AI coding agents

Project description

HarnessBox

Sandbox security, workspace, and harness primitives for AI coding agents.

HarnessBox gives you a single Sandbox class that works across cloud providers (E2B, Docker, Daytona, EC2), configures any agent harness (Claude Code, Codex, Gemini CLI, OpenCode), enforces security policies, and optionally clones a git repo into the workspace with one parameter.

from harnessbox import Sandbox, SecurityPolicy, GitWorkspace

sandbox = Sandbox(
    client="e2b",
    api_key="your-e2b-key",
    security_policy=SecurityPolicy(deny_network=True),
    harness="claude-code",
    workspace=GitWorkspace(
        remote="https://github.com/user/repo.git",
        commit_on_exit=True,
    ),
    files={"/workspace/CLAUDE.md": "You are a helpful coding assistant."},
)

await sandbox.setup()

async for line in sandbox.run_prompt("Fix the failing tests"):
    print(line)

await sandbox.end()  # commits + pushes changes back

Zero runtime dependencies. Stdlib only. Provider SDKs are optional extras.

Install

# From source (until PyPI name is finalized)
pip install -e packages/harnessbox

# With E2B provider
pip install -e "packages/harnessbox[e2b]"

What It Does

┌─────────────────────────────────────────────────────┐
│                    YOUR APPLICATION                   │
│                                                       │
│   from harnessbox import Sandbox, SecurityPolicy,    │
│                          GitWorkspace                 │
└──────────────────────┬────────────────────────────────┘
                       │
          ┌────────────▼────────────┐
          │       HarnessBox        │
          │                         │
          │  SecurityPolicy         │  ← deny rules, credential guards,
          │  HarnessTypeConfig      │    PreToolUse hooks
          │  GitWorkspace           │  ← clone repo, commit on exit,
          │  Sandbox                │    snapshots, diff, events
          └────────────┬────────────┘
                       │
        ┌──────────────┼──────────────┐
        ▼              ▼              ▼
   ┌─────────┐  ┌───────────┐  ┌──────────┐
   │   E2B   │  │  Docker   │  │ Daytona  │  ... any SandboxProvider
   └─────────┘  └───────────┘  └──────────┘

Examples

Basic Sandbox (No Workspace)

from harnessbox import Sandbox, SecurityPolicy

sandbox = Sandbox(
    client="e2b",
    api_key="...",
    harness="claude-code",
    security_policy=SecurityPolicy(
        denied_tools=["WebFetch", "WebSearch", "Agent"],
        deny_network=True,
    ),
    files={"/workspace/CLAUDE.md": "Analyze the code in /workspace."},
)

await sandbox.setup()
async for line in sandbox.run_prompt("What does this codebase do?"):
    print(line)
await sandbox.kill()

Sandbox with Git Workspace

from harnessbox import Sandbox, GitWorkspace

sandbox = Sandbox(
    client="e2b",
    api_key="...",
    harness="claude-code",
    workspace=GitWorkspace(
        remote="https://github.com/user/my-project.git",
        branch="main",
        commit_on_exit=True,
        auth_token="ghp_...",  # for private repos
    ),
)

await sandbox.setup()
# Repo cloned into /workspace. Agent has full git access.

async for line in sandbox.run_prompt("Add error handling to the API routes"):
    print(line)

await sandbox.end()
# Changes committed and pushed to origin/main

Workspace Snapshots and Diff

sandbox = Sandbox(
    client="e2b",
    api_key="...",
    workspace=GitWorkspace(remote="https://github.com/user/repo.git"),
)
await sandbox.setup()

# Checkpoint before a risky change
await sandbox.workspace.snapshot(sandbox.provider, "/workspace", "before-refactor")

async for line in sandbox.run_prompt("Refactor the auth module"):
    print(line)

# See what changed
diff = await sandbox.workspace.diff(sandbox.provider, "/workspace")
print(diff)

# Undo if it went wrong
await sandbox.workspace.restore(sandbox.provider, "/workspace", "before-refactor")

await sandbox.kill()

Push Failure Recovery

sandbox = Sandbox(
    client="e2b",
    api_key="...",
    workspace=GitWorkspace(
        remote="https://github.com/user/repo.git",
        commit_on_exit=True,
    ),
)
await sandbox.setup()
async for _ in sandbox.run_prompt("Make some changes"):
    pass
await sandbox.end()

# If push failed, the committed files are still accessible
if sandbox.unpushed_files:
    print("Push failed. Recovered files:")
    for path, content in sandbox.unpushed_files.items():
        print(f"  {path}: {len(content)} bytes")

Workspace Events

def on_push_failure(error, branch):
    send_slack_alert(f"Push to {branch} failed: {error}")

sandbox = Sandbox(
    client="e2b",
    api_key="...",
    workspace=GitWorkspace(
        remote="https://github.com/user/repo.git",
        commit_on_exit=True,
        on_clone_start=lambda **kw: print(f"Cloning {kw['remote']}..."),
        on_clone_complete=lambda **kw: print(f"Clone {'OK' if kw['success'] else 'FAILED'}"),
        on_push_failure=on_push_failure,
    ),
)

Setup Script

Run a shell command after files and workspace are injected, before the agent launches. Useful for installing dependencies, building assets, or configuring the environment.

sandbox = Sandbox(
    client="e2b",
    api_key="...",
    harness="claude-code",
    workspace=GitWorkspace(remote="https://github.com/user/repo.git"),
    setup_script="cd /workspace && npm install && npm run build",
)

await sandbox.setup()
# 1. Sandbox created, files injected
# 2. Repo cloned
# 3. "npm install && npm run build" runs
# 4. Agent starts with deps installed and assets built

The script runs in the workspace root. If it exits non-zero, setup() raises RuntimeError with the stderr output and the sandbox does not transition to ACTIVE.

Custom Harness Type

from harnessbox import Sandbox, HarnessTypeConfig, register_harness_type

register_harness_type(HarnessTypeConfig(
    name="my-agent",
    config_dir=".myagent",
    settings_file=None,
    hooks_dir=None,
    system_prompt_file="SYSTEM.md",
    default_dirs=("/workspace",),
    cli_command="myagent",
    cli_oneshot_template="myagent run {prompt}",
    cli_interactive_template="myagent",
))

sandbox = Sandbox(client="e2b", api_key="...", harness="my-agent")

Security

HarnessBox generates Claude Code settings.json deny rules and a PreToolUse hook guard that protect credentials inside sandboxes:

Threat Defense
printenv / env / os.environ Bash deny rules + hook guard
Read .env, .aws/credentials Read deny rules
WebFetch exfiltration Tool deny rules
Agent spawning sub-agents Agent deny rules
/proc/self/environ Bash deny rules + hook guard
IMDS credential theft (169.254.169.254) Hook guard regex
Git credential helper leak git config credential.* deny + Read .git/config deny
from harnessbox import SecurityPolicy

policy = SecurityPolicy(
    denied_tools=["WebFetch", "WebSearch", "Agent"],
    denied_bash_patterns=["rm -rf /"],
    deny_network=True,
    include_credential_guards=True,  # on by default
)

Built-in Harness Types

Harness Config Dir System Prompt CLI
claude-code .claude CLAUDE.md claude --dangerously-skip-permissions ...
codex .codex AGENTS.md codex --model o4-mini -q {prompt}
gemini-cli .gemini GEMINI.md gemini -p {prompt}
opencode .opencode AGENTS.md opencode -p {prompt}

Comparison

HarnessBox Cloudflare Artifacts Turso AgentFS Letta MemFS
Focus Harness + security + workspace Managed git repos SQLite filesystem Git-tracked memory
Providers E2B, Docker, Daytona, EC2 Cloudflare only Turso/libSQL Letta platform
Security Deny rules + hooks + credential guards Token-scoped auth N/A N/A
Git Clone any remote into sandbox Managed git protocol N/A Local git tracking
Versioning Full git (branch, diff, snapshot) Full git (fork, clone) SQL queries Git commits
Lock-in None Cloudflare Workers Turso Letta API
Dependencies Zero (stdlib only) Cloudflare SDK Turso SDK Letta SDK

API Reference

Sandbox

Sandbox(
    client: SandboxProvider | str,  # "e2b", "docker", or provider instance
    *,
    security_policy: SecurityPolicy | None = None,
    harness: str = "claude-code",
    env_vars: dict[str, str] | None = None,
    dirs: list[str] | None = None,
    files: dict[str, str] | None = None,
    timeout: int = 300,
    api_key: str | None = None,
    template: str | None = None,
    workspace: Workspace | None = None,
    setup_script: str | None = None,     # shell command to run before agent launch
)

Lifecycle: setup()run_prompt() / start_interactive()end() or kill()

GitWorkspace

GitWorkspace(
    remote: str,                          # HTTPS git remote URL
    *,
    branch: str = "main",
    commit_on_exit: bool = False,         # auto-commit + push on end()
    commit_message: str | None = None,    # default: "harnessbox: auto-commit {timestamp}"
    clone_depth: int | None = None,       # None = full clone
    auth_token: str | None = None,        # HTTPS token (never stored as env var)
    on_clone_start: Callable | None = None,
    on_clone_complete: Callable | None = None,
    on_commit: Callable | None = None,
    on_push_success: Callable | None = None,
    on_push_failure: Callable | None = None,
)

Methods (called via provider):

  • inject(provider, workspace_root) — clone repo
  • extract(provider, workspace_root) — commit + push (if commit_on_exit)
  • snapshot(provider, workspace_root, name) — create named checkpoint
  • restore(provider, workspace_root, name) — revert to checkpoint
  • diff(provider, workspace_root) — unified diff since clone or last snapshot

SecurityPolicy

SecurityPolicy(
    denied_tools: list[str] = [],
    denied_bash_patterns: list[str] = [],
    deny_network: bool = False,
    include_credential_guards: bool = True,
)

Project Structure

packages/harnessbox/
  harnessbox/
    __init__.py          # public API
    sandbox.py           # Sandbox class
    workspace.py         # Workspace protocol, GitWorkspace, MountWorkspace
    providers.py         # SandboxProvider protocol
    harness.py           # HarnessTypeConfig registry
    security.py          # SecurityPolicy, deny rules
    hooks.py             # PreToolUse hook guard
    lifecycle.py         # SessionState machine
    _setup.py            # manifest builder
    _providers/
      e2b.py             # E2B provider
      docker.py          # stub
      daytona.py         # stub
      ec2.py             # stub
  tests/                 # 211 tests

License

MIT

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

harnessbox-0.1.1.tar.gz (26.6 kB view details)

Uploaded Source

Built Distribution

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

harnessbox-0.1.1-py3-none-any.whl (23.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for harnessbox-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d17df7fac7464972e2061097f8401639fa449a04eae834feebd7951bca691f7b
MD5 a86d001afc014a34821bb0c61b30a8f7
BLAKE2b-256 d59cbc92c970143ab80843ecbb0ae0de48098d32b3a476db477a26c1ec30c26b

See more details on using hashes here.

Provenance

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

Publisher: publish.yml on Nikhil-Kadapala/HarnessBox

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

File details

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

File metadata

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

File hashes

Hashes for harnessbox-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 83567831264379ab154c7ed8ba72d7171c7861bd8bd38bbd113a2dbee0e500ca
MD5 2df77894e547fcee4815a2361d1e91d9
BLAKE2b-256 7fb4b8e7e149d1fd664dd122157e19f902ada199f131f11b5da0dcf02689d916

See more details on using hashes here.

Provenance

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

Publisher: publish.yml on Nikhil-Kadapala/HarnessBox

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