feat: add Claude Platform on AWS migration skill (.claude/skills/)#231
feat: add Claude Platform on AWS migration skill (.claude/skills/)#231wirjo wants to merge 4 commits into
Conversation
|
@rodzanto FYI, no rush |
| WORKSPACE_ID = "wrkspc_XXXXX" | ||
| API_KEY = "aws-external-anthropic-api-key-..." | ||
|
|
||
| client = Anthropic( |
There was a problem hiding this comment.
The CPOA path is the dedicated AnthropicAWS client rather than Anthropic() with a manual base_url — it handles SigV4 signing, base-URL construction, and the anthropic-workspace-id header for you, so all the plumbing here collapses:
from anthropic import AnthropicAWS # pip install -U "anthropic[aws]"
client = AnthropicAWS(api_key=API_KEY) # region + workspace from AWS_REGION / ANTHROPIC_AWS_WORKSPACE_IDRef: Claude Platform on AWS → Making requests — "Each SDK provides a platform-specific client class that handles SigV4 signing, region-based base URL construction, and the anthropic-workspace-id header."
There was a problem hiding this comment.
Confirmed ✅ — docs show AnthropicAWS (Python) and AnthropicAws (TypeScript from @anthropic-ai/aws-sdk) as the canonical CPOA clients. Will update all examples to use these instead of manual base_url/headers.
| REGION = "us-west-2" | ||
| WORKSPACE_ID = "wrkspc_XXXXX" | ||
|
|
||
| client = Anthropic( |
There was a problem hiding this comment.
Heads up — credentials={"type": "aws_iam", ...} isn't a real parameter, and a plain Anthropic() can't SigV4-sign at all. SigV4 mode is just the dedicated client with no key; it resolves creds via the standard AWS provider chain (env → ~/.aws → IRSA → ECS → IMDS):
from anthropic import AnthropicAWS
client = AnthropicAWS(aws_region=REGION) # SigV4 via default AWS credential chainThere was a problem hiding this comment.
Confirmed ✅ — credentials={"type": "aws_iam", ...} is not a real SDK parameter. SigV4 mode is simply AnthropicAWS() with no API key, which resolves creds via the standard AWS provider chain (env → ~/.aws → IRSA → ECS → IMDS).
Will fix to:
from anthropic import AnthropicAWS
client = AnthropicAWS(aws_region=REGION) # SigV4 via default AWS credential chainRef: SigV4 authentication — credential precedence shows apiKey → env creds → provider chain.
| const workspaceId = "wrkspc_XXXXX"; | ||
| const apiKey = "aws-external-anthropic-api-key-..."; | ||
|
|
||
| const client = new Anthropic({ |
There was a problem hiding this comment.
Same as the Python case — the Node client is AnthropicAws from @anthropic-ai/aws-sdk (npm install @anthropic-ai/aws-sdk), which sets the workspace header and signing automatically:
import AnthropicAws from "@anthropic-ai/aws-sdk";
const client = new AnthropicAws({ apiKey });There was a problem hiding this comment.
Confirmed ✅ — Node client is AnthropicAws from @anthropic-ai/aws-sdk (npm install @anthropic-ai/aws-sdk). Will update:
import AnthropicAws from "@anthropic-ai/aws-sdk";
const client = new AnthropicAws({ apiKey, awsRegion: "us-west-2" });Ref: Install an SDK → TypeScript — npm install @anthropic-ai/aws-sdk
| const workspaceId = "wrkspc_XXXXX"; | ||
|
|
||
| const client = new Anthropic({ | ||
| credentials: { type: "aws_iam", region }, |
There was a problem hiding this comment.
Same note as the Python SigV4 block — no credentials object; new AnthropicAws({ awsRegion: region }) signs via the default AWS chain.
There was a problem hiding this comment.
Confirmed ✅ — same as Python: new AnthropicAws({ awsRegion: region }) signs via default AWS chain. No credentials object. Will fix.
| }); | ||
| ``` | ||
|
|
||
| **Note:** `AnthropicAWS` class is Python-only. In Node.js, always use the standard `Anthropic` class with `authToken` or `credentials`. |
There was a problem hiding this comment.
Small correction — there is a dedicated Node client (AnthropicAws in @anthropic-ai/aws-sdk), so this note is the one thing to flip. The docs list platform clients for Python, TypeScript, Go, Java, C#, PHP, and Ruby. Ref: CPOA → Install an SDK.
There was a problem hiding this comment.
Confirmed ✅ — this note is wrong and will be removed. There IS a dedicated Node client (AnthropicAws in @anthropic-ai/aws-sdk). Docs list platform clients for Python, TypeScript, Go, Java, C#, PHP, and Ruby.
Ref: Install an SDK
|
|
||
| ```bash | ||
| curl -X POST https://aws-external-anthropic.us-west-2.api.aws/v1/messages \ | ||
| -H "Authorization: Bearer aws-external-anthropic-api-key-..." \ |
There was a problem hiding this comment.
CPOA API keys go on the x-api-key header rather than Authorization: Bearer — the short-term token generators also return tokens that "work with the x-api-key header." The anthropic-version + anthropic-workspace-id headers here are spot on. Ref: CPOA → API key authentication.
There was a problem hiding this comment.
Confirmed ✅ — CPOA API keys use the x-api-key header, not Authorization: Bearer. The docs say short-term tokens also "work with the x-api-key header." Will fix the curl example:
-H "x-api-key: $ANTHROPIC_AWS_API_KEY"Ref: Short-term API keys — "returns a time-limited token that works with the x-api-key header"
|
|
||
| ```python | ||
| from anthropic import Anthropic | ||
| from anthropic.helpers.beta.environments import WorkPoller |
There was a problem hiding this comment.
from anthropic.helpers.beta.environments import WorkPoller isn't the documented path — the self-hosted worker helper is EnvironmentWorker from anthropic.lib.environments. Worth aligning the "Before" side with that so the contrast is accurate.
There was a problem hiding this comment.
Good catch — will align the "Before" example with the documented EnvironmentWorker pattern rather than the invented WorkPoller path. The self-hosted docs show the SDK helpers .run() / .run_one() as the main interface.
|
|
||
| # Direct polling (bypasses WorkPoller's environmentKey requirement) | ||
| while True: | ||
| work = client.beta.environments.work.poll( |
There was a problem hiding this comment.
The work.poll(environment_id=..., timeout=30) signature is invented — the documented Python surface is the EnvironmentWorker helper (.run() / .run_one()), with client.beta.environments.work.poller(...) as the mid-level API. (The underlying REST route GET /v1/environments/{id}/work/poll does exist, so the concept is right — it's just the SDK shape.) Ref: Self-hosted sandboxes.
There was a problem hiding this comment.
Confirmed — the SDK shape is EnvironmentWorker with .run() / .run_one(), and client.beta.environments.work.poller(...) as the mid-level API. The REST route GET /v1/environments/{id}/work/poll does exist (confirmed in IAM actions under ProcessEnvironmentWork), but the Python SDK wraps it differently.
Will rewrite the "After" pattern to use the documented SDK helper, and note the raw endpoint as a fallback for custom implementations.
Ref: IAM actions → ProcessEnvironmentWork confirms GET /v1/environments/{id}/work/poll is a real route.
| 3. [ ] API key has `aws-external-anthropic-api-key-` prefix (if using key mode) | ||
| 4. [ ] No references to `sk-ant-api03-` or `sk-ant-env01-` keys | ||
| 5. [ ] No `AnthropicAWS` imports in Node.js code | ||
| 6. [ ] IAM role has `AnthropicSelfHostedEnvironmentAccess` policy (if SigV4 mode) |
There was a problem hiding this comment.
One correctness catch: AnthropicSelfHostedEnvironmentAccess is the self-hosted worker policy — its grant is GetEnvironment, ProcessEnvironmentWork, GetSession, UpdateSession, GetSkill, CallWithBearerToken, with no CreateInference. A role with only this policy 403s on /v1/messages. For plain SigV4 inference the minimal managed policy is AnthropicInferenceAccess. Ref: IAM actions → Managed policies.
There was a problem hiding this comment.
Confirmed ✅ — important distinction. Per the IAM docs:
AnthropicSelfHostedEnvironmentAccess= worker policy (GetEnvironment,ProcessEnvironmentWork,GetSession,UpdateSession,GetSkill,CallWithBearerToken) — noCreateInferenceAnthropicInferenceAccess= needed for plain SigV4 calls to/v1/messages
Will split the IAM guidance: inference needs AnthropicInferenceAccess; self-hosted workers need AnthropicSelfHostedEnvironmentAccess.
|
|
||
| 1. [ ] Base URL uses `aws-external-anthropic.{region}.api.aws` | ||
| 2. [ ] `anthropic-workspace-id` header present on all requests | ||
| 3. [ ] API key has `aws-external-anthropic-api-key-` prefix (if using key mode) |
There was a problem hiding this comment.
Could we cite a source for the aws-external-anthropic-api-key- prefix? The CPOA docs describe key generation but don't state a fixed prefix, so I'd soften this to avoid an agent asserting on a shape that may not hold. (Same prefix claim appears in SKILL.md lines 15 & 30.)
There was a problem hiding this comment.
Fair point — the docs describe key generation via the AWS Console but do not state a guaranteed aws-external-anthropic-api-key- prefix. This was observed empirically but should not be treated as a stable contract.
Will soften to: "API keys are generated in the AWS Console under Claude Platform on AWS → API keys" without asserting a specific prefix format. Will remove the prefix-based validation checklist item too.
| | Required headers | `x-api-key`, `anthropic-version` | `anthropic-workspace-id` (on all requests) | | ||
| | Billing | Anthropic billing | AWS Marketplace | | ||
| | Inference | Anthropic infra | Anthropic infra (same — CPOA only changes auth/billing layer) | | ||
| | Env keys (agents) | `sk-ant-env01-...` | NOT used — use IAM role or CPOA API key | |
There was a problem hiding this comment.
This is a bit too absolute — self-hosted sandbox agents are supported on CPOA and do authenticate with ANTHROPIC_ENVIRONMENT_KEY (the AnthropicSelfHostedEnvironmentAccess policy + ProcessEnvironmentWork action exist precisely for that worker). Might scope this to "managed/cloud agents" so an agent following the rule doesn't strip a required credential. (Also drives pitfall #3 at line 86 and step 5 at line 59.) Ref: CPOA → Claude Managed Agents.
There was a problem hiding this comment.
Confirmed ✅ — this was overly broad. The self-hosted sandboxes docs explicitly state:
"On Claude Platform on AWS, the worker authenticates with AWS IAM (SigV4) or an API key generated in the AWS Console, not an environment key. Environment keys generated in the Claude Console don't work with the Claude Platform on AWS endpoint."
So: environment keys from the Claude Console don't work on CPOA, but the worker still authenticates — just via IAM/API key instead. The table row and pitfall should say "Environment keys from Claude Console not used on CPOA — workers authenticate via IAM or CPOA API key" rather than implying the concept of worker auth doesn't exist.
| CPOA supports two auth modes: | ||
|
|
||
| - **IAM SigV4** (preferred for production): Uses execution role credentials. No secrets to manage. | ||
| - **API key** (dev/quick-start): CPOA-issued key with `aws-external-anthropic-api-key-` prefix. Short-lived (~15 min from Quick Start, longer for production keys). |
There was a problem hiding this comment.
The ~15-min figure doesn't match the docs — short-term tokens "default to 12 hours and are capped at the lesser of your requested duration, your AWS credentials' expiry, and 12 hours." Worth correcting here and in pitfall #4 (line 87). Ref: CPOA → Short-term API keys.
There was a problem hiding this comment.
Confirmed ✅ — the docs clearly state:
"Token lifetime defaults to 12 hours and is capped at the lesser of your requested duration, your AWS credentials' expiry, and 12 hours."
The ~15 min figure was likely confused with something else (perhaps an STS session token from a very short-lived assume-role). Will correct to 12 hours default, capped at min(requested, AWS creds expiry, 12h).
Ref: Short-term API keys
|
All review comments from @scouturier have been addressed in the latest commit (a55e37d). Summary of changes:
All corrections are backed by the official docs:
@scouturier @rodzanto — this should be ready for merge when you get a chance. Let us know if anything else needs attention. 🙏 |
|
Thanks @wirjo — re-verified the earlier review points and they're resolved. Two things before merge: 1. Rebase on 2. Model ID nit (non-blocking). Examples use Everything else checks out against the live docs (token generators, clients, IAM, curl SigV4). LGTM once those two are in. 🙏 |
Adds a structured .claude/skills/ directory with a migration skill for converting Anthropic 1P (direct API) code to Claude Platform on AWS (CPOA). Files: - .claude/skills/claude-platform-on-aws/SKILL.md - .claude/skills/claude-platform-on-aws/references/code-patterns.md Covers: - 1P → CPOA conversion for messages API, managed agents, and self-hosted environments - Both auth modes: SigV4 (IAM) and API key - Python, Node.js, and curl code patterns (before/after) - Common pitfalls (workspace header, environment keys, WorkPoller) - Validation checklist
Changes based on official CPOA documentation:
- Use AnthropicAWS (Python) and AnthropicAws (TypeScript) platform clients
instead of manual base_url/defaultHeaders configuration
- Remove invented credentials={"type": "aws_iam"} parameter; SigV4 is
simply the platform client with no API key (uses AWS provider chain)
- Fix auth header: CPOA uses x-api-key, not Authorization: Bearer
- Correct token lifetime: 12 hours default (not 15 min), capped at
min(requested, AWS creds expiry, 12h)
- Split IAM guidance: AnthropicInferenceAccess for /v1/messages vs
AnthropicSelfHostedEnvironmentAccess for workers (no CreateInference)
- Clarify environment keys: Console-generated env keys don't work on
CPOA; workers auth via IAM or CPOA API key instead
- Remove undocumented API key prefix assertion
- Replace WorkPoller with documented EnvironmentWorker SDK helper
- Add SigV4 curl example with --aws-sigv4 flag
- Add short-term token generation examples (Python + TypeScript)
- Add outbound web identity federation prerequisite
- Note: region is required with no fallback (unlike AnthropicBedrock)
Refs:
- https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws
- https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions
- https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes
Additional fixes from docs validation: - Use actual EnvironmentWorker import: from anthropic.lib.environments - Fix environment key prefix: sk-ant-oat01-... (not sk-ant-env01-...) - Replace invented client.beta.environments.worker.run() with actual EnvironmentWorker(client, ...).run() pattern from official docs - Show proper async pattern matching SDK docs examples - Fix validation checklist to reference correct key prefix Refs: - https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#sdk-helpers - SDK code: from anthropic.lib.environments import EnvironmentWorker
Swap claude-sonnet-4-6 → claude-sonnet-5 across all examples to match the current official CPOA documentation.
06f4f45 to
14a6b0d
Compare
|
@scouturier Rebased on latest main (should clear the CI failure) and updated all model IDs to |
| # On CPOA: no environment key needed — authenticate via IAM | ||
| # Requires AnthropicSelfHostedEnvironmentAccess IAM policy | ||
| environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] | ||
| async with AsyncAnthropic() as client: # SigV4 via AWS credential chain |
There was a problem hiding this comment.
One thing that slipped past the earlier round: the "Worker with IAM Auth" block still uses bare AsyncAnthropic(), and the comment # SigV4 via AWS credential chain is inaccurate — base AsyncAnthropic targets api.anthropic.com and can't SigV4-sign (same defect we fixed for the inference examples at :49/:109). We corrected the prose for this in SKILL.md:19 but not this code block.
Two things to reconcile:
- Use the AWS client, not the base one — the CPOA worker should be constructed via the platform client that signs and sets the workspace header.
- If a SigV4-authenticated
EnvironmentWorkerisn't actually a documented pattern (the self-hosted docs only show the async worker withauth_token=<key>), mark this variant as unverified rather than shipping it as working. The API-key worker block just below is fine as-is.
Summary
Adds a structured
.claude/skills/directory with a Claude Platform on AWS migration skill — a reference that coding agents (Claude Code, etc.) can use to automatically convert Anthropic 1P (direct API) code to CPOA.What this adds
Motivation
Developers migrating from
api.anthropic.comtoaws-external-anthropic.{region}.api.awsencounter several non-obvious differences:anthropic-workspace-idheader (not documented prominently)AnthropicAWSclass unavailable in Node.js SDKenvironmentKeyworkaroundThis skill provides a structured checklist and code patterns covering both auth modes (SigV4 + API key), managed agents, and session lifecycle.
Why
.claude/skills/?This sets the foundation for a skills directory in this repository that:
Relationship to existing content
The repo already has CPOA notebooks under
claude-platform-on-aws/notebooks/. This skill complements those by providing an agent-consumable reference (SKILL.md format) for automated conversions rather than human-walkthrough notebooks.Alternative repository
An alternative home for this type of contribution could be https://github.com/aws/agent-toolkit-for-aws/tree/main/skills/specialized-skills (the official AWS agent skills repository). Happy to cross-post or move there if preferred by maintainers.
Checklist
main