Skip to main content
A runnable example that swaps the agent’s execution backend to declaw. Every tool call the agent makes (bash, file I/O, PTY) runs inside the sandbox, with declaw’s security policy enforced at the VM’s network boundary.

What you’ll learn

  • Installing the integration with pip install "declaw[openai]"
  • Wiring a DeclawSandboxClient into the Agents SDK’s Runner
  • Enabling PII + prompt-injection scanning and a network allowlist from the same SecurityPolicy surface you use with the core SDK

Prerequisites

export DECLAW_API_KEY="your-api-key"
export DECLAW_DOMAIN="your-declaw-instance.example.com:8080"
Also:
export OPENAI_API_KEY="sk-..."
pip install "declaw[openai]"

Code

import asyncio
import os
import sys

from agents import Runner
from agents.run import RunConfig
from agents.sandbox import SandboxAgent, SandboxRunConfig

from declaw.openai import (
    DeclawSandboxClient,
    DeclawSandboxClientOptions,
    InjectionDefenseConfig,
    PIIConfig,
    SandboxNetworkOpts,
    SecurityPolicy,
)


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

    client = DeclawSandboxClient()
    session = await client.create(options=options)
    try:
        agent = SandboxAgent(
            name="quickstart",
            model="gpt-5.4",
            instructions="You are a helpful coding agent.",
        )
        result = await Runner.run(
            agent,
            "Create /workspace/notes.md with 'hello from declaw', then "
            "run `wc -c /workspace/notes.md` and report the byte count.",
            run_config=RunConfig(sandbox=SandboxRunConfig(session=session)),
        )
        print(result.final_output)
    finally:
        await client.delete(session)


if __name__ == "__main__":
    asyncio.run(main())

Expected output

I've written the file and measured it:
- /workspace/notes.md — 18 bytes
(Content will vary slightly — the agent may add a trailing newline or re-format the sentence.)

How the security policy applies

Everything inside SecurityPolicy(...) is enforced by the sandbox’s edge proxy, not by the adapter:
  • pii=PIIConfig(enabled=True, action="redact") — any outbound HTTP request the agent’s tool code makes that contains PII has the matches replaced with REDACTED_* tokens before the request reaches the upstream. Responses are rehydrated transparently so the sandbox program keeps working.
  • injection_defense=InjectionDefenseConfig(enabled=True, sensitivity="medium") — any outbound payload is scanned for prompt-injection patterns.
  • SandboxNetworkOpts(allow_out=[...]) — the allowlist is enforced at the network namespace level; any outbound connection to a host not in the list is dropped.
None of this lives in the adapter code — you’re using the exact same SecurityPolicy surface as Sandbox.create(security=...) in the core SDK.

Next steps