Skip to main content
The declaw.openai module plugs declaw into the OpenAI Agents SDK as a sandbox backend. Agent authors keep their existing Agents-SDK code; the only change is handing a DeclawSandboxClient to the runner. Every tool the agent invokes — bash, read_file, write_file, apply_patch, pty_exec_start, etc. — runs inside the VM, with the full declaw security surface applied at the VM’s network boundary.

Install

pip install "declaw[openai]"

Imports

Everything you need is available from a single namespace:
from declaw.openai import (
    # Adapter surface
    DeclawSandboxClient,
    DeclawSandboxClientOptions,
    DeclawSandboxSession,
    DeclawSandboxSessionState,
    DeclawSandboxTimeouts,
    DeclawSandboxType,
    # Security knobs (re-exported from declaw.security)
    SecurityPolicy,
    PIIConfig,
    InjectionDefenseConfig,
    TransformationRule,
    ToxicityConfig,
    CodeSecurityConfig,
    InvisibleTextConfig,
    EnvSecurityConfig,
    AuditConfig,
    # Network + lifecycle
    NetworkPolicy,
    SandboxNetworkOpts,
    SandboxLifecycle,
    ALL_TRAFFIC,
    # Agent-side guardrails helpers
    PIIHandler,
    GuardrailsClient,
)

DeclawSandboxClient

The sandbox-provider class. backend_id = "declaw".
  • await client.create(*, options: DeclawSandboxClientOptions) -> SandboxSession
  • await client.delete(session) -> SandboxSession
  • await client.resume(state: DeclawSandboxSessionState) -> SandboxSession
  • client.deserialize_session_state(payload) -> DeclawSandboxSessionState

DeclawSandboxClientOptions

Pydantic frozen model. Every field declaw’s Sandbox.create accepts is exposed here, plus the individual security sub-configs as convenience shortcuts.
FieldTypeDefaultWhat it controls
templatestr"base"Which preloaded sandbox template to spawn from. See templates.
api_keystr | Nonefrom DECLAW_API_KEYOverride the API key for this client.
domainstr | Nonefrom DECLAW_DOMAINAPI host (e.g. api.declaw.ai).
timeoutint | None300Sandbox lifetime in seconds.
envsdict[str,str]NoneEnvironment variables for the sandbox process.
metadatadict[str,str]NoneCustom labels for audit / routing.
allow_internet_accessboolTrueShorthand for “no egress lockdown”; overridden by network.
securitySecurityPolicyNoneFull security policy — see below.
piiPIIConfigNoneShortcut; overrides security.pii if set.
injection_defenseInjectionDefenseConfigNoneShortcut for security.injection_defense.
transformationslist[TransformationRule]NoneRegex substitution rules.
toxicityToxicityConfigNoneHarmful-content detection.
code_securityCodeSecurityConfigNoneCode-injection scanning in HTTP traffic.
invisible_textInvisibleTextConfigNoneZero-width / hidden-character stripping.
env_securityEnvSecurityConfigNoneEnv-var masking for audit logs.
auditAuditConfigNonePer-sandbox audit toggle.
networkSandboxNetworkOptsNoneallow_out / deny_out / mask_request_host.
lifecycleSandboxLifecycleNoneon_timeout (kill / pause), auto_resume.
timeoutsDeclawSandboxTimeoutsNoneAdapter-internal op timeouts.
Composition rule. If you pass a full SecurityPolicy via security=, we use it. Any per-field shortcut (e.g. pii=PIIConfig(...)) that’s also set overrides the matching sub-field on the composite policy. If neither is set, the sandbox runs with platform defaults.

DeclawSandboxSession

Returned from client.create() and client.resume(). Implements the BaseSandboxSession ABC — _exec_internal, read, write, running, persist_workspace, hydrate_workspace — plus a handful of declaw-specific conveniences:
# Wrapped by agents.sandbox.SandboxSession; unwrap to reach these:
declaw_session: DeclawSandboxSession = session._inner  # or session.inner
await declaw_session.list_snapshots()
await declaw_session.metrics(start=..., end=...)
await declaw_session.pause()
await declaw_session.resume()
declaw_session.underlying_sandbox      # the raw declaw AsyncSandbox

DeclawSandboxSessionState

Serializable state for client.resume(). Carries:
  • sandbox_id: str — to reattach to a live sandbox.
  • snapshot_id: str | None — if set, resume() restores from a memory+disk snapshot (Sandbox.restore), otherwise it reattaches to a still-running sandbox (Sandbox.connect).
  • template: str, created_at: datetime.

Quick start

import asyncio
from agents import Runner
from agents.run import RunConfig
from agents.sandbox import SandboxAgent, SandboxRunConfig
from declaw.openai import (
    DeclawSandboxClient, DeclawSandboxClientOptions,
    SecurityPolicy, PIIConfig, InjectionDefenseConfig, SandboxNetworkOpts,
)

async def main():
    options = DeclawSandboxClientOptions(
        template="python",
        security=SecurityPolicy(
            pii=PIIConfig(enabled=True, action="redact"),
            injection_defense=InjectionDefenseConfig(enabled=True, sensitivity="medium"),
        ),
        network=SandboxNetworkOpts(allow_out=["api.openai.com", "pypi.org"]),
    )

    client = DeclawSandboxClient()
    session = await client.create(options=options)
    try:
        agent = SandboxAgent(name="demo", model="gpt-5.4", instructions="...")
        result = await Runner.run(
            agent,
            "Write 'hello' to /workspace/x.txt and print its byte count.",
            run_config=RunConfig(sandbox=SandboxRunConfig(session=session)),
        )
        print(result.final_output)
    finally:
        await client.delete(session)

asyncio.run(main())

Security — exactly what the core SDK provides

The adapter does not introduce a parallel security path. Whatever you set in SecurityPolicy here is the same policy enforced by the sandbox’s edge proxy for any sandbox — the same six guardrail scanners, the same audit log entries, the same outcome. When the agent’s bash tool runs curl https://api.example.com/?email=alice@acme.com, the request is intercepted and scanned before it reaches the upstream. See Security → Overview for the full scanner list and policy reference.

Session resume

persist_workspace creates a declaw snapshot of memory + disk; the returned session state carries snapshot_id which client.resume() uses to restore the exact VM state later — in a different process, on a different machine, or across a cluster restart. Snapshots are persisted to the platform’s blob store (GCS in our managed cloud).

See also