Skip to content

[Enhancement] Add claude-agent-sdk (Python) as a supported framework #932

@theagenticguy

Description

@theagenticguy

[Enhancement] Add claude-agent-sdk (Python) as a supported framework

Description

Amazon Bedrock AgentCore positions itself as model- and framework-agnostic. The AgentCore CLI today scaffolds projects for Strands, LangChain/LangGraph, GoogleADK, and OpenAIAgents. The one notable omission is Anthropic's official Python agent framework, claude-agent-sdk.

Four official AgentCore samples already ship for this framework in awslabs/agentcore-samples:

All four use BedrockAgentCoreApp + @app.entrypoint and were configured via the legacy bedrock-agentcore-starter-toolkit (agentcore configure -e agent.py --disable-memory + agentcore launch --env CLAUDE_CODE_USE_BEDROCK=1). The new aws/agentcore-cli has no equivalent template, so customers following the samples today have to either bounce back to the deprecated starter toolkit or shoehorn claude-agent-sdk through --type byo.

Adding first-class ClaudeAgentSDK support would close this gap and give customers the same zero-config path they have for Strands and the other Claude-capable frameworks.

Why a first-class framework entry (vs. BYO)

claude-agent-sdk is architecturally distinct from the existing frameworks — it orchestrates a Node.js Claude Code CLI subprocess over JSON/stdio rather than running an in-process model client. It has its own ClaudeAgentOptions API, @tool decorator + create_sdk_mcp_server in-process MCP layer, HookMatcher/HookContext governance, and AgentDefinition-based subagents.

A shipped template removes the per-customer trial-and-error of:

  1. Bridging the async-generator output of query() / ClaudeSDKClient into BedrockAgentCoreApp's streaming contract (detected at src/bedrock_agentcore/runtime/app.py:415-421 — async generators are auto-wrapped in StreamingResponse(..., media_type="text/event-stream"), so the template just needs to yield messages; it does not need to hand-roll SSE).
  2. Installing the Node.js + @anthropic-ai/claude-code CLI into the runtime image (the stock src/assets/container/python/Dockerfile is ghcr.io/astral-sh/uv:python3.12-bookworm-slim — no Node).
  3. Configuring Bedrock auth via CLAUDE_CODE_USE_BEDROCK=1 (matches the official sample README at claude-sdk/README.md:85).
  4. Providing a pyproject.toml that pins claude-agent-sdk, bedrock-agentcore, and bedrock-agentcore-starter-toolkit (the three deps the official sample requires at claude-sdk/requirements.txt).

This matches the precedent set by OpenAIAgents — a framework limited to one model-provider family — but with stronger justification (four official samples vs. OpenAIAgents's zero).

Proposed surface

Attribute Proposal Source of truth
Framework identifier ClaudeAgentSDK Matches existing PascalCase convention (Strands, GoogleADK, OpenAIAgents)
Model providers Bedrock (default), Anthropic SDK gates on CLAUDE_CODE_USE_BEDROCK=1 vs. ANTHROPIC_API_KEY; OpenAI/Gemini not supported — claude-agent-sdk only talks to Claude
Protocol HTTP only in v1 AgentCore Runtime HTTP service contract; A2A/AGUI/MCP deferred
Default model global.anthropic.claude-opus-4-7 Bedrock global cross-region inference profile. Exposed as an overridable constant in main.py.
Build type Container required Needs Node.js for the Claude Code CLI — see "Node.js in the container" below

Design: template skeleton

src/assets/python/http/claude_agent_sdk/base/:

  • main.pyBedrockAgentCoreApp() + @app.entrypoint async def run_main(payload) that yields directly from query() or ClaudeSDKClient. Mirrors the official claude-sdk/agent.py (verified: 97 LOC, three modes, pure async-generator). Handlebars branches on hasMemory, hasGateway, sessionStorageMountPath — same three variables consumed by the Strands/LangGraph templates (see src/assets/python/http/strands/base/main.py:4-14).
  • model/load.py — Two provider branches modeled on src/assets/python/http/strands/base/model/load.py:1-7 and :9-47:
    • Bedrock: sets CLAUDE_CODE_USE_BEDROCK=1, AWS_REGION, and ANTHROPIC_MODEL in os.environ before constructing ClaudeAgentOptions(...) so the subprocess inherits them (subprocess inherits env at spawn — can't be lazy-loaded after the first call).
    • Anthropic: reuses the existing @requires_api_key pattern from src/assets/python/http/strands/base/model/load.py:11-37 and copies the resolved secret into ANTHROPIC_API_KEY before spawn.
  • mcp_client/client.pyget_streamable_http_mcp_client() + get_all_gateway_mcp_clients() returning dict[str, McpHttpServerConfig] entries for ClaudeAgentOptions.mcp_servers. Pattern matches src/assets/python/http/strands/base/mcp_client/client.py.
  • pyproject.toml — pins claude-agent-sdk, bedrock-agentcore>=1.0.3, mcp>=1.19.0, aws-opentelemetry-distro, botocore[crt]>=1.35.0. Matches the official sample's requirements.txt plus the shared deps the Strands template already pins at src/assets/python/http/strands/base/pyproject.toml.
  • README.md, gitignore.template.

Design: CLI/schema change set

The exhaustive switch at src/cli/templates/index.ts:28-40 and the Record<SDKFramework, …> typing on SDK_MODEL_PROVIDER_MATRIX and PROTOCOL_FRAMEWORK_MATRIX mean TypeScript will force every enforcement site to be updated once the enum is extended. Concretely:

  1. src/schema/constants.ts
    • Add 'ClaudeAgentSDK' to SDKFrameworkSchema (line 7).
    • Extend SDK_MODEL_PROVIDER_MATRIX with ClaudeAgentSDK: ['Bedrock', 'Anthropic'] as const (lines 45-50).
    • Add 'ClaudeAgentSDK' to PROTOCOL_FRAMEWORK_MATRIX.HTTP only (line 174).
    • Add reserved package names 'claudeagentsdk' and 'claude_agent_sdk' (lines 79-133).
  2. src/cli/templates/ — add ClaudeAgentSDKRenderer.ts cloning StrandsRenderer.ts; register in createRenderer (lines 22-40 of src/cli/templates/index.ts) and re-export from the barrel (lines 1-17).
  3. TUI optionssrc/cli/tui/screens/generate/types.ts (SDK_OPTIONS, lines 122-127) and src/cli/tui/screens/agent/types.ts (FRAMEWORK_OPTIONS, lines 161-166).
  4. CLI help strings--framework descriptions in src/cli/commands/create/command.tsx:180-183 and src/cli/primitives/AgentPrimitive.tsx:218.
  5. Build-type guard — if Container is the only supported build (per the Node-in-container discussion below), add a validator in src/cli/commands/add/validate.ts and src/cli/commands/create/validate.ts that rejects --framework ClaudeAgentSDK --build CodeZip with a clear error.
  6. Testssrc/schema/__tests__/constants.test.ts, src/cli/commands/add/__tests__/validate.test.ts, src/cli/commands/create/__tests__/validate.test.ts, src/cli/commands/add/__tests__/add-agent.test.ts, src/cli/tui/screens/generate/__tests__/useGenerateWizard.test.tsx, src/cli/operations/agent/generate/__tests__/schema-mapper.test.ts, a new case in integ-tests/create-frameworks.test.ts, optional e2e-tests/claudeagentsdk-bedrock.test.ts + claudeagentsdk-anthropic.test.ts, plus the auto-updated asset snapshot at src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap.
  7. Docsdocs/frameworks.md (framework list, protocol compatibility, comparison table), README.md supported-frameworks table, CHANGELOG.md.

Node.js in the container

The Claude Agent SDK Python package spawns the Claude Code Node.js CLI (@anthropic-ai/claude-code) as a subprocess over JSON/stdio. The stock Dockerfile at src/assets/container/python/Dockerfile is ghcr.io/astral-sh/uv:python3.12-bookworm-slim — no Node. The official sample README (line 19) explicitly lists Node.js and npm as a prerequisite.

Proposal: add a per-framework Dockerfile under src/assets/container/python-claude/Dockerfile that extends the stock bookworm-slim base with apt-get install -y nodejs npm and npm install -g @anthropic-ai/claude-code@latest, then branch BaseRenderer.render() (src/cli/templates/BaseRenderer.ts:69-82) on sdkFramework to pick the right container template. This is the cleanest split — it adds ~70 MB to the ClaudeAgentSDK image only, leaves every other framework unaffected, and keeps Dockerfile changes auditable per framework.

Alternative considered: add Node to the shared Python Dockerfile. Rejected because it bloats every framework's image for a dep only ClaudeAgentSDK uses. Open to maintainer preference.

Import (agentcore add agent --type import)

Out of scope for v1. The Bedrock Agents → framework translator at src/cli/operations/agent/import/index.ts:70-73 currently supports Strands and LangChain_LangGraph via a binary ternary; extending it to ClaudeAgentSDK would require a new claude-translator.ts (analogous to strands-translator.ts) and is deferred.

What does NOT change

Verified by reading the CDK assets + starter toolkit:

  • ModelProvider enumAnthropic and Bedrock already exist (src/schema/constants.ts:13).
  • Credential plumbingCredentialPrimitive, .env.local, ApiKeyCredentialProvider provisioning in src/cli/operations/deploy/pre-deploy-identity.ts, and CDK hand-off at src/assets/cdk/bin/cdk.ts:73-82 are all framework-agnostic and key off ModelProvider — verified by reading src/assets/cdk/lib/cdk-stack.ts:9-62 (no sdkFramework branching; just spec and credentials).
  • Dev server / invokesrc/cli/operations/dev/codezip-dev-server.ts and src/cli/commands/invoke/action.ts branch on protocol, not sdkFramework. BedrockAgentCoreApp auto-detects async generators and serves them as SSE without any per-framework bridging (verified in src/bedrock_agentcore/runtime/app.py:415-421).
  • CDK L3 constructs (@aws/agentcore-cdk, aws/agentcore-l3-cdk-constructs — currently private) — framework-opaque; they consume AgentCoreProjectSpec which has no framework field.

Acceptance Criteria

  • agentcore create --framework ClaudeAgentSDK --model-provider Bedrock scaffolds a project that agentcore dev runs locally (with CLAUDE_CODE_USE_BEDROCK=1) and agentcore deploy deploys to AgentCore Runtime.
  • agentcore create --framework ClaudeAgentSDK --model-provider Anthropic works end-to-end, with the Anthropic API key captured via the existing ApiKeyCredentialProvider flow (.env.local locally, AgentCore Identity at runtime).
  • agentcore create --framework ClaudeAgentSDK --model-provider OpenAI (and Gemini) is rejected at validation time with a clear error message, matching the existing OpenAIAgents/GoogleADK guard behaviour.
  • agentcore create --framework ClaudeAgentSDK --build CodeZip is rejected at validation time with a message pointing at the Container build type (Node.js subprocess requirement).
  • agentcore invoke '{"prompt": "hello", "mode": 1}' returns a streaming response, matching the payload shape used by the official sample at claude-sdk/README.md:100-107.
  • agentcore add gateway and agentcore add gateway-target wire Gateway into ClaudeAgentOptions.mcp_servers as an HTTP MCP server and the agent can call gateway tools.
  • agentcore add memory wires memory into the template — or is explicitly deferred and documented (see open questions).
  • The interactive TUI wizard (create and add agent) lists ClaudeAgentSDK and filters model-provider options to {Bedrock, Anthropic} only.
  • Every Record<SDKFramework, …> matrix in src/schema/constants.ts is updated; tsc --noEmit passes.
  • Container build of the scaffolded project produces a working image that claude --version succeeds inside (verifying the Node stage).
  • Snapshot tests in src/assets/__tests__/assets.snapshot.test.ts cover the new template directory.
  • New integ test mirroring integ-tests/create-frameworks.test.ts covers both ClaudeAgentSDK + Bedrock and ClaudeAgentSDK + Anthropic.
  • docs/frameworks.md, README.md, and CHANGELOG.md are updated.

Additional Context

References

Related issues

Open questions for reviewers

  1. Framework identifier. Preferred: ClaudeAgentSDK (mirrors the PyPI name and import path claude_agent_sdk). Alternative: AnthropicAgentSDK (parallels OpenAIAgents). Happy to flip.
  2. Memory capability. Strands has a first-class AgentCoreMemorySessionManager wired into its template at src/assets/python/http/strands/capabilities/memory/session.py. claude-agent-sdk has its own conversation memory model (continue_conversation, resume, session store, hook-based memory). Should v1 ship an AgentCore-Memory capability directory for ClaudeAgentSDK (mirroring Strands), or defer with a doc pointer to ClaudeAgentOptions.session_store / resume?
  3. Docker layering. Preference for per-framework Dockerfile (src/assets/container/python-claude/Dockerfile + BaseRenderer branch) vs. adding Node unconditionally to the shared Python Dockerfile. Per-framework seems cleaner; open to the other direction.
  4. Sample parity. There are four official samples (basic, hooks, sub-agents, code-interpreter). Does v1 ship one canonical template (basic with tools) and offer the other three as post-create docs, or ship multiple templates selectable via a flag?
  5. Default model ID. Proposal: global.anthropic.claude-opus-4-7, surfaced as an overridable constant in the generated main.py. Confirm the inference profile ID is available in the target regions.
  6. Stale framework entries. docs/frameworks.md lists CrewAI but there is no corresponding enum value, no template, and no test coverage. Similarly, src/assets/python/*/autogen/ asset trees exist on disk but Autogen is not in SDKFrameworkSchema. Happy to clean these up under a separate issue while this change is in flight, or leave them alone.

Non-goals for v1

  • A2A / AGUI / MCP protocol variants for ClaudeAgentSDK.
  • --type import support (Bedrock Agents → claude-agent-sdk code translation).
  • Vertex AI / Azure Foundry model-provider branches (requires new ModelProvider enum values).
  • Parity with all four samples — target is the basic claude-sdk flow; hooks/sub-agents/code-interpreter patterns are reachable by editing the scaffolded main.py.

Happy to own the PR once direction is agreed. Per CONTRIBUTING.md, filing this issue first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions