aws / aws/agentcore-cli

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

Open
#932 1 comment 3 reactions 0 assignees View on GitHub
enhancement
Dominant language
TypeScript
Stars
283
Forks
95
Avg merge
1d 2h
Merged PRs (30d)
183

Description

# [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`](https://pypi.org/project/claude-agent-sdk/).

Four **official AgentCore samples** already ship for this framework in [`awslabs/agentcore-samples`](https://github.com/awslabs/agentcore-samples/tree/main/03-integrations/agentic-frameworks/claude-agent):

- [`claude-sdk/`](https://github.com/awslabs/agentcore-samples/tree/main/03-integrations/agentic-frameworks/claude-agent/claude-sdk) — basic + options + tools, three modes.
- [`claude-hooks/`](https://github.com/awslabs/agentcore-samples/tree/main/03-integrations/agentic-frameworks/claude-agent/claude-hooks) — `PreToolUse`/`PostToolUse` hook governance.
- [`claude-sub-agents/`](https://github.com/awslabs/agentcore-samples/tree/main/03-integrations/agentic-frameworks/claude-agent/claude-sub-agents) — orchestrator/workers with `AgentDefinition`.
- [`claude-with-code-interpreter/`](https://github.com/awslabs/agentcore-samples/tree/main/03-integrations/agentic-frameworks/claude-agent/claude-with-code-interpreter) — `ClaudeSDKClient` + SDK MCP server + AgentCore Code Interpreter.

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`](https://github.com/aws/bedrock-agentcore-sdk-python/blob/main/src/bedrock_agentcore/runtime/app.py#L415-L421) — 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`](https://github.com/awslabs/agentcore-samples/blob/main/03-integrations/agentic-frameworks/claude-agent/claude-sdk/README.md#L85)).
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`](https://github.com/awslabs/agentcore-samples/blob/main/03-integrations/agentic-frameworks/claude-agent/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.py`** — `BedrockAgentCoreApp()` + `@app.entrypoint async def run_main(payload)` that yields directly from `query()` or `ClaudeSDKClient`. Mirrors the official [`claude-sdk/agent.py`](https://github.com/awslabs/agentcore-samples/blob/main/03-integrations/agentic-frameworks/claude-agent/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.py`** — `get_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`](https://github.com/awslabs/agentcore-samples/blob/main/03-integrations/agentic-frameworks/claude-agent/claude-sdk/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`](https://github.com/aws/agentcore-cli/blob/main/src/cli/templates/index.ts#L28-L40) and the `Record` typing on [`SDK_MODEL_PROVIDER_MATRIX`](https://github.com/aws/agentcore-cli/blob/main/src/schema/constants.ts#L45-L50) and [`PROTOCOL_FRAMEWORK_MATRIX`](https://github.com/aws/agentcore-cli/blob/main/src/schema/constants.ts#L173-L178) 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 options** — `src/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. **Tests** — `src/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. **Docs** — `docs/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`](https://github.com/aws/agentcore-cli/blob/main/src/assets/container/python/Dockerfile) is `ghcr.io/astral-sh/uv:python3.12-bookworm-slim` — no Node. The official sample README ([line 19](https://github.com/awslabs/agentcore-samples/blob/main/03-integrations/agentic-frameworks/claude-agent/claude-sdk/README.md#L19)) 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`](https://github.com/aws/agentcore-cli/blob/main/src/cli/operations/agent/import/index.ts#L70-L73) 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` enum** — `Anthropic` and `Bedrock` already exist (`src/schema/constants.ts:13`).
- **Credential plumbing** — `CredentialPrimitive`, `.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 / invoke** — `src/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`](https://github.com/awslabs/agentcore-samples/blob/main/03-integrations/agentic-frameworks/claude-agent/claude-sdk/README.md#L100-L107).
- [ ] `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` 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

- SDK on PyPI: https://pypi.org/project/claude-agent-sdk/
- SDK source: https://github.com/anthropics/claude-agent-sdk-python
- Python API docs: https://code.claude.com/docs/en/agent-sdk/python.md
- Claude Code on Bedrock: https://docs.anthropic.com/en/docs/claude-code/amazon-bedrock
- AgentCore Runtime service contract: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-service-contract.html
- Streaming auto-detection in `BedrockAgentCoreApp`: [`src/bedrock_agentcore/runtime/app.py:415-421`](https://github.com/aws/bedrock-agentcore-sdk-python/blob/main/src/bedrock_agentcore/runtime/app.py#L415-L421)
- Official AgentCore samples for claude-agent-sdk: [`awslabs/agentcore-samples/03-integrations/agentic-frameworks/claude-agent/`](https://github.com/awslabs/agentcore-samples/tree/main/03-integrations/agentic-frameworks/claude-agent)

#### Related issues

- #900 (CopilotKit/AG-UI for AgentCore CLI) — establishes the pattern of shipping a new framework/protocol combination as a first-class CLI offering.
- #327 (Python templates install unused deps) — relevant because `claude-agent-sdk`'s provider gating is simpler than the existing multi-provider frameworks; scoping the `pyproject.toml` to exactly `{Bedrock, Anthropic}` should avoid regressing that issue.

#### 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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.