What the agent does
The agent clones the repository into its own cloud sandbox and reads the stack and its test setup. In typescript/api-cors-lambda-crud-dynamodb from aws-samples/aws-cdk-examples (aws-cdk-lib 2.262.1, aws-cdk 2.1133.0), everything is in index.ts: a DynamoDB Table named items with partition key itemId of type STRING and RemovalPolicy.DESTROY, five NodejsFunction Lambdas on Runtime.NODEJS_24_X that share PRIMARY_KEY and TABLE_NAME environment variables, a RestApi called Items Service with /items and /items/{id}, and an addCorsOptions helper that puts an OPTIONS mock integration on both resources. A jest.config.js already exists, using @swc/jest and aws-cdk-lib/testhelpers/jest-autoclean, but package.json has no test script and there is no test file.
Before writing a test it fixes the one thing that blocks testing. index.ts ends with const app = new App(); new ApiLambdaCrudDynamoDBStack(app, ...); app.synth(); at module level, so importing the stack class into a test would also build and synthesize the whole app. The agent moves those three lines into a separate entry file and points cdk.json's app command at it, or guards them, so the test can create its own App and stack. It adds "test": "jest" to package.json. The Lambdas bundle with esbuild during synth and read lambdas/package-lock.json, which the postinstall script creates by running npm install in lambdas/, so npm install has to run before the tests.
Then it writes the assertions with Template.fromStack. The table: KeySchema with itemId as HASH, AttributeDefinitions with type S, TableName items, and the billing mode, which the code never sets, so the template shows the provisioned default; the test pins what synthesizes today and the pull request points out that nothing chose it. Each Lambda: resourceCountIs('AWS::Lambda::Function', 5) plus hasResourceProperties for the runtime and the two environment variables, with TABLE_NAME matched as a reference to the table rather than a literal. The API: GET and POST on /items, GET, PATCH and DELETE on /items/{id}, and an OPTIONS method on each with the four Access-Control-Allow-* response parameters. Last, a Jest snapshot of the full template, with asset hashes normalised so a Lambda code change does not churn it.
The CORS test turns up a real mismatch: Access-Control-Allow-Methods is 'OPTIONS,GET,PUT,POST,DELETE', but the API has no PUT method and uses PATCH for updates, so a browser preflight for an update would be refused. The agent writes the test to assert today's header and reports the mismatch in the pull request instead of editing the stack. It runs npm test until it passes; nothing needs AWS credentials, because synthesis is local.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "In typescript/api-cors-lambda-crud-dynamodb, write Jest tests with aws-cdk-lib/assertions for the synthesized template. If index.ts synthesizes the app at import time, move the App construction and synth into a separate entry file and update cdk.json so tests can build their own stack. Add a test script to package.json that uses the existing jest.config.js. Assert the table's key schema, attribute types, table name and billing mode as synthesized; each Lambda's runtime and environment variables, with TABLE_NAME matched as a reference to the table; every API resource and method; and the CORS OPTIONS method and its Access-Control-Allow-* headers on each resource. Add a snapshot of the full template with asset hashes normalised. Do not change the stack's resources; if a test shows something inconsistent, assert today's value and report it. Run npm install and npm test until it passes, with no AWS credentials, and open a pull request.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
- Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
- Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.
What comes back
What comes back is a pull request on its own branch. For an example like this one, the diff adds a test file such as test/stack.test.ts with its __snapshots__ folder, a test script in package.json, and the small split of index.ts that lets a test build the stack without synthesizing the app, with cdk.json updated to match. The description lists each assertion group (table, functions, API, CORS, snapshot) and reports what the tests surfaced: the PUT in the CORS methods where the API uses PATCH, and a billing mode that comes from the default rather than a decision.
The session transcript keeps each command with its output: npm install including the postinstall in lambdas/, the esbuild bundling during synth, and every npm test run. The pull request's checks then repeat it on GitHub: aws-cdk-examples' build-pull-request.yml builds each changed TypeScript example with scripts/build-typescript.sh, which installs, runs build, runs npm run --if-present test and synthesizes. Today that test step does nothing for this example because there is no test script; once the pull request adds one, the new tests run on every later change to it.
Before merging, a reviewer checks that the assertions say what the team means rather than what the template happens to contain, decides whether to fix the CORS header in a follow-up change, and confirms the snapshot ignores asset hashes so it changes only when the infrastructure does.
Run it on every new CDK stack
In a monorepo with many stacks, send one POST /o/{org}/sessions per stack with its directory named in input and the repository in resources. Each run gets its own sandbox and branch; a key runs at most its max_concurrent sessions at once (4 by default), so a script starts the next when one finishes.
With a webhook_url on the key, Rush posts run.completed or run.failed when each run's turn finishes. The session read, GET /o/{org}/sessions/{id}, carries the repository and pull request, so your script can collect the links for review.
The use case this job follows, with its automation and trigger: Write the missing tests.
Why run it on Rush?
Assertion tests need the stack to synthesize, and synthesis here means installing two package.json trees, bundling five Lambdas with esbuild and running Jest with @swc/jest, all without AWS credentials. In a Rush sandbox the agent does that on a clean machine with no AWS profile on it, which also proves the tests do not quietly depend on one.
The transcript keeps every install and test run with its output, so a reviewer sees the synthesized resources the assertions were written against and the run where they pass. The findings, like the CORS methods mismatch, come with the test that exposed them.
Frequently asked questions
Does it need my AWS account or credentials?
No. Template.fromStack synthesizes the stack locally and the assertions read the resulting CloudFormation template. Nothing is deployed and no AWS API is called, and Rush never asks for AWS credentials for this job.
Why does it change index.ts if the prompt says not to change the stack?
Only the entry point moves. When index.ts creates an App and calls app.synth() at module level, any test that imports the stack class runs that too. Moving those lines to their own file leaves every resource the same and lets the test build its own stack.
Will the snapshot break every time a Lambda changes?
Not if asset hashes are normalised, which the prompt asks for. The snapshot then changes when the infrastructure changes, a new resource or a changed property, and a code-only Lambda change shows up in the Lambda's own tests instead.
Does it work for Python CDK apps?
Yes. The same assertions module exists in Python as aws_cdk.assertions, and the agent writes pytest tests with Template.from_stack instead. Point input at the directory and say which language.