Sandbox security, workspace, and harness primitives for AI coding agents
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file harnessbox-0.3.0.tar.gz.
File metadata
- Download URL: harnessbox-0.3.0.tar.gz
- Upload date:
- Size: 187.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b50bd8f677c30bad41b13a887f7c4e34776de109f869956d6e8c957af0319dfe
|
|
| MD5 |
a4041345dc1fe61bfe07d4376393cfde
|
|
| BLAKE2b-256 |
4075dccad525e60686c1f6eae2b084138b31f3dbda647e1bb28c6c0daf37c9f5
|
Provenance
The following attestation bundles were made for harnessbox-0.3.0.tar.gz:
Publisher:
publish.yml on Nikhil-Kadapala/HarnessBox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
harnessbox-0.3.0.tar.gz -
Subject digest:
b50bd8f677c30bad41b13a887f7c4e34776de109f869956d6e8c957af0319dfe - Sigstore transparency entry: 1575157058
- Sigstore integration time:
-
Permalink:
Nikhil-Kadapala/HarnessBox@04513614c6b1c7a1cbbe4086daf7630403936f43 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Nikhil-Kadapala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@04513614c6b1c7a1cbbe4086daf7630403936f43 -
Trigger Event:
release
-
Statement type:
File details
Details for the file harnessbox-0.3.0-py3-none-any.whl.
File metadata
- Download URL: harnessbox-0.3.0-py3-none-any.whl
- Upload date:
- Size: 101.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e6d4e2f8adf624f8c849467ba0203e6d0c952331a325304cdb7d42d6a91f560
|
|
| MD5 |
09f90b08c398dc2fd675826d07ca36a1
|
|
| BLAKE2b-256 |
c052483a3fef5af4e37f6d06f394054f0ba7355b1298e0ae3f9b92fb1ed187c2
|
Provenance
The following attestation bundles were made for harnessbox-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on Nikhil-Kadapala/HarnessBox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
harnessbox-0.3.0-py3-none-any.whl -
Subject digest:
7e6d4e2f8adf624f8c849467ba0203e6d0c952331a325304cdb7d42d6a91f560 - Sigstore transparency entry: 1575157086
- Sigstore integration time:
-
Permalink:
Nikhil-Kadapala/HarnessBox@04513614c6b1c7a1cbbe4086daf7630403936f43 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Nikhil-Kadapala
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@04513614c6b1c7a1cbbe4086daf7630403936f43 -
Trigger Event:
release
-
Statement type: