{"id":43407801,"url":"https://github.com/sshh12/modal-claude-agent-sdk-python","last_synced_at":"2026-02-02T16:17:44.433Z","repository":{"id":333391009,"uuid":"1137020878","full_name":"sshh12/modal-claude-agent-sdk-python","owner":"sshh12","description":"This package wraps the Claude Agent SDK to execute AI agents in secure, scalable Modal containers. It provides progressive complexity—simple usage mirrors the original Agent SDK, while advanced features expose Modal's full capabilities (GPU, volumes, image customization, etc.).","archived":false,"fork":false,"pushed_at":"2026-01-19T06:12:45.000Z","size":160,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-19T10:17:44.927Z","etag":null,"topics":["agent","agents-sdk","anthropic","claude","modal","sandbox"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sshh12.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-18T19:15:57.000Z","updated_at":"2026-01-19T06:12:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sshh12/modal-claude-agent-sdk-python","commit_stats":null,"previous_names":["sshh12/modal-claude-agent-sdk-python"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sshh12/modal-claude-agent-sdk-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sshh12%2Fmodal-claude-agent-sdk-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sshh12%2Fmodal-claude-agent-sdk-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sshh12%2Fmodal-claude-agent-sdk-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sshh12%2Fmodal-claude-agent-sdk-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sshh12","download_url":"https://codeload.github.com/sshh12/modal-claude-agent-sdk-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sshh12%2Fmodal-claude-agent-sdk-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29015147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T16:17:30.374Z","status":"ssl_error","status_checked_at":"2026-02-02T15:58:50.469Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","agents-sdk","anthropic","claude","modal","sandbox"],"created_at":"2026-02-02T16:17:42.469Z","updated_at":"2026-02-02T16:17:44.428Z","avatar_url":"https://github.com/sshh12.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Modal Agents SDK\n\n\u003e **Disclaimer**: This is an unofficial community package. It is not affiliated with, endorsed by, or associated with Anthropic or Modal in any way.\n\nRun [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-python) agents in [Modal](https://modal.com) sandboxes.\n\nThis package wraps the Claude Agent SDK to execute AI agents in secure, scalable Modal containers. It provides progressive complexity—simple usage mirrors the original Agent SDK, while advanced features expose Modal's full capabilities (GPU, volumes, image customization, etc.).\n\n## Features\n\n| Feature | modal-agents-sdk | claude-agent-sdk |\n|---------|-----------------|------------------|\n| Sandboxed execution | ✅ Modal containers | ❌ Local only |\n| GPU support | ✅ A10G, H100, A100, etc. | ❌ |\n| Persistent storage | ✅ Modal Volumes | ❌ |\n| Custom images | ✅ Docker/Dockerfile | ❌ |\n| Network isolation | ✅ Configurable | ❌ |\n| Auto-scaling | ✅ Built-in | ❌ |\n| Built-in tools | ✅ Read, Write, Bash, etc. | ✅ |\n| MCP servers | ✅ | ✅ |\n| Host-side hooks | ✅ Intercept tool calls | ✅ |\n| Host-side tools | ✅ Run on local machine | ✅ |\n| Multi-turn conversations | ✅ | ✅ |\n\n## Installation\n\n```bash\npip install modal-agents-sdk\n```\n\n### Prerequisites\n\n1. **Modal account**: Sign up at [modal.com](https://modal.com)\n2. **Modal CLI**: Install and authenticate\n   ```bash\n   pip install modal\n   modal setup\n   ```\n3. **Anthropic API key**: Create a Modal secret\n   ```bash\n   modal secret create anthropic-key ANTHROPIC_API_KEY=sk-ant-...\n   ```\n\n## Quick Start\n\n```python\nimport asyncio\nfrom modal_agents_sdk import query\n\nasync def main():\n    async for message in query(\"What is 2 + 2?\"):\n        print(message)\n\nasyncio.run(main())\n```\n\n## Basic Usage: `query()`\n\n`query()` is an async function for querying Claude in a Modal sandbox. It returns an `AsyncIterator` of response messages.\n\n```python\nfrom modal_agents_sdk import query, ModalAgentOptions, AssistantMessage, TextBlock\nimport modal\n\n# Simple query\nasync for message in query(prompt=\"Hello Claude\"):\n    if isinstance(message, AssistantMessage):\n        for block in message.content:\n            if isinstance(block, TextBlock):\n                print(block.text)\n\n# With options\noptions = ModalAgentOptions(\n    system_prompt=\"You are a helpful assistant\",\n    max_turns=3,\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n\nasync for message in query(prompt=\"Tell me a joke\", options=options):\n    print(message)\n```\n\n## Using Tools\n\n```python\noptions = ModalAgentOptions(\n    allowed_tools=[\"Read\", \"Write\", \"Bash\"],\n    permission_mode=\"acceptEdits\",  # auto-accept file edits\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n\nasync for message in query(prompt=\"Create a hello.py file\", options=options):\n    pass\n```\n\n## Working Directory\n\n```python\nfrom pathlib import Path\n\noptions = ModalAgentOptions(\n    cwd=\"/workspace/myproject\",  # or Path(\"/workspace/myproject\")\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n```\n\n## GPU Compute\n\n```python\noptions = ModalAgentOptions(\n    gpu=\"A10G\",  # or \"H100\", \"A100-80GB:2\", etc.\n    memory=16384,  # 16 GB\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n```\n\n## Persistent Storage\n\n```python\nimport modal\n\ndata_volume = modal.Volume.from_name(\"my-data\", create_if_missing=True)\n\noptions = ModalAgentOptions(\n    volumes={\"/data\": data_volume},\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n\n# Files written to /data persist across sandbox executions\n```\n\n## Custom Image\n\n```python\nfrom modal_agents_sdk import ModalAgentImage\n\nimage = (\n    ModalAgentImage.default()\n    .pip_install(\"pandas\", \"numpy\", \"scikit-learn\")\n    .apt_install(\"ffmpeg\")\n    .run_commands(\"npm install -g typescript\")\n)\n\noptions = ModalAgentOptions(\n    image=image,\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n```\n\n## Network Restrictions\n\nThe agent requires network access to call the Anthropic API. Use `cidr_allowlist` to restrict access while allowing the API:\n\n```python\n# Anthropic API CIDR (required): 160.79.104.0/23\n# Source: https://docs.anthropic.com/en/api/ip-addresses\n\noptions = ModalAgentOptions(\n    cidr_allowlist=[\"160.79.104.0/23\"],  # Anthropic API only\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n```\n\n**Note:** `block_network=True` is not supported as it would prevent API calls.\n\n## `ModalAgentClient`\n\n`ModalAgentClient` supports multi-turn conversations:\n\n```python\nfrom modal_agents_sdk import ModalAgentClient, ModalAgentOptions\nimport modal\n\noptions = ModalAgentOptions(\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n\nasync with ModalAgentClient(options=options) as client:\n    await client.query(\"Create a Python project structure\")\n    async for msg in client.receive_response():\n        print(msg)\n\n    # Follow-up (maintains context)\n    await client.query(\"Now add a requirements.txt\")\n    async for msg in client.receive_response():\n        print(msg)\n```\n\n## MCP Servers\n\n```python\noptions = ModalAgentOptions(\n    mcp_servers={\n        \"filesystem\": {\n            \"command\": \"npx\",\n            \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/workspace\"],\n        },\n    },\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n```\n\n## Host-Side Hooks\n\nIntercept and control tool calls from your local machine while the agent runs in the sandbox:\n\n```python\nfrom modal_agents_sdk import (\n    ModalAgentHooks,\n    PreToolUseHookInput,\n    PreToolUseHookResult,\n    ModalAgentOptions,\n)\n\nasync def block_dangerous_commands(input: PreToolUseHookInput) -\u003e PreToolUseHookResult:\n    \"\"\"Block dangerous bash commands before execution.\"\"\"\n    if input.tool_name == \"Bash\" and \"rm -rf\" in input.tool_input.get(\"command\", \"\"):\n        return PreToolUseHookResult(\n            decision=\"deny\",\n            reason=\"Blocked dangerous command\",\n        )\n    return PreToolUseHookResult(decision=\"allow\")\n\nhooks = ModalAgentHooks(\n    pre_tool_use=[block_dangerous_commands],\n    tool_filter=\"Bash|Write|Edit\",  # Only intercept these tools\n)\n\noptions = ModalAgentOptions(\n    host_hooks=hooks,\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n```\n\n## Host-Side Tools\n\nDefine custom tools that run on your local machine but can be called by the agent in the sandbox:\n\n```python\nfrom modal_agents_sdk import host_tool, HostToolServer, ModalAgentOptions\nimport os\n\n@host_tool(\n    name=\"get_secret\",\n    description=\"Retrieve a secret from local environment\",\n    input_schema={\"key\": str},\n)\nasync def get_secret(args):\n    \"\"\"Access local environment variables not available in sandbox.\"\"\"\n    value = os.environ.get(args[\"key\"], \"\")\n    return {\"content\": [{\"type\": \"text\", \"text\": f\"Secret value: {value}\"}]}\n\nserver = HostToolServer(name=\"local-tools\", tools=[get_secret])\n\noptions = ModalAgentOptions(\n    host_tools=[server],\n    secrets=[modal.Secret.from_name(\"anthropic-key\")],\n)\n\n# Agent can now call get_secret to access your local environment\nasync for message in query(\"Get the DATABASE_URL secret\", options=options):\n    print(message)\n```\n\n### Modal Functions as Tools\n\nExpose deployed Modal functions as host tools to offload compute-intensive work to separate Modal containers:\n\n```python\n# modal_compute_functions.py - Deploy separately with: modal deploy modal_compute_functions.py\nimport modal\n\napp = modal.App(\"agent-compute-tools\")\n\n@app.function()\ndef compute_fibonacci(n: int) -\u003e dict:\n    def fib(x): return x if x \u003c= 1 else fib(x-1) + fib(x-2)\n    return {\"fibonacci\": fib(n), \"n\": n}\n```\n\n```python\n# main.py - Run after deploying the Modal function\nimport modal\nfrom modal_agents_sdk import HostTool, HostToolServer, ModalAgentOptions, query\n\nasync def fibonacci_handler(args: dict) -\u003e dict:\n    func = modal.Function.from_name(\"agent-compute-tools\", \"compute_fibonacci\")\n    result = await func.remote.aio(n=args[\"n\"])\n    import json\n    return {\"content\": [{\"type\": \"text\", \"text\": json.dumps(result)}]}\n\ntool = HostTool(\n    name=\"compute_fibonacci\",\n    description=\"Compute the nth Fibonacci number\",\n    input_schema={\"type\": \"object\", \"properties\": {\"n\": {\"type\": \"integer\"}}, \"required\": [\"n\"]},\n    handler=fibonacci_handler,\n)\n\nserver = HostToolServer(name=\"compute-tools\", tools=[tool])\noptions = ModalAgentOptions(host_tools=[server], secrets=[modal.Secret.from_name(\"anthropic-key\")])\n\nasync for message in query(\"Calculate fibonacci(20)\", options=options):\n    print(message)\n```\n\n## Types\n\nSee `src/modal_agents_sdk/_types.py` for complete type definitions. Key types are re-exported from `claude-agent-sdk`:\n\n- `AssistantMessage`, `UserMessage`, `SystemMessage`, `ResultMessage` - Message types\n- `TextBlock`, `ToolUseBlock`, `ToolResultBlock`, `ThinkingBlock` - Content blocks\n\n## Error Handling\n\n```python\nfrom modal_agents_sdk import (\n    ModalAgentError,        # Base error\n    SandboxCreationError,   # Failed to create sandbox\n    SandboxTimeoutError,    # Execution timed out\n    SandboxTerminatedError, # Sandbox terminated\n    ImageBuildError,        # Image build failed\n    CLINotInstalledError,   # claude-agent-sdk not in image\n    AgentExecutionError,    # Agent execution failed\n)\n\ntry:\n    async for message in query(prompt=\"Hello\", options=options):\n        pass\nexcept SandboxTimeoutError:\n    print(\"Execution timed out\")\nexcept AgentExecutionError as e:\n    print(f\"Agent failed: exit code {e.exit_code}\")\n```\n\n## Examples\n\nSee the `examples/` directory for complete working examples:\n\n### Getting Started\n- `quick_start.py` - Basic usage with message type handling\n- `multi_turn.py` - Multi-turn conversations with `ModalAgentClient`\n\n### Infrastructure \u0026 Resources\n- `custom_image.py` - Custom container images with pip/apt packages\n- `gpu_compute.py` - GPU-enabled agents (A10G, CUDA, PyTorch)\n- `resource_limits.py` - CPU, memory, and timeout configuration\n- `cloud_region.py` - Cloud provider and region selection (AWS, GCP)\n\n### Storage \u0026 Persistence\n- `persistent_storage.py` - Using Modal volumes for data persistence\n- `network_file_system.py` - NFS for shared storage across sandboxes\n- `ephemeral_volume_upload.py` - Upload local files to sandbox\n- `multi_turn_snapshots.py` - Multi-turn conversations with sandbox snapshots between turns\n- `session_resume.py` - Persist conversation state across runs\n\n### Security \u0026 Monitoring\n- `security_sandbox.py` - Network isolation with CIDR allowlist\n- `hooks.py` - Host-side hooks for security, monitoring, and tool interception\n- `budget_control.py` - Cost tracking and budget limits\n\n### Advanced Features\n- `model_selection.py` - Choose Claude models (Haiku, Sonnet, Opus)\n- `extended_thinking.py` - Complex reasoning with visible thought process\n- `structured_output.py` - JSON responses with defined schemas\n- `multi_agent.py` - Define specialized sub-agents for delegation\n- `programmatic_subagents.py` - Custom agents with `AgentDefinition`\n- `host_tools.py` - Custom tools that run on host machine\n- `host_modal_functions_as_tools.py` - Use deployed Modal functions as agent tools\n\n### Integrations\n- `tunnel_web_app.py` - Build and expose web servers via encrypted tunnels\n\n## Development\n\n```bash\ngit clone https://github.com/sshh12/modal-claude-agent-sdk-python\ncd modal-claude-agent-sdk-python\npip install -e \".[dev]\"\n\n# Install pre-commit hooks\npre-commit install\n\n# Run checks manually\npytest          # Run tests\nmypy src/       # Type checking\nruff check src/ # Linting\nruff format src/ tests/  # Format code\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsshh12%2Fmodal-claude-agent-sdk-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsshh12%2Fmodal-claude-agent-sdk-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsshh12%2Fmodal-claude-agent-sdk-python/lists"}