HarnessBox
Run AI coding agents in secure sandbox environments with workspace orchestration, auto-pause, and multi-session support.
import os
from harnessbox import HarnessBox
async with HarnessBox(
provider="e2b",
harness="claude-code",
secrets={
"provider_api_key": os.getenv("E2B_API_KEY"),
"harness_secrets": {"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY")},
},
) as hb:
async for event in hb.send_message("Fix the failing test"):
print(event.delta or "", end="")
HarnessBox is the sole public API — provision sandboxes, manage workspaces, run agent sessions. Zero runtime dependencies.
Install
pip install harnessbox
# With E2B provider
pip install "harnessbox[e2b]"
Quickstart
import os
from harnessbox import HarnessBox, GitWorkspace
hb = HarnessBox(
provider="e2b",
harness="claude-code",
secrets={
"provider_api_key": os.getenv("E2B_API_KEY"),
"harness_secrets": {"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY")},
},
workspace=GitWorkspace(
remote="https://github.com/user/repo.git",
branch="main",
commit_on_exit=True,
),
)
sandbox_id = await hb.create()
async for event in hb.send_message("Fix the tests"):
print(event.delta or "", end="")
await hb.kill()
How It Works
HarnessBox is a Python library. You import it, provision a sandbox, and stream agent output. That's the whole product.
from harnessbox import HarnessBox
hb = HarnessBox(provider="e2b", harness="claude-code", secrets={...})
await hb.create()
async for event in hb.send_message("Fix the failing test"):
print(event.delta or "", end="")
await hb.kill()
Everything else is a deployment choice:
┌────────────────────────────────────────────────────────────┐
│ HarnessBox (Python SDK) │
│ │
│ • Create workspaces and sessions │
│ • Stream agent output as async events │
│ • Auto-pause idle sandboxes, resume on next message │
│ • Persist state across restarts (SQLite) │
│ • Security policies, credential guards │
└─────────────────────┬───────────────────┬──────────────────┘
│ │
"I'm a script │ │ "I need a web UI
or service" │ │ or team access"
▼ ▼
┌─────────────────┐ ┌────────────────────────────┐
│ Use the SDK │ │ Run `harnessbox serve` │
│ directly │ │ (same SDK + HTTP/SSE) │
│ │ │ │
│ No server. │ │ Adds: multi-client, │
│ No infra. │ │ web dashboard, shared │
│ Just Python. │ │ state across consumers. │
└─────────────────┘ └────────────────────────────┘
Think of it like SQLite vs Postgres. SQLite is embedded — no server, works great for one process. Postgres adds a server for shared access. Same SQL, same data model, different deployment. HarnessBox works the same way.
When you don't need the server:
- Scripts and CI pipelines
- Single-developer tools
- Programmatic agents (backend services)
- Anything where one Python process is enough
When you add the server:
- You're building a web UI for your team
- Multiple clients (web + CLI + SDK) need to see the same workspaces
- You want an always-on orchestrator that survives process restarts
- You're running our hosted platform (
base_url="https://api.harnessbox.dev")
Server
The server is the SDK running as a long-lived process that accepts HTTP connections. Same features, accessible over the network.
# Self-hosted
pip install "harnessbox[server]"
harnessbox serve --port 8080
# Or with Docker
docker run -p 8080:8080 harnessbox/server
Point the SDK at your server (planned for v0.4.0):
# SDK becomes a thin client — all orchestration happens server-side
hb = HarnessBox(base_url="http://localhost:8080", secrets={...})
# Same API, same streaming, same everything
Server endpoints:
POST /v1/workspaces— create workspaceGET /v1/workspaces— list workspacesDELETE /v1/workspaces/{id}— destroy workspacePOST /v1/workspaces/{id}/prompt— send prompt (SSE stream)GET /v1/workspaces/{id}/events— subscribe to live events (SSE)
Security
HarnessBox generates agent-specific deny rules and PreToolUse hook guards 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 |
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} |
opencode |
.opencode |
AGENTS.md |
opencode -p {prompt} |
Key Features
| Feature | Description |
|---|---|
| Auto-pause/resume | Idle workspaces pause → $0/hr. Resume transparently on next message. |
| Multi-session | Multiple concurrent agent sessions per workspace. |
| Branch-based pooling | Same (remote, branch) reuses existing workspace. |
| Security policies | Credential guards, tool deny lists, network blocking. |
| Git workflows | Clone, commit, push on exit. Branch creation from base. |
| Zero dependencies | Stdlib only at runtime. Provider SDKs are optional extras. |
| Any provider | E2B, Docker, Daytona, EC2. Protocol-based extensibility. |
API Reference
HarnessBox
from harnessbox import HarnessBox, HarnessBoxSecrets
hb = HarnessBox(
provider="e2b", # Provider name or instance
harness="claude-code", # Agent harness type
api_key="hb_live_...", # Platform key (None = self-hosted)
secrets=HarnessBoxSecrets( # Or pass as dict
provider_api_key="e2b_...",
harness_secrets={"ANTHROPIC_API_KEY": "sk-ant-..."},
),
model="claude-sonnet-4-6-20250514",
system_prompt=Path("CLAUDE.md"), # Path to load from file, or str for inline content
workspace=GitWorkspace(...),
security_policy=SecurityPolicy(...),
setup_script="npm install",
timeout=300,
)
# Lifecycle
sandbox_id = await hb.create()
async for event in hb.send_message("Fix tests"):
print(event.delta)
response = await hb.send_message("Fix tests", stream=False)
result = await hb.run_command("pytest")
await hb.write_file("/workspace/f.py", "content")
content = await hb.read_file("/workspace/f.py")
await hb.kill()
# Context manager (auto create + kill)
async with HarnessBox(provider="e2b") as hb:
async for event in hb.send_message("Hello"):
print(event.delta)
GitWorkspace
GitWorkspace(
remote: str, # HTTPS git remote URL
*,
branch: str = "main",
base_branch: str | None = None, # Branch to fork from
commit_on_exit: bool = False,
commit_message: str | None = None,
clone_depth: int | None = None,
auth_token: str | None = None, # Never stored as env var
)
SecurityPolicy
SecurityPolicy(
denied_tools: list[str] = [],
denied_bash_patterns: list[str] = [],
deny_network: bool = False,
include_credential_guards: bool = True,
)
Project Structure
harnessbox/
__init__.py # public API
harnessbox.py # HarnessBox — sole public entry point
workspace_manager.py # internal workspace orchestration
agent_manager.py # internal agent lifecycle
sandbox.py # internal sandbox orchestration
workspace.py # Workspace protocol, GitWorkspace
providers.py # SandboxProvider protocol
lifecycle.py # WorkspaceState machine
storage.py # StorageBackend protocol
streaming.py # UniversalEvent, StreamParser
events.py # EventBuffer (SSE replay)
server.py # HTTP/SSE transport
config/
harness.py # HarnessTypeConfig registry
manifest.py # SandboxManifest builder
security/
policy.py # SecurityPolicy, deny rules
hooks.py # PreToolUse hook guard
events.py # SandboxEvent, EventHandler
_providers/
e2b.py # E2B provider
_storage/
sqlite.py # SQLite backend
memory.py # In-memory backend
tests/ # 651 tests
License
MIT
Release files for harnessbox 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| harnessbox-0.3.0.tar.gz | 187.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| harnessbox-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:288.7 kB
Release files / harnessbox-0.3.0.tar.gz
| Download URL | harnessbox-0.3.0.tar.gz |
|---|---|
| Size | 187.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b50bd8f677c30bad41b13a887f7c4e34776de109f869956d6e8c957af0319dfe
|
|
BLAKE2b-256 checksum How to use checksums |
4075dccad525e60686c1f6eae2b084138b31f3dbda647e1bb28c6c0daf37c9f5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency logRelease files / harnessbox-0.3.0-py3-none-any.whl
| Download URL | harnessbox-0.3.0-py3-none-any.whl |
|---|---|
| Size | 101.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7e6d4e2f8adf624f8c849467ba0203e6d0c952331a325304cdb7d42d6a91f560
|
|
BLAKE2b-256 checksum How to use checksums |
c052483a3fef5af4e37f6d06f394054f0ba7355b1298e0ae3f9b92fb1ed187c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 19, 2026.
Transparency log