CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-claude-agent-sdk

Python SDK for Claude Code enabling developers to build AI-powered applications and agents with support for custom tools, hooks, and bidirectional interactive conversations

Moderation error
Malicious code detected in tile.json: This tile describes a package named 'claude-agent-sdk' on PyPI, which appears to be typosquatting/impersonating official Anthropic SDK packages. The legitimate Anthropic Python SDK is 'anthropic', not 'claude-agent-sdk'. This naming pattern (claude-agent-sdk) is designed to deceive developers into installing a potentially malicious package by mimicking official Anthropic/Claude branding. This is a classic supply chain attack vector through package name confusion.
Overview
Eval results
Files

sandbox.mddocs/reference/

Sandbox Configuration

Configure bash command sandboxing for filesystem and network isolation on macOS and Linux. The sandbox provides security boundaries for code execution, allowing control over which commands run inside/outside the sandbox, network access configuration, and violation handling.

Capabilities

Sandbox Settings

Main configuration for bash command sandboxing.

class SandboxSettings(TypedDict, total=False):
    enabled: bool
    autoAllowBashIfSandboxed: bool
    excludedCommands: list[str]
    allowUnsandboxedCommands: bool
    network: SandboxNetworkConfig
    ignoreViolations: SandboxIgnoreViolations
    enableWeakerNestedSandbox: bool

Fields:

  • enabled: Enable bash sandboxing (macOS/Linux only, default: False)
  • autoAllowBashIfSandboxed: Auto-approve bash commands when sandboxed (default: True)
  • excludedCommands: Commands that run outside sandbox (e.g., ["git", "docker"])
  • allowUnsandboxedCommands: Allow commands to bypass via dangerouslyDisableSandbox (default: True)
  • network: Network configuration for sandbox
  • ignoreViolations: Violations to ignore
  • enableWeakerNestedSandbox: Enable weaker sandbox for unprivileged Docker (Linux only, default: False)

Important: Filesystem and network restrictions are configured via permission rules, not sandbox settings:

  • Filesystem read restrictions: Use Read deny rules
  • Filesystem write restrictions: Use Edit allow/deny rules
  • Network restrictions: Use WebFetch allow/deny rules

Usage:

from claude_agent_sdk import ClaudeAgentOptions, SandboxSettings

sandbox: SandboxSettings = {
    "enabled": True,
    "autoAllowBashIfSandboxed": True,
    "excludedCommands": ["docker", "git"],
    "allowUnsandboxedCommands": False,
    "network": {
        "allowUnixSockets": ["/var/run/docker.sock"],
        "allowLocalBinding": True
    }
}

options = ClaudeAgentOptions(
    sandbox=sandbox,
    permission_mode="acceptEdits"
)

Network Configuration

Network access settings for sandboxed commands.

class SandboxNetworkConfig(TypedDict, total=False):
    allowUnixSockets: list[str]
    allowAllUnixSockets: bool
    allowLocalBinding: bool
    httpProxyPort: int
    socksProxyPort: int

Fields:

  • allowUnixSockets: Unix socket paths accessible in sandbox (e.g., SSH agents, Docker)
  • allowAllUnixSockets: Allow all Unix sockets (less secure)
  • allowLocalBinding: Allow binding to localhost ports (macOS only)
  • httpProxyPort: HTTP proxy port if bringing your own proxy
  • socksProxyPort: SOCKS5 proxy port if bringing your own proxy

Usage:

from claude_agent_sdk import SandboxNetworkConfig

# Allow specific Unix sockets
network: SandboxNetworkConfig = {
    "allowUnixSockets": [
        "/var/run/docker.sock",
        "/run/user/1000/ssh-agent.socket"
    ],
    "allowLocalBinding": True
}

# Allow all Unix sockets (less secure)
network_permissive: SandboxNetworkConfig = {
    "allowAllUnixSockets": True,
    "allowLocalBinding": True
}

# Custom proxy configuration
network_proxy: SandboxNetworkConfig = {
    "httpProxyPort": 8080,
    "socksProxyPort": 1080
}

Ignore Violations

Configure which sandbox violations to ignore.

class SandboxIgnoreViolations(TypedDict, total=False):
    file: list[str]
    network: list[str]

Fields:

  • file: File paths for which violations should be ignored
  • network: Network hosts for which violations should be ignored

Usage:

from claude_agent_sdk import SandboxIgnoreViolations

ignore: SandboxIgnoreViolations = {
    "file": [
        "/tmp/safe-temp-dir",
        "/home/user/.cache"
    ],
    "network": [
        "trusted-internal-host.local",
        "192.168.1.100"
    ]
}

sandbox: SandboxSettings = {
    "enabled": True,
    "ignoreViolations": ignore
}

Complete Sandbox Examples

Example 1: Basic Sandbox Setup

import anyio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": []  # All commands run in sandbox
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        permission_mode="acceptEdits"
    )

    async for message in query(
        prompt="Run some bash commands to explore the system",
        options=options
    ):
        print(message)

anyio.run(main)

Example 2: Docker Development Environment

