AWS SAM skill for Codex
Local invokes, reviewed change sets, canary releases. Codex keeps SAM projects in a known-good loop: lint the template, build with the right method per language, invoke functions locally with generated events, and use sam sync only for personal dev stacks. Staging and production deploy through samconfig environments and reviewed change sets, with AutoPublishAlias canaries and alarms that roll bad releases back.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- aws-sam Installs to ~/.agents/skills/aws-sam/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install aws-sam The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project aws-sam Installs to .agents/skills/aws-sam/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/aws-sam.zipunzip -o aws-sam.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) aws-sam PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $aws-sam, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Builds, tests and deploys serverless apps with AWS SAM - template.yaml with the Serverless transform, Globals, policy templates and connectors, esbuild and container builds, sam local invoke and start-api with generated events, sam sync for dev, sam deploy with samconfig.toml and change sets, gradual deployments with AutoPublishAlias and CodeDeploy, and sam validate --lint. Use when starting or editing a SAM project, running Lambda functions locally, setting up dev/prod deploys, a sam build or deploy fails, or adding canary releases to functions.
Use it when
- Starting or editing a SAM template.yaml project
- Running or debugging Lambda functions locally
- sam build or sam deploy fails
- Adding gradual deployments to Lambda functions
Use something else when
- The infrastructure is a CDK app: use aws-cdk
- The question is the function code, cold starts or concurrency: use aws-lambda
How to check the result
sam validate --lint and sam build pass, sam local invoke returns the expected response, and a production deploy shows a reviewed change set followed by a completed CodeDeploy traffic shift.
The mistake it prevents
Running sam sync against a shared or production stack, which skips change set review and leaves the stack drifted from its template.
Done well means: the template passes sam validate --lint, every function can be invoked
locally with a realistic event, dev iterates with sam sync while staging and production
deploy only through reviewed change sets, and production functions shift traffic
gradually with alarms that roll back.
Before changing anything
- Read
AGENTS.md,template.yaml(ortemplate.yml),samconfig.tomland each function’sCodeUrifolder with its lockfile. - Check the toolchain:
sam --version, Docker running (docker info) for local emulation and container builds, the language runtime locally for non-container builds. - Run
sam validate --lintandsam buildon the untouched project to know the baseline.sam buildwith local runtimes works offline if dependencies are cached; it needs network to install packages, and--use-containerneeds network to pull images.
Template shape
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Orders service
Parameters:
Stage:
Type: String
AllowedValues: [dev, staging, prod]
Globals:
Function:
Runtime: nodejs22.x
Architectures: [arm64]
MemorySize: 512
Timeout: 10
Tracing: Active
LoggingConfig:
LogFormat: JSON
Environment:
Variables:
TABLE_NAME: !Ref OrdersTable
POWERTOOLS_SERVICE_NAME: orders
Resources:
OrdersApi:
Type: AWS::Serverless::HttpApi
CreateOrderFunction:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: es2022
Sourcemap: true
EntryPoints: [src/handlers/create-order.ts]
Properties:
CodeUri: ./
Handler: create-order.handler
AutoPublishAlias: live
DeploymentPreference:
Type: Canary10Percent5Minutes
Alarms: [!Ref CreateOrderErrorsAlarm]
Policies:
- DynamoDBWritePolicy:
TableName: !Ref OrdersTable
Events:
Create:
Type: HttpApi
Properties:
ApiId: !Ref OrdersApi
Path: /orders
Method: POST
OrdersTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions: [{ AttributeName: pk, AttributeType: S }]
KeySchema: [{ AttributeName: pk, KeyType: HASH }]
CreateOrderLogs:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${CreateOrderFunction}
RetentionInDays: 30
Outputs:
ApiUrl:
Value: !Sub https://${OrdersApi}.execute-api.${AWS::Region}.amazonaws.com
Rules:
- Put shared function settings in
Globals; override per function only where needed. - Permissions: SAM policy templates (
DynamoDBReadPolicy,DynamoDBCrudPolicy,SQSPollerPolicy,SQSSendMessagePolicy,S3ReadPolicy,SSMParameterReadPolicy) scope to one resource.AWS::Serverless::Connectorexpresses “function A writes to table B” and generates the policy. Avoid managed policies likeAmazonDynamoDBFullAccess. DeletionPolicy: RetainandUpdateReplacePolicy: Retainon tables and buckets with data.- Declare the log group yourself (as above) to control retention; on an existing stack
whose function already created
/aws/lambda/<name>, import or delete that group first (with confirmation) or the deploy fails withalready exists. - Esbuild builds need
esbuildin the project’s dev dependencies (npm i -D esbuild).
Build decisions
| Situation | Build with |
|---|---|
| TypeScript/JavaScript | BuildMethod: esbuild (bundled, tree-shaken) |
| Python with pure-Python deps | sam build (uses local Python matching the runtime) |
| Native deps, or local runtime differs from Lambda’s | sam build --use-container |
| Custom tooling (Rust, Go with flags, monorepo builds) | BuildMethod: makefile with a build-<LogicalId> target |
| Container image functions | PackageType: Image with Metadata: Dockerfile/DockerContext |
sam build --cached --parallel speeds up repeated builds.
Local testing
sam build
sam local generate-event apigateway http-api-proxy > events/create-order.json # edit body
sam local invoke CreateOrderFunction -e events/create-order.json --env-vars env.local.json
sam local start-api --port 3000 # HTTP routes on localhost, needs Docker
sam local start-lambda # Lambda endpoint for SDK-driven tests
env.local.json overrides environment variables per function:
{ "CreateOrderFunction": { "TABLE_NAME": "orders-local", "AWS_ENDPOINT_URL_DYNAMODB": "http://host.docker.internal:8000" } }
Local emulation runs the function code but not IAM, authorizers or real event source mappings. Test those in a deployed dev stack. Unit tests for handlers should not need SAM at all.
Deploy configuration
samconfig.toml holds per-environment settings so deploys are one short command:
version = 0.1
[default.global.parameters]
stack_name = "orders-dev"
[default.deploy.parameters]
resolve_s3 = true
capabilities = "CAPABILITY_IAM CAPABILITY_AUTO_EXPAND"
parameter_overrides = "Stage=dev"
confirm_changeset = false
[prod.deploy.parameters]
stack_name = "orders-prod"
resolve_s3 = true
capabilities = "CAPABILITY_IAM CAPABILITY_AUTO_EXPAND"
parameter_overrides = "Stage=prod"
confirm_changeset = true
| Environment | Command | Notes |
|---|---|---|
| Personal dev stack | sam sync --stack-name orders-dev-$USER --watch | Fast code-only updates, bypasses CloudFormation for code; dev only |
| Shared dev | sam deploy | Uses [default] |
| Production | sam deploy --config-env prod | Change set shown for confirmation |
| CI | sam deploy --config-env prod --no-confirm-changeset --no-fail-on-empty-changeset | Only after review in the pipeline |
Deploy workflow for staging and production:
-
sam validate --lintpasses - Unit tests pass;
sam buildsucceeds -
sam deploy --config-env prodcreates the change set; read it forReplacement: Trueand deletions of stateful resources - User approves the change set explicitly
- Watch the CodeDeploy deployment; the alarm-based rollback must stay enabled
- Smoke-test the outputs (
sam list stack-outputs --stack-name orders-prod)
Never run sam sync against production: it skips change set review and creates drift.
sam delete removes the whole stack; confirm the stack name with the user and check
retained resources first.
Gradual deployments
AutoPublishAlias publishes a version per code change and points the alias at it.
DeploymentPreference uses CodeDeploy to shift traffic: Canary10Percent5Minutes,
Linear10PercentEvery1Minute, AllAtOnce and similar. Add:
Alarms: error rate or latency alarms on the alias; an alarm in ALARM rolls back.Hooks.PreTraffic/PostTraffic: Lambda functions that run checks and report status withcodedeploy:PutLifecycleEventHookExecutionStatus.
Event sources must target the alias (SAM wires this automatically when
AutoPublishAlias is set).
Troubleshooting
| Error | Fix |
|---|---|
Requires capabilities : [CAPABILITY_AUTO_EXPAND] | Add it to capabilities (needed for the transform and nested apps) |
Error: Unable to upload artifact ... S3 Bucket not specified | resolve_s3 = true or --s3-bucket |
Binary validation failed for python | Install the runtime’s Python version locally or use --use-container |
esbuild: not found | Add esbuild to devDependencies and install |
Stack in ROLLBACK_COMPLETE on first deploy | It cannot be updated; delete it (with confirmation) and redeploy |
No changes to deploy failing CI | --no-fail-on-empty-changeset |
| Local invoke cannot reach other containers | Use host.docker.internal or --docker-network |
Read the failing resource’s status reason:
aws cloudformation describe-stack-events --stack-name orders-prod --query "StackEvents[?contains(ResourceStatus,'FAILED')].[LogicalResourceId,ResourceStatusReason]" --output table.
Useful extras
sam logs -n CreateOrderFunction --stack-name orders-dev --tailstreams logs.sam remote invoke CreateOrderFunction --stack-name orders-dev --event-file events/create-order.jsoninvokes the deployed function.sam pipeline init --bootstrapscaffolds CI pipelines with per-stage roles; review the generated IAM before using it.
What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "AWS SAM"
short_description: "Local invokes, reviewed change sets, canary releases"
default_prompt: "$aws-sam Set up dev and prod deploys for this SAM app with samconfig.toml" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.