CLI¶
rayito is the SDK's command-line tool: it publishes and lists the image,
prepares the account (rayito setup), prunes old versions, lists, inspects
and kills sandboxes, reads their CloudWatch logs and diagnoses an account
before the first Sandbox.create(). It also deploys the optional stacks
(rayito stack, rayito events, rayito domain), builds declarative
templates (rayito template) and the AI agent as a project
(rayito agent). There is no rayito.toml: configuration is
options and environment variables.
Messages stay in Spanish
The CLI's own messages are written in Spanish, so the literal texts quoted
on this page (sin región: …, falta el access token: …, sin logs: …,
build fallido: …) appear in Spanish. Each one is glossed where it
appears.
| Group | Commands |
|---|---|
rayito image |
publish, list, sizes, prune, zip |
rayito sandbox |
list, info, kill, logs, create, connect, proxy, exec, metrics |
rayito stack |
list, status, deploy, destroy |
rayito domain (experimental) |
deploy, status, destroy |
rayito events |
deploy, status, destroy, list, webhook add, webhook list, webhook remove |
rayito template |
build, status, logs |
rayito agent |
init, build, run, detect, deploy, export, invoke, status, stop, list, delete, template build |
rayito dashboard |
— |
rayito setup |
— |
rayito doctor |
— |
There are two CLIs with the same surface, output and exit codes: the Python
one (the cli extra) and the TypeScript one (the rayito executable of the
npm package). What follows applies to both except where stated otherwise; the
two command trees are compared against testdata/cli/surface.json and
scripts/check_sdk_parity.py --cli. The MCP server is another executable in
the same package, rayito-mcp (MCP server).
Installation¶
The CLI is an extra of the rayito package (it adds typer):
From a checkout of the repository, without installing anything:
Without the extra, rayito prints how to install it and exits with 2.
The rayito npm package declares the rayito executable (Node 20 or
later, ESM only, no CLI dependencies: it uses node:util):
npx rayito --help # without installing anything
npm install --global rayito # or: pnpm add --global rayito
rayito --help
The AWS clients that not every command needs are optional peers of the
package (@aws-sdk/client-cloudformation for stack, events and
domain, @aws-sdk/client-cloudwatch-logs for sandbox logs,
@aws-sdk/client-iam for doctor's IAM simulation,
@aws-sdk/client-service-quotas and @aws-sdk/client-cost-explorer for
the dashboard, among others). A command that needs a missing one fails and
says which package to install. The TypeScript API is async-only: the CLI
does not change because of that.
Two global installs
If you install both CLIs, the first one on the PATH wins.
rayito --version says which one answers ((python) or (node)).
Global options and credentials¶
--profileand--regionbuild theboto3session; without themAWS_REGIONis used and, if missing, the usual chain (AWS_PROFILE,AWS_DEFAULT_REGION, the config file, the machine's role). There is no Rayito API key.- With no resolvable region:
sin región: pasa --region o exporta AWS_REGION("no region: pass --region or export AWS_REGION") and exit code 2, before any call. With no credentials or with an unknown profile, the same. --json: each command writes a single JSON document to stdout and progress to stderr, sorayito --json sandbox list | jqworks.--verbose:INFOlogs from the SDK (reconnections, probes) and the CLI.--version: printsrayito <version> (python). The runtime in parentheses says which of the two CLIs answers when the Python one and the npm package's coexist (rayito <version> (node)): the first on thePATHwins.
Exit codes: 0 success; 1 the operation failed (non-launchable build, a
version that prune could not delete, an unknown id in kill, a doctor
FAIL, an AWS error printed as AWS error <Code>: <Message>); 2 usage or
environment (arguments, no region, no credentials, no extra).
rayito image¶
image publish¶
rayito image publish --artifact image/rayito-image.zip --base-image-version 1 \
--bucket <bucket> [--variant full|slim|poly] [--image-name N] \
[--os-capabilities ALL] [--build-role-arn ARN | --stack-name rayito-m0-iam] \
[--memory-mib 2048] [--timeout-seconds 1800] [--force] \
[--sizes 512mb,1gb,4gb,8gb] [--env K=V]... [--with-efs] \
[--artifact-run-id RUN_ID]
--base-image-version is required and pins the version of the AWS managed
base (imageVersion of list-managed-microvm-image-versions) the image is
built on. There is no need to look it up by hand: with latest the newest one
AWS lists is used and printed (base_image_version=<version>); an explicit
number pins a reproducible build.
--with-efs publishes the image with the amazon-efs-utils that volumes=
needs (EFS volumes): it requires a
zip made with rayito image zip --with-efs, --os-capabilities ALL (rayd
only mounts with CAP_SYS_ADMIN) and the full variant, and its default name
is rayito-base-caps-efs. A zip with the efs marker without --with-efs, or
--with-efs with a zip without it, is rejected before calling AWS.
--sizes publishes, in addition to the baseline (2048 MiB), one image with a
size suffix for each listed name from the same artifact; --env KEY=VALUE
(repeatable) bakes additional image variables into all the images the
invocation publishes. With --sizes, --memory-mib only accepts the default
value (2048): the baseline of --sizes is always the image without a suffix.
See Sizes.
It reproduces the make image-publish pipeline:
- Checks, before calling AWS, that the zip exists and that its variant marker
(
warmup_variantforslim,kernels_variantforpoly) matches--variant, and that theefs_variantmarker is present if and only if--with-efsis passed. - Uploads the zip to
s3://<bucket>/rayito/images/rayd-<12 hex of the sha256>.zip, unless the key already exists (content-addressed key: same zip, same key). With--artifact-run-id RUN_IDthe key israyito/images/runs/<RUN_ID>/rayd-<12 hex of the sha256>.zip: the object belongs only to that run (see below). - Takes the build role from
--build-role-arnor from theBuildRoleArnoutput of the--stack-namestack. - If there is already a
SUCCESSFUL/ACTIVEversion built from that zip with the same configuration (hooks, memory, log group,additionalOsCapabilitiesandbaseImageVersion, the latter compared numerically because the API accepts1and returns1.0), it reuses it and builds nothing;--forcebuilds anyway. Each version costs one week of snapshot storage. - Otherwise,
create-microvm-imagethe first time orupdate-microvm-imageafterwards, and polls every 10 s for the three-state gate: imageCREATED|UPDATED, versionSUCCESSFUL, statusACTIVE. Only then is the version launchable. - Prints the
snapshotBuildsummary and, on the last line,RAYITO_TEMPLATE=<arn>. If the build fails, it prints thestateReasons and the tail of the build logs of the/rayito/<image>group and exits with 1.
--artifact-run-id is for those who publish disposable images in parallel (a
release's acceptance, e2e): two runs of the same commit would share the
content-addressed key, and the first one's cleanup would delete the zip the
second one's image still points to. RUN_ID is a single key segment
(letters, digits and hyphens, 1 to 64, starting with a letter or digit);
any other value is a usage error (2) before calling AWS. The key stays under
rayito/images/, so the permissions below do not change. The --json
summary says in artifactUploaded whether this invocation uploaded the
object (true) or it already existed (false): a cleanup deletes only the
objects its run uploaded. With --sizes, the root (the baseline) is the one
that uploads; the sizes reuse that object and say false. Without the flag
the key is the usual shared one.
--bucket is resolved from the flag or from RAYITO_BUCKET; with neither
it is a usage error (2). The library ships no default bucket: the bucket
belongs to the account that publishes.
S3 permissions of the publishing principal (ImagePublisherPolicy or
CallerPolicy in infra/iam.yaml grant them as is): s3:PutObject and
s3:GetObject on arn:aws:s3:::<bucket>/rayito/* and s3:ListBucket on
arn:aws:s3:::<bucket>. s3:ListBucket is what makes the head-object of a
new artifact answer 404 instead of 403 (without it the CLI uploads the
artifact anyway and a genuinely missing permission surfaces at put-object)
and the only thing rayito doctor's head-bucket needs.
image list¶
rayito image list [--name-filter F] # images: name, state, latestActive/FailedImageVersion, createdAt
rayito image list rayito-base # versions of an image, newest first
With a name or ARN it lists imageVersion, state, status,
baseImageVersion, the S3 artifact name and createdAt.
image sizes¶
For each size in the closed catalog (512mb/1gb/2gb/4gb/8gb,
Sizes), which image of the variant
rayito image publish --sizes has already published (name, published,
imageArn, state, sameArtifact, createdAt) or whether none has. Always
one list-microvm-images filtered by the base name; if any additional size
is published, also one GetMicrovmImageVersion (with no quota of its own) per
published image for sameArtifact — with only the baseline published, no
additional call. It never builds, publishes or launches anything.
sameArtifact compares the codeArtifact.uri of each size's active version
against the baseline's: false detects a size published from a different
zip, without launching any sandbox. --image-name lists the family published
with rayito image publish --image-name <name> --sizes ... (<name>,
<name>-4gb, ...) instead of the variant's.
image prune¶
rayito image prune --dry-run # first: the plan, deleting nothing
rayito image prune [--image-name rayito-base] [--keep 5] [--wait-timeout 600]
Keeps the newest --keep launchable versions, every version that a
non-terminated MicroVM is using (read right before each deletion) and those
that are PENDING, IN_PROGRESS, DELETING or DELETED; deletes the rest
from oldest to newest, one at a time (the API answers ConflictException
while the image is UPDATING/DELETING), with 5/10/20/40/80 s backoff and
first deactivating an ACTIVE version that the API refuses to delete. It
prints the plan table and a JSON summary; exits with 1 if any candidate still
exists. It never deletes the image or its /rayito/<image> log group; when
retiring a whole image, delete both by hand
(Declarative templates).
image zip¶
rayito image zip image image/rayito-image.zip [--variant full|slim|poly] [--sidecar kernel-sidecar] [--with-efs]
--with-efs adds the kernel-sidecar/efs_variant marker, which activates the
Dockerfile's conditional amazon-efs-utils layer (without it, no image
changes). The --json summary reports it in withEfs.
Deterministic zip (fixed dates and modes; without __pycache__, tests,
.venv, caches, uv.lock or other zips) with the Dockerfile at the root.
With --sidecar it first copies kernel-sidecar/ to
image/kernel-sidecar/ with the same exclusions. It prints files, bytes,
variant and the zip's sha256 (with it the S3 key can be predicted). It is the
only command that does not need AWS.
If the directory carries rayd, it must also carry its license notices in
licenses/ (LICENSE, NOTICE and THIRD_PARTY_LICENSES.md): the
Dockerfile copies them to /usr/share/doc/rayd/ and the zip refuses to
package rayd without them. From the repository, make image-licenses
leaves them there, generating THIRD_PARTY_LICENSES.md with cargo-about from
Cargo.lock (the make image-zip* targets already do it).
rayito sandbox¶
rayito sandbox list [--template T] [--template-version V] [--all-states] [--state S]… [--metadata K=V]… [--index-table TABLE]
rayito sandbox info ID [--no-metadata]
rayito sandbox kill ID… | rayito sandbox kill --all [--template T] [--yes]
rayito sandbox logs ID [--log-group G] [--limit 1000] [--since 30m|2h|1d|ISO]
rayito sandbox create [TEMPLATE] [--timeout S] [--metadata K=V]… [--env K=V]… [--detach] [--token-file F] [--user U] [--cwd D]
rayito sandbox connect ID [--user U] [--cwd D] [--env K=V]… [--token-file F]
rayito sandbox exec ID [--background] [--cwd D] [--user U] [--env K=V]… [--timeout 0] [--token-file F] -- CMD…
rayito sandbox metrics ID [--follow] [--interval 5] [--token-file F]
rayito sandbox proxy ID --port N [--local-port M] [--bind 127.0.0.1] [--allow-remote] [--allowed-host H]… [--allow-origin O]… [--max-connections 8]
listomitsTERMINATINGandTERMINATED(AWS keeps listing them for about 20 minutes) unless--all-states; it probes no endpoint.--state(repeatable, case-insensitive:--state suspended) filters by state.--metadata K=V(repeatable) filters by metadata: without--index-tableit is the O(n) probe ofSandbox.list(metadata=)(oneHealthperRUNNINGsandbox); with--index-table TABLE(optional, off by default) it uses the metadata index in that DynamoDB table (infra/metadata-index.yaml): onedynamodb:BatchGetItemper page, no probes, and also over paused sandboxes (rayito sandbox list --metadata user=42 --state suspended --index-table rayito-sandboxes). Only sandboxes created withindex=appear; with--jsoneach row carries itsmetadata. Cost and IAM in Metadata index.--index-tablewithout--metadatais a usage error (exit code 2) and does not call DynamoDB: the index is only useful for filtering by metadata.--all-statescannot be combined with--state,--metadataor--index-table(exit code 2).infodoes aget-microvmand, on aRUNNINGsandbox, reads its metadata with aHealth(a single-use JWE, dedicated channel);--no-metadataavoids it. Metadata are not secrets; the endpoint is a hostname; there is no token to print.killterminates each id and printsterminatedornot found(exit code 1 if any did not exist).--alllists the live ones, asks for confirmation (unless--yes) and terminates them; it is mutually exclusive with ids.logsresolves the/rayito/<image>group (or--log-group) and the sandbox'sYYYY/MM/DD[<version>]<id>stream; if the exact name does not exist it walks up to 10 pages of streams by last event looking for those ending in]<id>. It prints<ISO timestamp> <message>(--json: list of{timestamp, message, stream}). There are runtime logs only if the sandbox was launched withexecution_role_arnandlogging="cloudwatch"; if there is no stream or group:sin logs: el sandbox se lanzó con logging disabled, sin executionRoleArn, o en otro grupo (--log-group)("no logs: the sandbox was launched with logging disabled, without executionRoleArn, or in another group") and exit code 1.
create, connect, exec and metrics¶
The four operational commands of E2B's CLI that Lambda MicroVMs can serve.
Those that need to talk to rayd use the sandbox's access token, which
never travels in argv (it would show up in ps) nor is printed:
--token-file F(the file's contents, without surrounding whitespace) orRAYITO_ACCESS_TOKEN; if both are present, the file wins. With neither, exit code 2 withfalta el access token: --token-file o RAYITO_ACCESS_TOKEN("missing the access token: --token-file or RAYITO_ACCESS_TOKEN").create --detachwrites the token to--token-filebeforerun-microvm(withO_CREAT | O_EXCLand mode0600: an existing file is exit code 2), so a failure to write it never leaves an orphan VM. WithoutRAYITO_ACCESS_TOKENor--token-file,--detachis exit code 2. On Windows the mode is ignored by the system: it leaves the file in your user profile.
Behavior:
createwithout--detachopens an interactive terminal in the sandbox and terminates it on exit (likee2b sandbox create); with--detachit prints thesandbox_id(--json:sandbox_id,endpoint,template,template_versionandexpires_at, never the token) and exits with 0.--timeoutis the nativetimeout(3600 by default).connectresumes a suspended sandbox and opens the terminal; it does not terminate it.execrunsCMD…(joined withshlex.join) and forwards stdout and stderr as they arrive; it exits with the remote code, or 124 if the server's--timeoutexpired (timeout del comandoon stderr, "command timeout"). With--backgroundit prints thepidand exits with 0.metricsprints theget_metrics()snapshot (table, or a JSON object with--json);--followrepeats every--intervalseconds until Ctrl-C (exit code 0) or until the sandbox disappears (exit code 1). Connecting wakes a suspended sandbox.
A complete walkthrough, with the token in a file that only your user can read:
export AWS_PROFILE=<your-profile> AWS_REGION=us-east-1
mkdir -p ~/.rayito && chmod 700 ~/.rayito # --detach creates the file, not the directory
rayito sandbox create rayito-base --detach --timeout 1800 \
--metadata team=data --token-file ~/.rayito/demo.token # prints microvm-<id>
rayito sandbox exec microvm-<id> --token-file ~/.rayito/demo.token -- python3 -c 'print(40 + 2)'
rayito sandbox exec microvm-<id> --background --token-file ~/.rayito/demo.token -- sleep 600
rayito --json sandbox metrics microvm-<id> --token-file ~/.rayito/demo.token
rayito sandbox connect microvm-<id> --token-file ~/.rayito/demo.token # terminal; Ctrl-D to exit
rayito sandbox kill microvm-<id>
The same token works in the SDKs: Sandbox.connect("microvm-<id>",
access_token=open(path).read().strip()).
The terminal puts yours in raw mode on POSIX (restored on exit; Ctrl-C
travels to the sandbox as \x03, never as a local SIGINT) and forwards size
changes (SIGWINCH); on a Windows console it translates the arrows and
polls the size every second; with piped stdin it forwards the bytes as they
are and sends \x04 at the end. The exit code is the remote shell's.
proxy¶
Exposes a guest port at http://<bind>:<local-port> (by default
--local-port equals --port), for local development: curl, a browser or
any HTTP/1.1 client against a server that the sandbox is already serving.
WebSocket passthrough (upgrade) is implemented, not measured against AWS. The
sandbox's access token is never needed, only the proxy JWE.
rayito sandbox proxy microvm-<id> --port 8000
# http://127.0.0.1:8000 → microvm-<id>:8000
# with cookies isolated from other local apps: http://microvm-<id>.localhost:8000
curl http://127.0.0.1:8000/
- It rejects
--port 9000(the lifecycle hooks port) and any value outside 1-65535, without calling AWS. --bindother than127.0.0.1/::1/localhostneeds--allow-remote(otherwise, a usage exit): anyone who reaches that port uses the sandbox with the same access as whoever launched the proxy.--bind 0.0.0.0/::additionally needs--allowed-host.HostandOrigin: it only forwards ifHostis127.0.0.1,localhostor[::1]with the local port, the--bindaddress,<id>.localhostor an--allowed-host(otherwise,421), and if theOrigin, when present, is one of those same origins or an--allow-origin(otherwise,403). So a web page open in your browser does not reach the sandbox through DNS rebinding, a cross-site POST or aWebSocketfrom another origin (Local proxy).- At most
--max-connections(8) forwarded connections at a time; the next one gets503. - Headers: it strips any
x-aws-proxy-*the client brings, setsHostto the sandbox endpoint, addsX-aws-proxy-auth(the current JWE) andX-aws-proxy-port, and forcesConnection: closeexcept on an upgrade request (Upgrade+Connection: upgrade, WebSocket). It only forwards the first request of each connection, with its body delimited byContent-Lengthorchunked(400if ambiguous); an upgrade to which the sandbox does not answer101is forwarded withConnection: closeand closed. With no current JWE or no connection to the sandbox it answers502and writes the reason to stderr; the header has to arrive within 30 s and the connection to the sandbox open within 30 s. It never logs the JWE, the headers, the bodies or the paths of what goes through the proxy (Security). - The JWE is renewed at 45 min with the same
TokenRefresherthat the SDK's gRPC channel uses: a new one is not minted on every request. - A
SUSPENDEDsandbox with auto-resume is woken by the first request that reaches the proxy (which does bill compute, plus a snapshot read on resume: Limits and Pricing for the price per GB). - $0 from AWS beyond
GetMicrovm+CreateMicrovmAuthToken(free, 50 TPS quota per account/region; ~1 mint every 45 min per running proxy); no new resources. Ctrl-C stops the refresher and closes the listener. - IAM:
lambda:GetMicrovmandlambda:CreateMicrovmAuthTokenon the MicroVM (already inSandboxLauncherPolicyand inCallerPolicyofinfra/iam.yaml; nothing new to deploy to use the proxy).
rayito stack¶
rayito stack list
rayito stack status <component> [--stack-name N]
rayito stack deploy <component> [--param K=V]... [--artifact-bucket B] [--tag K=V]... [--stack-name N] [--yes]
rayito stack destroy <component> [--stack-name N] [--yes]
The OptionalStack convention:
each optional feature with its own infrastructure is a CloudFormation stack
in your account, and nothing is deployed unless you ask for it.
listprints the catalog (name, whether it is implemented and idle cost) without calling AWS.deployprints the component's "Cost and activation" block and the parameters that change, and asks for confirmation unless--yes(or--json). On a stack that already exists, the parameters you do not repeat keep their current value; defaults only apply on creation.--artifact-bucketis required for a component with Lambda code (events-webhooks): that is where the code is uploaded, atrayito/stacks/<component>/<sha256>.zip, only if the bucket belongs to your account and comparing the content of an object that already exists.statusis aDescribeStacks: the stack's state and outputs.destroysays what is kept and asks for confirmation unless--yes.
rayito domain¶
rayito domain deploy --public-domain D --certificate-arn ARN [--alternate-domain-name H]... [--stack-name N] [--yes]
rayito domain status | destroy [--stack-name N] [--yes]
Custom domain (experimental, not
yet verified end to end on real AWS): a facade over
rayito stack deploy custom-domain (and status/destroy) with
CustomDomain's names. deploy validates --public-domain and each
--alternate-domain-name before calling AWS, asks for confirmation unless
--yes and prints what to point the CNAME at. The ACM certificate has to be
in us-east-1.
rayito events¶
rayito events deploy --artifact-bucket B --log-group-name G [--reconciler-interval-minutes 5] [--tag K=V]... [--yes]
rayito events status | destroy [--yes]
rayito events list [--sandbox-id ID] [--type T]... [--limit 100] [--order desc|asc]
rayito events webhook add <url> --secret-name S --type T [--type T]...
rayito events webhook list
rayito events webhook remove <webhook-id>
A shortcut for rayito stack deploy events-webhooks plus webhook management
and event querying (Events and webhooks).
All accept --stack-name (default rayito-events-webhooks). deploy prints
the cost (≈ $0.40/month at rest, the HMAC secret) and asks for confirmation
like rayito stack deploy.
rayito template¶
rayito template build <spec.py> --name N --bucket B [--memory-mb 2048] [--force] [--timeout 1800]
rayito template status <name> [--version V]
rayito template logs <name> [--limit 500]
Builds a declarative template: build
runs spec.py (which must define a module variable template holding a
rayito.Template), uploads the context to --bucket under
rayito/templates/ and creates or updates the --name image, printing the
build log. Each new version costs snapshot storage, just like
rayito image publish; old ones are deleted with
rayito image prune --image-name <name>. status and logs only read:
without --version, the most recent version.
rayito agent¶
rayito agent init [DIR] [--runtime R] [--language python|typescript] [--provider P] [--model ID]
[--region R] [--force]
rayito agent build --bucket B [--file PATH] [--force] [--timeout 1800]
rayito agent run PROMPT [--file PATH] [--session-id ID] [--model ID] [--stream]
rayito agent detect [PATH] [--framework F] [--language L] [--entry E] [--protocol P]
[--model-id ID] [--model-provider P] [--model-base-url URL] [--write]
rayito agent deploy [PATH] [--file PATH] [--timeout S] [--port N] [--token-file F] [--keep-on-failure]
[--framework F] [--language L] [--entry E] [--protocol P]
[--model-id ID] [--model-provider P] [--model-base-url URL]
[--memory MIB] [--max-sessions N] [--sessions shared|dedicated]
[--min-vms N] [--max-vms N] [--warm N] [--idle S] [--queue N] [--queue-timeout S]
[--env K=V]... [--allow-out DEST]... [--bucket B] [--secret PROVIDER=NAME]...
[--create-secret] [--secret-env NAME=SECRET]... [--secret-env-from SECRET]...
[--create-secrets-from FILE] [--check-env]
[--base-artifact ZIP] [--yes] [--dry-run]
[--target microvm|agentcore] [--tag K=V]... [--bedrock-model ID]...
[--readable-secret NAME]... [--idle-session-timeout S] [--max-session-lifetime S]
[--external-model] [--scale-in-after S] [--no-save-recipe]
[--renew-gateway-keys]
rayito agent export --target docker|agentcore --out DIR [--file PATH] [--overwrite]
rayito agent invoke SANDBOX_ID [PROMPT] [--session-id ID] [--input JSON | --input-file F]
[--stream] [--token-file F] [--target microvm|agentcore]
[--renew-gateway-keys]
rayito agent status SANDBOX_ID [--token-file F] [--target microvm|agentcore]
rayito agent stop SANDBOX_ID [--target microvm|agentcore] [--session-id ID] [--keep-recipe]
rayito agent list --target agentcore
rayito agent delete NAME --target agentcore [--yes]
rayito agent template build --bucket B [--name rayito-agent] [--base rayito-base-caps] [--memory-mb 2048]
[--no-deepagents] [--no-prefetch] [--force] [--timeout 1800]
Since 0.14.0 the init, build, run, deploy, export, invoke,
status and stop commands work with an agent project (rayito-agent.toml,
--file defaults to the current directory): see
Deploy your agent. init and export make no
AWS call; init overwrites nothing without --force (exit code 2), deploy
prints the sandbox id, the URL and the port (with --json, sandboxId, url
and port) and never the access headers, and --stream prints the events as
they arrive (with --json, one JSON line per event). deploy saves the
sandbox access token to --token-file (or uses RAYITO_ACCESS_TOKEN) and
exits with 2 without creating anything if it has neither; invoke and status
read it the same way, and stop does not need it. If the startup fails,
deploy prints the cause (the failure code and the end of the app's standard
error, with no environment values or credentials) and terminates the sandbox,
unless --keep-on-failure is given, which leaves it alive for debugging (it
bills until rayito agent stop). With an HttpApp that declares its own
routes without protocol = "raw", deploy warns that they are not reachable
from outside. run and invoke print tokens=desconocido ("unknown") (and
usageReported: false with --json) when the agent reported no tokens.
init --runtime custom writes an HTTP app ([runtime.app] with protocol =
"raw", requirements, install and a serve.py), and init --runtime
langgraph, a plain LangGraph graph.
rayito agent detect and rayito agent deploy (since 0.14.0) work with an
agent you already have, with no rayito-agent.toml: they detect the language,
framework, entrypoint, install and provider by reading the files (they do not
run your code), and the flags set what detection gets wrong. detect makes no
AWS call and with --write saves what it detected as rayito-agent.json;
deploy --dry-run prints the detection, the plan and the cost without calling
AWS. deploy deploys a fleet
(Several sessions and several VMs): --min-vms
live VMs and --warm parked slots; with --secret provider=name it uses an
existing secret and with --create-secret it creates a missing one from the
standard variable of the gateway's preset (AWS_BEARER_TOKEN_BEDROCK for a
[gateways.model] preset = "bedrock"), under exactly the name the gateway reads
(it costs $0.40 per month); it creates no buckets
(rayito setup does; use --bucket, RAYITO_BUCKET, the cdk bootstrap one
and, if it does not exist, the BucketName output of the rayito-m0-artifacts
stack that rayito setup created) and only publishes the base image with --base-artifact and --yes. invoke,
status and stop accept the fleet name (rayito agent stop <name> terminates
all its VMs); the session_id that invoke returns on a fleet with several VMs
identifies the VM, and passing it with --session-id continues the
conversation. Messages and help are in Spanish. See
Deploy your agent.
Since 0.17.0, deploy saves the
fleet recipe in Parameter
Store after starting the fleet (--no-save-recipe does not save it): with it,
invoke, status and stop with the fleet name rebuild it as it was
deployed, and status prints the real scaling or, without project or recipe,
members: N (escalado desconocido: sin proyecto ni receta) (with --json, the
scalingSource key). stop <name> deletes the recipe (--keep-recipe keeps
it). A recipe warning (recipe_access_denied, recipe_not_saved,
recipe_renewal_ignored, recipe_too_large) goes to stderr and, with --json, to warnings; it never
fails the deploy. --scale-in-after S sets the idle seconds after which a VM
above --min-vms ends (default 900, minimum 60). --renew-gateway-keys renews
the short-term Bedrock key of the bedrock gateways before creating each VM
(Secret gateway).
With --target agentcore, those three flags exit with 2
(option_not_supported). --env rejects, before calling anyone, a name that
looks like a secret (*_TOKEN, *_KEY, *_SECRET, *_PASSWORD..., with a
PASS, PASSWD, PAT, CREDENTIAL or CREDENTIALS segment, such as
DB_PASS, or with AUTH or BEARER as the last segment or next to TOKEN,
KEY or HEADER, such as X_AUTH or AUTH_HEADER; case-insensitive): use
--secret-env or --secret-env-from. AUTH_MODE, AUTH_URL or
AUTHOR_NAME are accepted.
invoke with a fleet name accepts --renew-gateway-keys: it renews the
gateways' Bedrock key before each new VM the fleet creates, signed with your
credentials, because the recipe does not turn it on by itself (without the
flag it warns recipe_renewal_ignored if the recipe asked for it). With a
sandbox id it exits with 2 without calling anyone, and with
--target agentcore, with 2 (option_not_supported).
With several graphs in langgraph.json, detect and deploy accept
--graph NAME (exclusive with --entry). Instead of PROMPT, invoke
accepts --input JSON or --input-file F (- reads standard input): the input
object of a graph with its own schema; exactly one of the three, or it exits
with 2 before calling anything. The graph's output (output) is printed as
JSON, and with --json it goes in the output key. See
Several graphs and structured input.
With --secret-env NAME=<secret>[#key] and --secret-env-from
<secret>[,prefix=P][,keys=A|B] (repeatable, on both targets) the agent
receives Secrets Manager values as environment variables, added to the
[secret_env] and [[secret_env_from]] of the file; --create-secrets-from
FILE.env creates (or updates) a JSON secret with the values of that .env,
shows only the names and asks for --yes (it costs $0.40 per month), and
--check-env warns about the .env.example variables that receive no value.
See Secrets as environment variables.
--protocol accepts agentcore, json, raw and, since this version,
langgraph-api (experimental): on a project with langgraph.json it serves
the graph with langgraph dev and its LangGraph Platform API instead of
importing it; without langgraph.json it fails with invalid_value. See
LangGraph Platform API.
Builds the AgentTemplate image
(Agent templates): it starts
from --base (an image already published with rayito image publish) and
installs OpenCode, ripgrep and, unless --no-deepagents, the deepagents
environment, all pinned by hash. --no-prefetch omits the daemon that
preloads the binaries after each snapshot restore. No spec file: the recipe is
the SDK's. It prints template_id= and build_id= (with --json,
templateId, buildId and alias); a failed build is build fallido: …
("build failed") and exit code 1.
It is built once: the agent's normal start is
Sandbox.create(template="rayito-agent", ...) + sbx.agent.run(...), with no
pool. Prefetch and warm pools are optional:
What do I use?. Each new version
costs snapshot storage (Pricing); old
ones are deleted with rayito image prune --image-name <name>.
--model-id, --model-provider and --model-base-url (on detect and
deploy) pin the model when your code
picks it from its configuration: the id, the gateway (openai-compatible,
litellm…) and the https URL of your LLM gateway, which becomes its
upstream. With a project file they behave like --entry: what the file says
wins. An unknown --model-provider gives invalid_value on model.provider.
See Model chosen by your code.
agent with --target agentcore¶
Since 0.15.0, rayito agent deploy --target agentcore
deploys the agent to Amazon Bedrock AgentCore Runtime instead of a MicroVM
fleet, and invoke, status, stop, list and delete operate it. Without
--target, or with --target microvm, everything is as in 0.14. Full guide:
Deploy to AgentCore.
Cost and activation
- Turns it on:
--target agentcoreinrayito agent deploy.--dry-runmakes no AWS call. - AWS resources and calls: one CloudFormation stack per agent
(
rayito-agentcore-<name>), one CodeBuild build for each new content and one AgentCore runtime. - Approximate cost (us-east-1, list prices, checked on 2026-10-19): runtime at $0.0895 per vCPU-hour and $0.00945 per GB-hour of actual use; build at $0.0034 per minute (100 minutes a month free); image in ECR at $0.10 per GB-month. More in Pricing.
- IAM: Before you start.
- How to turn it off:
rayito agent delete <name> --target agentcore. - Example:
rayito agent deploy ./my-agent --target agentcore --yes.
| Option | Commands | What it does |
|---|---|---|
--target (microvm or agentcore) |
deploy, invoke, status, stop (on list and delete it is required and only agentcore is valid) |
Where it is deployed. Default: microvm |
--tag K=V |
deploy |
Tag for the rayito-agentcore-<name> stack and the runtime; repeatable; useful if the organization requires tags |
--bedrock-model ID |
deploy |
Bedrock model or inference profile the runtime role may invoke; repeatable. Default: the project's model |
--readable-secret NAME |
deploy |
Secrets Manager secret the runtime role may read; repeatable. Default: none |
--idle-session-timeout S |
deploy |
Seconds without use after which AgentCore ends a session's microVM (60-28800, default 900) |
--max-session-lifetime S |
deploy |
Maximum lifetime of a session's microVM (60-28800, default 28800) |
--external-model |
deploy |
Allows a model outside Bedrock: the role gets no Bedrock permission you do not ask for and your code obtains the key (--readable-secret). Without it, a provider other than bedrock gives provider_unsupported (guide) |
--session-id ID |
stop |
The session whose microVM is stopped (StopRuntimeSession); with --target agentcore it is required |
--yes |
deploy, delete |
Do not ask for confirmation (required with no terminal or with --json) |
The new options, except --target, only apply with --target agentcore:
without it they give option_requires_agentcore (exit 2). With
--target agentcore, the MicroVM options that have no equivalent (--min-vms,
--max-vms, --warm, --memory, --port, --timeout, --idle, --secret,
--create-secret, --token-file, --keep-on-failure, --base-artifact,
--allow-out) give option_not_supported (exit 2) before calling AWS; the
full table says what
each one does and why.
deploy --target agentcoreprints the plan (three steps: stack, image and runtime), theSeguridad:section (AgentCore has no Rayito secrets gateway: the agent gets credentials from the runtime role), the warnings and the approximate cost, and asks for confirmation (¿Desplegar en AgentCore?). With--dry-runit stops there without calling AWS; with no terminal or with--json,--yesis required (needs_confirmation, exit 2). When done it printstarget=agentcore,name,runtime_id,runtime_arn,version,regionandlogs, and how to invoke it.invoke NAME PROMPT --target agentcore: the argument is the agent name;--session-idand--streamwork as they are.--token-filegivesoption_not_supported: AgentCore authenticates with SigV4.status NAME --target agentcoreprints the runtime's state, its version, the image, the region and the log group.stop NAME --target agentcore --session-id IDends that session; without--session-idit givessession_required(exit 2).list --target agentcorelists the region's Rayito agents (<name> runtime=… id=… version=… status=…) or says there are none.delete NAME --target agentcoredeletes the runtime, therayito-agentcore-<name>stack (ECR repository with its images, CodeBuild project and logs, and the two roles) and the runtime's log group; only what Rayito created for that name. It asks for confirmation (--yesskips it; with no terminal or with--json,delete_needs_confirmation, exit 2). With nothing to delete, it exits 0.
Exit 2 (usage or environment): unsupported_region, option_not_supported,
option_requires_agentcore, target_unsupported, provider_unsupported,
network_policy_unsupported, name_invalid, name_conflict, model_required (reserved: not raised today),
image_missing, lifecycle_invalid, lifecycle_order, tags_invalid,
env_invalid, iam_resource_invalid, raw_protocol, no_bucket, bucket_region, needs_confirmation,
delete_needs_confirmation and session_required. Exit 1 (what fails in
AWS): stack_blocked, stack_failed, image_build_failed,
image_build_timeout, build_quota, image_too_large, runtime_blocked,
runtime_failed, runtime_timeout, runtime_not_found, delete_failed,
access_denied and aws_error. What each means:
Errors.
With --json, each command prints a single document:
| Command | Keys |
|---|---|
deploy --dry-run |
dryRun, target, detection, plan (target, name, region, runtimeName, stackName, repositoryName, buildProjectName, imageTag, bucket, bucketSource, network, bedrockModels, readableSecrets, environment, lifecycle, tags, steps, security, warnings, cost) |
deploy |
target, name, region, runtimeName, runtimeId, runtimeArn, runtimeVersion, status, imageUri, stackName, logGroup, steps |
status |
target, name, region, runtimeName, runtimeId, runtimeArn, runtimeVersion, status, imageUri, logGroup |
list |
target, region, agents (name, runtimeName, runtimeId, runtimeVersion, status) |
delete |
target, name, region, runtimeDeleted, stackDeleted, logGroupDeleted |
stop |
target, name, sessionId, stopped |
| an error | {"error": {"code", "message"}, "exitCode"} on stdout and the line rayito: <message> on stderr, like rayito setup |
Each step (steps) carries resource (stack, image or runtime), name,
action and status; in the plan, action is always planned.
rayito dashboard¶
rayito dashboard [--port N] [--allow-actions] [--cost-explorer]
[--events-stack NAME] [--log-group GROUP]
[--theme FILE] [--logo FILE]
[--account NAME=ROLE_ARN ...] [--external-id ID] [--open]
rayito [--region R] dashboard cloudwatch [--log-group GROUP ...]
[--log-group-prefix PREFIX] [--otlp] [--quota] [--output FILE]
The local management dashboard, identical in both CLIs (same page, same
/api/v1 API, same headers and same Host, Origin and CSRF checks): a server on 127.0.0.1 (random port unless
--port) with a page and the /api/v1 API over your AWS credentials, until
you press Ctrl+C. It prints the bootstrap URL only once, with a
single-use token. By default it is read-only: --allow-actions enables
kill, suspend and resume with confirmation and a queue that respects the TPS;
--cost-explorer allows querying billed cost (each query costs $0.01, also
the "Ignorar la caché" (ignore cache) button, and startup announces it);
--events-stack enables the events view (DynamoDB reads, paid though
minimal); resuming with --allow-actions bills compute again; --theme
(.json or .css, or RAYITO_DASHBOARD_THEME) and --logo (PNG or SVG, or
RAYITO_DASHBOARD_LOGO) change the palette and the logo, and are validated
before opening the port. It does not support --json. Exit code 0 on close
and 2 if the port is invalid or busy or the region or credentials are
missing. --account (repeatable, opt-in) adds other read-only accounts
through assumed roles, with --external-id if the roles require it;
rayito dashboard cloudwatch prints the JSON of a CloudWatch dashboard
(/rayito/* logs, --otlp, --quota) without calling AWS or needing
credentials (generating it is free; deploying it costs $3 per month per
dashboard beyond the 3 free ones and $0.005 per GB scanned in each Logs
Insights widget, and --quota requires the quota-alerts stack, ~$0.30 per
month); see
Dashboard: CloudWatch, accounts and alerts.
Full guide in
Management dashboard,
with the step-by-step walkthrough and screenshots
(the dashboard summarizes it in its Help entry),
defenses in Security. To have it always
available inside your account, with sign-in and audit:
rayito stack deploy dashboard --artifact-bucket B
(Dashboard in your account).
rayito setup¶
rayito [--profile P] [--region R] [--json] [--verbose] setup
[--bucket BUCKET] [--artifact PATH] [--tag K=V ...] [--yes] [--dry-run]
[--caps-image]
Prepares the account and region for Rayito in one idempotent command, like
cdk bootstrap. Step-by-step tutorial: Set up AWS.
| Option | What it does |
|---|---|
--bucket BUCKET |
Artifacts bucket in the same region; by default RAYITO_BUCKET, the IAM stack's one, the CDK bootstrap one or a new rayito-artifacts-<account>-<region>. If it does not exist, it is created with that name (rayito-m0-artifacts stack). |
--artifact PATH |
Already verified image zip (e.g. with cosign); without it, rayito-image.zip is downloaded from the rayd-v<SDK version> release and checked against its SHA256SUMS. Only the full variant zip, without EFS, is valid. |
--tag K=V |
Etiqueta K=V; repetible. Se aplica a las pilas que crea setup (rayito-m0-artifacts y rayito-m0-iam) y CloudFormation la propaga a sus recursos; útil si la organización exige etiquetas. (Help text, in Spanish like the rest of the CLI: K=V tag, repeatable; applied to the stacks setup creates and propagated by CloudFormation to their resources; useful if your organization requires tags. Reused stacks are not retagged and the image gets none.) |
--yes |
Do not ask for confirmation (required without a terminal or with --json if there is anything to create). |
--dry-run |
Only reads the account and shows the plan; creates or changes nothing. |
--caps-image |
Also publish rayito-base-caps, the base of the MicroVM agent (the same image with additionalOsCapabilities ALL, from the same zip). It is one more image version that costs money, so it is off: without the option the step shows as skip and neither reads nor writes that image. rayito agent deploy on MicroVM needs it. |
RAYITO_BUCKET is read by the command, not by the parser, like rayito doctor.
With tags, if your organization requires them:
The plan is always four steps, in this order:
| Resource | Possible actions | Writes | Asks for confirmation |
|---|---|---|---|
bucket (rayito-m0-artifacts stack if created) |
create, reuse, wait |
create |
create |
iamStack (rayito-m0-iam stack) |
create, update, reuse, wait |
create, update |
create, update |
baseImage (rayito-base image) |
publish, reuse, wait |
publish |
publish |
capsImage (rayito-base-caps image) |
publish, reuse, wait, skip |
publish |
publish |
- Bucket, in two phases. Reuse: the first that exists of
--bucketorRAYITO_BUCKET(if you give an explicit one, it is the only candidate), theArtifactBucketparameter of the IAM stack or thecdk bootstrapbucket of that account and region (default qualifier), each with oneHeadBucket. Exists in the region:reuse(sourceargument,environment,iamStackorcdkBootstrap). Exists in another region:bucket_region. Exists but is not accessible (403):bucket_unavailable, except thecdk bootstrapone, which is skipped. Does not exist: with--bucketorRAYITO_BUCKET, it is created with that name; if it is the IAM stack's or thecdk bootstrapone, the next candidate is tried. An account with a reusable bucket never reaches the second phase or reads anything more. Creation: with no reusable bucket,createwith therayito-m0-artifactsstack (templateinfra/artifact-bucket.yaml), with the explicit name or, otherwise,rayito-artifacts-<account>-<region>(sourcerayitoDefault). If that stack already exists and is complete,reuse(sourceartifactStack); in progress,wait; blocked,stack_blocked. The created bucket is encrypted (SSE-S3), with all public access blocked, ACLs disabled, TLS only and therayito/images/objects expiring after 7 days; deleting the stack keeps it. A bucket that already exists with the default name and does not belong to that stack is not adopted (bucket_taken): if it is yours, pass it with--bucket. - IAM stack: if it does not exist,
createwithArtifactBucket=<bucket>andTemplateFingerprint, the sha256 of theinfra/iam.yamlthe SDK ships. InCREATE_COMPLETE,UPDATE_COMPLETEorUPDATE_ROLLBACK_COMPLETEand with theBuildRoleArnoutput,reuseonly if itsArtifactBucketis the plan's and itsTemplateFingerprintis this SDK's; otherwiseupdatewith this SDK's template (the other parameters keep their value). Since 0.17.1 a stack from an earlier version, or deployed by hand, is updated this way even if the bucket does not change: the plan says «actualizar a la plantilla infra/iam.yaml de este SDK» andpreviousBucketisnull. A stack created with the template of 0.6.1 or earlier getsLegacyCallerPolicy=true, which keeps the descriptionCallerPolicywas created with: IAM cannot change it and CloudFormation would replace the policy, whose fixed name collides with itself (the update would roll back). A stack that a newer Rayito deployed (itsrayito:sdk-versiontag) never goes back to this SDK's template: with the same bucket it isreuse(«ya existe (…) con la plantilla de Rayito X, más nuevo que este SDK: se conserva»,stackSdkVersionin--json) and, if the plan changes its bucket,stack_newer(exit 2). That way a CI job on an earlier version does not undo a later version's permissions. When it updates the stack,setupsends again the tags it already had, with the--tagones on top: a tag from an earlier run is kept even if you do not repeat--tag(to remove it, userayito stack deployor the console). In a*_IN_PROGRESSstate,wait(and, once it ends,updateif it still has another bucket or another template); inDELETE_IN_PROGRESS,ROLLBACK_COMPLETEor*_FAILED,stack_blocked. - Image: if
rayito-basedoes not exist,publish; with aPENDINGorIN_PROGRESSversion,wait; with aSUCCESSFULandACTIVEversion,reuse(whateverraydit was built from;rayito doctor --launchwarns about an old one andrayito image publishupdates it); with only failed or inactive versions,publish.publishuses--artifactor therayd-v<SDK version>release and thelatestof AWS's managed base. - Image with capabilities (since 0.17):
rayito-base-caps, the base thatrayito agent deployuses on MicroVM. It is decided like the image and published from the same zip (one download) withadditionalOsCapabilities=["ALL"], likerayito image publish --os-capabilities ALL. Only with--caps-image: without it the step isskipand the image is neither read nor published. Ifrayito agent deploy(MicroVM) later does not find it, it fails with a message that asks forrayito setup --caps-image.
The plan is ready when every step is reuse (or skip). It asks for confirmation
if any step is create, update or publish: on a terminal, with
¿Preparar la cuenta? [y/N]:; without a terminal or with --json, --yes is
required (needs_confirmation, exit 2). A wait costs nothing new and does not
ask. After applying, it runs rayito doctor (without --launch) on
rayito-base and the chosen bucket, and ends with RAYITO_TEMPLATE=<arn> and
RAYITO_BUCKET=<bucket>. The first run takes about 10–12 minutes, almost all of
it the image snapshot on AWS; an already prepared account finishes in seconds.
On an account with no bucket at all (with a reusable one, the first line says
reutilizar (reuse) and there is no bucket cost line):
rayito setup: cuenta 123456789012, región us-east-1
bucket rayito-artifacts-<account>-<region>: crear con la pila rayito-m0-artifacts (nombre por defecto de Rayito)
pila de IAM rayito-m0-iam: crear
imagen rayito-base: publicar desde rayd-v0.17.0 (≈ 10 min)
imagen con capacidades rayito-base-caps: omitida (sin --caps-image)
Coste aproximado:
bucket de artefactos: los zips de la imagen caducan a los 7 días (regla de ciclo de vida)
pila de IAM: gratis
imagen: ≈ $0,04 por semana por versión publicada (mínimo una semana)
zip de la imagen en el bucket: céntimos
no se creó ni cambió nada (--dry-run)
Exit codes. 0: success, --dry-run, or nothing to do with a doctor
without FAIL. 1: the operation fails (stack_blocked, stack_incomplete,
release_download, checksum_missing, checksum_mismatch,
image_build_failed, a "no" at the confirmation, a doctor FAIL or an
untranslated AWS error). 2: usage or environment (unsupported_region,
bucket_unavailable, bucket_region, bucket_taken,
artifact_stack_conflict, artifact_missing, artifact_variant,
needs_confirmation, stack_newer, and the usual ones: no region, no
profile or no credentials). What to do with each:
Troubleshooting.
With --json a single document goes to stdout and progress to stderr. Its
keys, in this order: rayito (SDK version), region, account (null if the
plan failed), dryRun, ready, steps, cost, result, doctor, error
and exitCode. Each element of steps carries resource (bucket,
iamStack, baseImage or capsImage), name, action (create, update,
reuse, wait, publish or skip), source (argument, environment, iamStack,
cdkBootstrap, artifactStack, rayitoDefault, release, artifact or null), status, imageVersion,
release, previousBucket and stackSdkVersion (the Rayito version that
deployed the IAM stack, only if it is newer than this SDK and is kept;
otherwise null). The imageVersion of a publish step is
null in the plan and, once applied, the version just published (since
0.17.1; before, it stayed null). result (bucket, imageArn,
imageVersion, artifactUploaded, capsImageArn and capsImageVersion, the
last two null without --caps-image) is null until the preparation finishes;
doctor is the document of rayito --json doctor, or null with --dry-run
and if the preparation stopped earlier; error is {"code", "message"} or
null. On an error the message also goes to stderr as rayito: <message>.
{
"rayito": "0.17.0",
"region": "us-east-1",
"account": "123456789012",
"dryRun": true,
"ready": false,
"steps": [
{"resource": "bucket", "name": "amzn-s3-demo-bucket", "action": "reuse",
"source": "argument", "status": null, "imageVersion": null,
"release": null, "previousBucket": null,
"stackSdkVersion": null},
{"resource": "iamStack", "name": "rayito-m0-iam", "action": "create",
"source": null, "status": null, "imageVersion": null,
"release": null, "previousBucket": null,
"stackSdkVersion": null},
{"resource": "baseImage", "name": "rayito-base", "action": "publish",
"source": "release", "status": null, "imageVersion": null,
"release": "rayd-v0.17.0", "previousBucket": null,
"stackSdkVersion": null},
{"resource": "capsImage", "name": "rayito-base-caps", "action": "skip",
"source": null, "status": null, "imageVersion": null,
"release": null, "previousBucket": null,
"stackSdkVersion": null}
],
"cost": [
"pila de IAM: gratis",
"imagen: ≈ $0,04 por semana por versión publicada (mínimo una semana)",
"zip de la imagen en el bucket: céntimos"
],
"result": null,
"doctor": null,
"error": null,
"exitCode": 0
}
Cost and activation
- Turns on: running
rayito setupand confirming.--dry-runonly reads the account; with an already prepared account it writes nothing either. - AWS resources and calls: with no reusable bucket, the
rayito-m0-artifactsstack (CreateStackwithout capabilities: a bucket and its policy); therayito-m0-iamstack (CreateStack/UpdateStackwithCAPABILITY_NAMED_IAM); therayito-baseandrayito-base-capsimages (one shared object in the bucket, andCreateMicrovmImageorUpdateMicrovmImageper image; the second, only with--caps-image, withadditionalOsCapabilities=["ALL"]); reads ofGetCallerIdentity,DescribeStacks,HeadBucket,GetMicrovmImageandListMicrovmImageVersions; the HTTPS download ofrayito-image.zipandSHA256SUMS. The SDK does not callCreateBucket: CloudFormation creates the bucket with your credentials. - Approximate cost: IAM stack, free; the bucket costs nothing to exist
and its zips expire after 7 days; each published version of each image
≈ $0.04 per week ($0.08 per GB-month, minimum one week; with
--caps-image, one image more); the zip in the bucket, cents. See Pricing. - IAM: administrator or bootstrap credentials, once, like
cdk bootstrap: CloudFormation, IAM (roles and policies), publishing the image and, if it creates the bucket, S3 (s3:CreateBucket,s3:PutEncryptionConfiguration,s3:PutBucketPublicAccessBlock,s3:PutBucketOwnershipControls,s3:PutLifecycleConfiguration,s3:PutBucketTagging,s3:GetBucketPolicy,s3:PutBucketPolicy). To use the SDK afterwards, the minimal policy of Set up AWS. - How to turn it off: do not run it; without
--caps-image(the default) it does not publishrayito-base-caps; to undo it, delete the stacks (rayito-m0-iamand, if it exists,rayito-m0-artifacts) and the image versions. The created bucket is kept: empty and delete it by hand. - Example:
rayito setup --dry-run.
The hash does not prove authenticity
The check against SHA256SUMS catches a truncated, corrupted or wrong zip,
but not that it is authentic (SHA256SUMS comes from the same release).
For the cosign signature, verify the zip and pass it with --artifact:
Verify a release.
rayito doctor¶
rayito [--json] doctor [--template rayito-base] [--template-version V] [--bucket B] [--launch]
[--efs-vpc-id V --efs-subnet-ids S1,S2]
Ten checks, in order, each with OK, WARN, FAIL or SKIP. An exception
inside a check is its FAIL (or SKIP when an AccessDeniedException only
prevents a diagnosis) naming the operation AWS rejected
(details.operation) next to the IAM permission the check needs
(details.action), and the others keep running. It exits with 1 only if any
is a FAIL.
| # | Check | What it looks at | WARN |
FAIL |
SKIP |
What to do |
|---|---|---|---|---|---|---|
| 1 | credentials |
sts:GetCallerIdentity and the session's region |
region outside the ten with Lambda MicroVMs | no credentials, expired token, no region | — | aws login / export AWS_PROFILE and AWS_REGION |
| 2 | managed-images |
list-managed-microvm-images and the newest al2023-1 version |
the call responds but al2023-1 is not there |
AccessDenied, unknown endpoint (old botocore), region without the service |
— | update boto3; change region |
| 3 | quotas |
Service Quotas of lambda with microvm in the name against the published defaults (L-CD1C0CC4 memory, L-535CA9B6 RunMicrovm...) |
some adjustable quota below the default | — | servicequotas:ListServiceQuotas denied |
request a quota increase in the console |
| 4 | iam-simulation |
iam:SimulatePrincipalPolicy over the actions the SDK and the CLI use (image, lists, PassNetworkConnector, the bucket's S3, logs, quotas), one call per resource |
some implicitDeny |
explicitDeny or an SCP denial |
root, non-simulable principal, iam:GetRole/SimulatePrincipalPolicy denied |
indicative: checks 2, 5, 6 and 8 are the ones that count; iam:PassRole is not simulated. Measured 2026-09-16: the simulator returns implicitDeny for lambda:PassNetworkConnector even with AdministratorAccess, while run-microvm works: that WARN blocks nothing |
| 5 | bucket |
a head-bucket of the artifacts bucket (s3:ListBucket, the same permission publish needs) and the region from its x-amz-bucket-region header |
bucket in another region (S3_CROSS_REGION_ACCESS_DENIED when building); no region header |
403/404 (the summary names the rejected operation and publish's S3 permissions) |
no --bucket or RAYITO_BUCKET |
grant s3:ListBucket on the bucket; use a bucket in the same region |
| 6 | image-gate |
get-microvm-image + the version (--template-version or the latest active) through the three-state gate and its snapshotBuild |
launchable but with a failed build listed | the image does not exist, is not CREATED|UPDATED or the version is not SUCCESSFUL/ACTIVE |
— | rayito image publish …; rayito image prune for the failed build |
| 7 | sandboxes |
non-terminated MicroVMs of the image (list-microvms) |
1–10 RUNNING (they bill) |
more than 10 RUNNING |
— | rayito sandbox list, rayito sandbox kill --all |
| 8 | token |
create-microvm-auth-token (port 8080) for the --launch sandbox or the newest RUNNING one |
— | AccessDenied, ValidationException |
no RUNNING sandbox (use --launch) |
check lambda:CreateMicrovmAuthToken |
| 9 | agent |
a rayd Health: agent_version, kernel_ready, imds_blocked, hook_anomalies |
kernel_ready=false, hook_anomalies>0, imds_blocked=false on a -caps image |
Health fails (UNAVAILABLE, UNAUTHENTICATED, proxy 403) |
no token | wait for the kernel; check who holds an allPorts token; republish the image |
| 10 | compatibility |
the SDK ↔ rayd table in Limits; the image version (build counter per image and account) is only reported |
rayd newer than the SDK in MAJOR.MINOR |
rayd below the SDK's minimum |
no agent_version |
update the SDK or publish an image from the minimum rayd tag |
With --efs-vpc-id and --efs-subnet-ids (EFS volumes in a VPC that already
exists) the efs-network check is added after check 7: the same as
EfsVolumes.check(), read-only (ec2:DescribeVpcs, DescribeVpcAttribute,
DescribeSubnets, DescribeRouteTables). FAIL if the VPC or a subnet does
not exist, a subnet belongs to another VPC, two share an AZ or one has fewer
than 2 free IPs left; WARN with a single AZ or without DNS in the VPC. The
summary says what rayito stack deploy efs-volumes would create and its idle
cost; it creates nothing. See
EFS volumes in your VPC.
Without --launch the doctor never creates a MicroVM: checks 8–10 use the
newest RUNNING sandbox of the image or end up SKIP. With --launch it
creates a 300 s one (idle=None, logging="disabled",
metadata={"rayito": "doctor"}), uses it for 8–10 and kills it in a finally
no matter what (also on Ctrl-C); it costs the snapshot read plus a few seconds
of compute (Pricing) and its id appears
as launched_sandbox_id.
Human output: one line per check (OK credentials cuenta …, "cuenta" being
Spanish for "account"), the details indented under WARN/FAIL, the
compatibility table and rayito doctor: N OK, N WARN, N FAIL, N SKIP. With
--json:
{
"rayito": "0.11.0",
"region": "us-east-1",
"account": "123456789012",
"principal_kind": "assumed-role",
"checks": [{"name": "credentials", "status": "OK", "summary": "…", "details": {}}],
"compatibility": [
{"sdk_series": "0.1", "min_agent_version": "0.1.0", "note": "…"},
{"sdk_series": "0.2", "min_agent_version": "0.2.0", "note": "…"},
{"sdk_series": "0.3", "min_agent_version": "0.3.0", "note": "…"},
{"sdk_series": "0.4", "min_agent_version": "0.4.0", "note": "…"},
{"sdk_series": "0.5", "min_agent_version": "0.5.0", "note": "…"},
{"sdk_series": "0.6", "min_agent_version": "0.6.0", "note": "…"},
{"sdk_series": "0.7", "min_agent_version": "0.7.0", "note": "…"},
{"sdk_series": "0.8", "min_agent_version": "0.8.0", "note": "…"},
{"sdk_series": "0.9", "min_agent_version": "0.9.0", "note": "…"},
{"sdk_series": "0.10", "min_agent_version": "0.10.0", "note": "…"},
{"sdk_series": "0.11", "min_agent_version": "0.11.0", "note": "…"}
],
"launched_sandbox_id": null,
"exit_code": 0
}
Nothing the CLI prints is a secret: neither the proxy JWE, nor the access
token, nor the runHookPayload appear in any output (the tests check it with
canaries).
Equivalents with make¶
The four scripts in scripts/ still exist with the same arguments and are
shims over the CLI, so the Makefile targets do not change:
make |
Script | Equivalent |
|---|---|---|
make image-zip |
python scripts/copy_sidecar.py kernel-sidecar image/kernel-sidecar, make image-licenses and python scripts/image_zip.py image image/rayito-image.zip |
rayito image zip image image/rayito-image.zip --sidecar kernel-sidecar |
make image-zip-efs |
python scripts/image_zip.py image image/rayito-image-efs.zip --with-efs |
rayito image zip image image/rayito-image-efs.zip --sidecar kernel-sidecar --with-efs |
make image-publish-caps-efs |
… publish_image.py --artifact image/rayito-image-efs.zip --with-efs --os-capabilities ALL … |
rayito image publish --artifact image/rayito-image-efs.zip --with-efs --os-capabilities ALL … |
make image-publish (-slim, -poly, -caps) |
uv run --project clients/python python scripts/publish_image.py --artifact … --bucket $(BUCKET) --base-image-version 1 |
rayito image publish --artifact … --bucket … --base-image-version 1 |
make image-publish-caps MOUNT_BUCKETS=b1,b2 (also -caps-efs) |
… publish_image.py … --env RAYITO_ALLOWED_MOUNT_BUCKETS=b1,b2 |
rayito image publish … --env RAYITO_ALLOWED_MOUNT_BUCKETS=b1,b2 |
make image-prune PRUNE_ARGS="--keep 5 --dry-run" |
uv run --project clients/python python scripts/image_prune.py --image-name rayito-base --keep 5 --dry-run |
rayito image prune --keep 5 --dry-run |
image_zip.py and copy_sidecar.py only use the standard library (they load
rayito/cli/_artifact.py by file path) because CI and the release run them
with a bare python3 without installing the SDK. publish_image.py and
image_prune.py need the client environment (typer and the SDK) and without
it they print the uv run --project clients/python … command and exit with 2.
What the CLI does not do¶
rayito.tomlor any configuration file of its own.- Building the image beyond the zip: AWS builds the Dockerfile.
sandbox logs --follow: that is what the SDKs and the MCP server are for.auth,snapshotsandforkfrom E2B's CLI: they have no primitive or are out bySPEC.md§4 (E2B compatibility).- Wrapping the development tools (
bench_cold_start.py,hooks-sim.py,gen_limits.py,check_*.py). - Shell completion.