AWS runner
Deploy a runner into your own AWS account, wire it to Evident, and understand exactly what it holds and what it costs.
This runner runs in your own AWS account, not on your machine and not
on Evident's infrastructure — Evident boots and suspends it on demand instead of you
running evident run yourself (see the local
runner for that path).
Two strategies, one package
Both AWS strategies ship from a single published package,
@evident-ai/runner-cdk (npm install @evident-ai/runner-cdk,
no checkout required to install it):
- Fargate —
EvidentScaleToZeroConstruct. A long-running container that scales itself to zero when idle. Your runner image is anyecs.ContainerImage— a registry reference, no checkout of this repo needed. See the package's GETTING-STARTED.md for the full walkthrough — this page doesn't duplicate it. - MicroVM —
EvidentMicrovmConstruct. A per-session Lambda MicroVM that boots on demand and suspends between messages — the rest of this page. Its runner image has no registry equivalent, because the Lambda MicroVM service builds the image inside your own account rather than pulling one. So instead of an image reference it takes a build context, and this package ships one:stageMicrovmImageContext()combines the published Dockerfile, hook scripts and hook server with your repository. No checkout of this repo is needed either.
What you get, and what stays yours
Evident never holds a key to your AWS account, and the infrastructure you deploy holds no Evident credential at rest. The only Evident secret it stores is a shared HMAC key, and its only job is verification: your controller uses it to check that a request really came from Evident before it starts or suspends anything. It grants no access to Evident, and no access to AWS.
A running runner is the one exception — stated plainly rather than softened. While a runner is running, it does hold one Evident credential: a runner key that Evident issues for that boot so the runner can call Evident back (that is how it streams your conversation and how it reconnects after a suspend). It is not your Evident account credential. It is scoped to that single runner, so it cannot touch any other runner, and it cannot manage your team, your billing or your API keys. It expires on its own within nine hours — longer than the eight hours AWS allows a MicroVM to live, so every cold start gets a fresh one — but nothing revokes it early when a VM stops; expiry is what ends it. And it travels with the VM rather than with your infrastructure: it is written inside the VM at boot and is present in the VM's suspended snapshot.
The runner only ever dials out to Evident — there is nothing inbound to open on your side. Model provider credentials and the runner's durable state stay in your account, in the S3 bucket the stack creates.
One more honest detail: although the HMAC key never appears in the CloudFormation
template or its outputs, anyone in your account with
lambda:GetFunctionConfiguration can read its resolved value from the
controller Lambda's environment. That's acceptable because it is a
verification key — it grants access to nothing of Evident's.
What isn't configurable yet
-
The runner's workspace is fixed at image build time — it ships the repository you pass
to
stageMicrovmImageContext(), checked out at the commit the image was built from. Any repository works: if it commits apnpm-lock.yamlthe image pre-installs its dependencies, and if not that step is skipped and the agent installs on first use. - There is no per-runner repository setting yet.
-
Changing what's baked into the image means rebuilding it — about five minutes, via one
cdk deploy.
Prerequisites
- An AWS account with permission to create Lambda MicroVM images, Lambda functions, IAM roles, and an S3 bucket.
- The AWS CLI configured for that account.
-
cdk bootstrapalready run for that account and the region you'll deploy into. - Node.js and
pnpm. -
npm install @evident-ai/runner-cdk— the image build context ships inside it. No checkout of the Evident repository is required. - A full (non-shallow) clone of the repository your agent will work on, which is baked into the image as its workspace.
- An Evident team where you are an admin or owner — turning on the run-payload option below is admin/owner gated.
Choose a region
The default region is eu-west-1. These are the regions Evident expects
MicroVMs to run in today:
eu-west-1us-east-1us-east-2us-west-2ap-northeast-1
The region is whichever one your own stack deploys into — set it on the stack's
env, as you would for any CDK stack. The construct adds no region check
of its own, so deploying into a region without Lambda MicroVM support fails at the
AWS API rather than at synth; check the list above first, and check AWS's own
documentation if it looks out of date.
Step 1 — Create the pool and connector in Evident
- Create a runner pool in the Evident web app.
- Turn on Auto-provisioning for the pool — this routes one runner per person and marks the pool as MicroVM-backed.
-
In the pool's Connectors section, add a Webhook connector:
- Give it a placeholder HTTPS URL — you'll replace this with the real one in step 3.
- Turn on the run-payload option — this is the one setting the whole thing depends on, and it needs an admin or owner to enable.
- Leave "Message queued (automatic wake)" ticked — it's on by default, and it's what boots a runner for a new message. Don't use "Wake requested (manual wake button)" instead; that's for the manual wake button, a different use case. The form requires at least one event to save.
- Copy the signing secret now — it is shown exactly once. You'll need it in the next step.
You don't need to separately subscribe this connector to a suspend event — turning on the run-payload option already does that for you.
Step 2 — The one cdk deploy
Look up the managed base image for your region:
aws lambda list-managed-microvm-images --region <region> These are service-managed images, so there's nothing to hardcode — always read the ARN and version from that call.
Then deploy your own CDK app — the one where you instantiated
EvidentMicrovmConstruct, passing that ARN and version, the secret you
copied in step 1, and a stageMicrovmImageContext() build context. The
package's
README has the exact snippet.
npx cdk deploy
How you feed in the ARN, version and secret is your stack's call — literals,
CfnParameters, or an SSM lookup. The construct takes plain strings and a
Secrets Manager ISecret, deliberately, so it mints nothing into your
stack. The first deploy stages the context, uploads the image as an S3 asset, builds
the MicroVM image, and wires up the controller; expect about five to six minutes.
A later, routine redeploy is just cdk deploy again. Rotating the doorbell
secret means updating the secret your stack passes in and redeploying. (If you wired
the ARN, version and secret as CfnParameters, CloudFormation reuses their
previous values on an update that omits them.)
Step 3 — Paste the Function URL back into Evident
Once the deploy finishes, read the ControllerFunctionUrl output — from the
CloudFormation console, or:
aws cloudformation describe-stacks \
--stack-name <your stack name> \
--query "Stacks[0].Outputs" Edit the webhook connector's Endpoint URL to that value and save. This is the last wiring step — you don't need to re-enter the secret.
What Evident sets for you
- Evident allocates the durable-state location each runner writes to.
- Each cold boot gets a fresh runner key — the same short-lived, single-runner key described above, not a second thing.
- Machine size defaults to the stack's default shape, and is chosen in the pool's settings.
Verification
Open the pool's settings and confirm the machine-size picker lists the sizes your stack advertises. If it does, Evident reached your controller and the signing key matched on both sides — that's a genuine end-to-end check, and it needs no AWS console.
You can also confirm the stack itself deployed correctly by checking its
ControllerFunctionUrl, MicrovmShapes, and
DurableStateBucketName outputs exist.
For the real end-to-end test, send a message to the pool. Expect a first boot of about 27 seconds, after which the runner comes online. It will boot successfully even without a model provider connected — that's expected, not a failure — but it needs one to actually answer; see model providers.
Troubleshooting
If the machine-size picker can't load shapes, here's what each case usually means:
| What you see | Likely cause |
|---|---|
| No shapes, no error | No webhook connector with the run-payload option on for this pool yet. |
| "Connector disabled" | The webhook connector is toggled off. |
| "URL not allowed" | The endpoint URL isn't a public HTTPS URL. |
| "Couldn't reach the controller" |
Wrong URL, or the Lambda Function URL was removed — check the
ControllerFunctionUrl output.
|
| Controller responded, but with an error |
Usually a mismatched signing secret — re-check the
DoorbellSecret you deployed with against the one Evident showed you.
|
| "Not a valid controller" | The endpoint isn't answering as an Evident MicroVM controller. |
Cost
A runner suspends itself automatically about two minutes after it goes idle — there's nothing for you to switch on for this to happen. And whatever happens, AWS terminates a MicroVM after at most eight hours, so a single boot can never cost more than the ceiling below.
Prices are eu-west-1 on-demand list prices at the time of writing — re-check AWS's pricing page for current rates:
- Memory (ARM): $0.0000038603 / GB-second
- vCPU (ARM): $0.0000291572 / vCPU-second
- Snapshot storage: $0.0001322222 / GB-hour
- Snapshot read: $0.0016403088 / GB
- Snapshot write: $0.0040636422 / GB
There's no vCPU dial — Lambda allocates CPU proportionally at 1,769 MiB ≈ 1 vCPU, so the default 4,096 MiB shape gets 4096 ÷ 1769 = 2.3154 vCPU. The derivation for the default shape:
memory: 4 GB × $0.0000038603/GB-s × 3600 = $0.055588 / h
vCPU: 2.3154 × $0.0000291572/vCPU-s × 3600 = $0.243041 / h
total = $0.29863 / h → ~$0.30 / h That $/hour figure is a calculation from the prices above, not a measured bill. Of the idle and boot timings on this page, only ~27 seconds is a measurement; two minutes and eight hours are configured limits (an idle-timeout default and AWS's MicroVM lifetime cap, respectively), not something Evident measured:
- Running: ~$0.30/hour.
- At most ~$2.39 for the longest possible single session — eight hours at ~$0.30/hour.
- Suspended: ~$0.0024/day, assuming roughly 0.75 GB of snapshot state — effectively free either way. That 0.75 GB is from the spike's runner-shaped test image, not a re-confirmed measurement of the deployed default shape's actual snapshot size.
- ~$0.004 per suspend/resume cycle (writing and reading that state).
When you'll pay the ceiling instead
In two cases, nothing asks the runner to suspend and it runs to the eight-hour cap:
- The webhook connector is switched off while a runner is live.
- A runner dies without a clean shutdown — a crash, or a hard network drop — rather than exiting normally.
Two gaps we haven't closed: whether standing storage for the MicroVM image itself is billed is not yet established, and the S3 buckets plus the controller Lambda carry a small, nonzero cost beyond what's shown above.
Teardown
Before tearing anything down, let any running or suspended runner stop on its own. Then destroy the stack from your own CDK app:
npx cdk destroy The durable-state S3 bucket is retained on purpose and survives cdk destroy, so it keeps costing you money until you delete it yourself. It's retained because it holds each runner's credentials and state, which deleting a
stack must not throw away. Because the bucket is versioned, emptying it
means deleting object versions, not just current objects.
The MicroVM image itself goes with the stack. The CDK bootstrap/staging bucket is separate and shared with other CDK apps in the account — don't delete it blindly.
Next steps
- Model providers — connect an AI provider so your runner can answer.
- Local runner — run OpenCode on your own machine instead.
- CLI reference — every command, flag, and environment variable.
- Troubleshooting — fixes for common issues.