import anyio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def main():
    # Allow Docker but sandbox everything else
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": ["docker", "docker-compose"],
        "allowUnsandboxedCommands": False,
        "network": {
            "allowUnixSockets": ["/var/run/docker.sock"],
            "allowLocalBinding": True
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        cwd="/workspace"
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Build and run the Docker containers")
        async for msg in client.receive_response():
            print(msg)

anyio.run(main)

Example 3: CI/CD Sandbox

import anyio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    # Strict sandbox for CI/CD environments
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": ["git"],  # Only git runs outside
        "allowUnsandboxedCommands": False,  # No bypass allowed
        "network": {
            "allowLocalBinding": False,
            "allowUnixSockets": []
        },
        "ignoreViolations": {
            "file": ["/tmp/build-cache"],
            "network": []
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        permission_mode="acceptEdits",
        allowed_tools=["Bash", "Read", "Write"]
    )

    async for message in query(
        prompt="Run the build process",
        options=options
    ):
        print(message)

anyio.run(main)

Example 4: Development with SSH and Git

import anyio
import os
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def main():
    # Allow SSH agent for git operations
    ssh_socket = os.environ.get("SSH_AUTH_SOCK", "")

    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": ["git", "ssh", "ssh-add"],
        "network": {
            "allowUnixSockets": [ssh_socket] if ssh_socket else [],
            "allowLocalBinding": True
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        permission_mode="acceptEdits"
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Clone the repository and make changes")
        async for msg in client.receive_response():
            print(msg)

anyio.run(main)

Example 5: Web Development Environment

import anyio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def main():
    # Allow localhost binding for dev servers
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": ["npm", "node", "yarn", "pnpm"],
        "allowUnsandboxedCommands": True,
        "network": {
            "allowLocalBinding": True,
            "allowUnixSockets": []
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        cwd="/project"
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Start the development server")
        async for msg in client.receive_response():
            print(msg)

anyio.run(main)

Example 6: Nested Docker Sandbox

import anyio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    # Enable weaker sandbox for unprivileged Docker (Linux only)
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": ["docker"],
        "enableWeakerNestedSandbox": True,  # For unprivileged containers
        "network": {
            "allowUnixSockets": ["/var/run/docker.sock"],
            "allowLocalBinding": True
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        permission_mode="acceptEdits"
    )

    async for message in query(
        prompt="Work with Docker containers",
        options=options
    ):
        print(message)

anyio.run(main)

Example 7: Permissive Development Sandbox

import anyio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def main():
    # More permissive for local development
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": ["docker", "git", "npm", "make"],
        "allowUnsandboxedCommands": True,  # Allow bypass when needed
        "network": {
            "allowAllUnixSockets": True,
            "allowLocalBinding": True
        },
        "ignoreViolations": {
            "file": ["/tmp", "/var/tmp"],
            "network": ["localhost", "127.0.0.1"]
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        cwd="/home/user/projects"
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Set up the development environment")
        async for msg in client.receive_response():
            print(msg)

anyio.run(main)

Example 8: Sandbox with Custom Proxy

import anyio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    # Use custom proxy for network access
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "network": {
            "httpProxyPort": 8888,
            "socksProxyPort": 1080,
            "allowLocalBinding": False
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        permission_mode="acceptEdits"
    )

    async for message in query(
        prompt="Download and process data",
        options=options
    ):
        print(message)

anyio.run(main)

Example 9: Strict Security Sandbox

import anyio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    # Maximum security - minimal access
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": True,
        "excludedCommands": [],  # Everything in sandbox
        "allowUnsandboxedCommands": False,  # No bypass allowed
        "network": {
            "allowUnixSockets": [],
            "allowAllUnixSockets": False,
            "allowLocalBinding": False
        },
        "ignoreViolations": {
            "file": [],
            "network": []
        },
        "enableWeakerNestedSandbox": False
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        permission_mode="default",  # Require permission for everything
        allowed_tools=["Read", "Bash"]
    )

    async for message in query(
        prompt="Analyze the files in a safe manner",
        options=options
    ):
        print(message)

anyio.run(main)

Example 10: Combined Sandbox and Permissions

import anyio
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    PermissionResultAllow,
    PermissionResultDeny
)

async def permission_callback(tool_name, tool_input, context):
    # Additional permission layer on top of sandbox
    if tool_name == "Bash":
        command = tool_input.get("command", "")

        # Block dangerous commands even in sandbox
        if any(p in command for p in ["curl", "wget", "nc"]):
            return PermissionResultDeny(
                behavior="deny",
                message="Network commands blocked",
                interrupt=False
            )

    return PermissionResultAllow(behavior="allow")

async def main():
    sandbox = {
        "enabled": True,
        "autoAllowBashIfSandboxed": False,  # Still use permission callback
        "excludedCommands": ["git"],
        "network": {
            "allowLocalBinding": True
        }
    }

    options = ClaudeAgentOptions(
        sandbox=sandbox,
        can_use_tool=permission_callback,
        allowed_tools=["Bash", "Read", "Write"]
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Work on the project")
        async for msg in client.receive_response():
            print(msg)

anyio.run(main)

Platform Support

Supported Platforms:

  • macOS: Full sandbox support
  • Linux: Full sandbox support (use enableWeakerNestedSandbox for unprivileged Docker)
  • Windows: Sandbox not supported (settings ignored)

Network Features:

  • allowLocalBinding: macOS only
  • enableWeakerNestedSandbox: Linux only

Best Practices:

  • Enable sandbox for production or untrusted environments
  • Use excludedCommands sparingly for tools that don't work in sandbox
  • Set allowUnsandboxedCommands: False in strict security contexts
  • Combine sandbox with permission callbacks for defense in depth
  • Use ignoreViolations carefully - only for known-safe paths/hosts

Install with Tessl CLI

npx tessl i tessl/pypi-claude-agent-sdk@0.1.3

docs

index.md

tile.json