Sandbox¶
Sandbox (síncrono) y AsyncSandbox (asyncio). Guías:
Ciclo de vida, Comandos,
Ejecutar código y Async.
Sandbox(*, info: SandboxInfo, access_token: str, control_plane: ControlPlane, transport: TransportSettings, refresher: TokenRefresher, request_timeout: float, ready_timeout: float, reconnect_timeout: float = DEFAULT_RECONNECT_TIMEOUT_SECONDS, logger: logging.Logger | None = None)
¶
Un MicroVM con rayd dentro. Se crea con create() o connect().
access_token: str
property
¶
Guárdalo junto al sandbox_id para poder hacer connect() después.
info: SandboxInfo
property
¶
Última SandboxInfo conocida sin llamar a AWS; get_info() la refresca.
launch_info: SandboxInfo
property
¶
La SandboxInfo con la que se abrió el handle (la respuesta de
run-microvm en create(), el get-microvm de connect()), nunca
refrescada y sin llamar a AWS.
resume_generation: int
property
¶
Última generación de resume vista en Health (cambia con cada /resume).
metadata: dict[str, str]
property
¶
Metadatos de create(metadata=) tal como los devolvió el último
Health; inmutables durante la vida del sandbox, así que son
definitivos desde el primer agent_ready (vacíos sobre una imagen
anterior a M6).
persist: S3Prefix | None
property
¶
El S3Prefix (con name) enlazado por create(persist=) o
connect(persist=); None si el sandbox no persiste.
transfer: S3Staging | None
property
¶
El S3Staging de create(transfer=)/connect(transfer=) o de
RAYITO_TRANSFER_BUCKET; None sin bucket de transferencias.
last_restore: RestoreResult | None
property
¶
El resultado del restore automático de create(persist=); None si
no hubo (primera vida de ese name) o si el sandbox no persiste.
gateways: GatewayHandle
property
¶
{nombre: GatewayStatus} de create(gateways=): vacío (y su
refresh() no hace nada) sin esa opción. Tras connect() desde otro
proceso se reconstruye con ConfigureStatus (nombres y puertos;
su refresh() sólo relee el estado, no rota secretos). GatewayStatus.url es
"http://127.0.0.1:<puerto>", el host al que apuntar
ANTHROPIC_BASE_URL y similares dentro del sandbox.
mounts: dict[str, MountStatus]
property
¶
Estado en vivo de cada mounts= (m15-s3-mounts): una
ConfigureStatus por lectura, nunca cacheada — un montaje puede
pasar de "pending" a "mounted"/"failed" entre dos lecturas de
esta propiedad. Vacío si create()/take() no recibió mounts=.
volumes: dict[str, VolumeStatus]
property
¶
Estado en vivo de cada volumes= (m15-efs-volumes): una
ConfigureStatus por lectura, nunca cacheada — tras un resume()
un volumen puede pasar por "remounting"/"degraded". Vacío si
create() no recibió volumes=.
commands: Commands
property
¶
ProcessService: run, list, kill, connect, send_stdin, close_stdin.
files: Filesystem
property
¶
FilesystemService: read, write, write_files, list, exists,
get_info, remove, rename, make_dir, watch_dir.
pty: Pty
property
¶
PtyService: create, connect, send_input, resize, kill.
agent: Agent
property
¶
El agente de IA de este sandbox (ai-agent-core): run,
stream, prepare. Tocar esta propiedad no manda ningún RPC.
Se construye en el primer uso, así que import rayito no carga
rayito._agent.
git: Git
property
¶
El módulo git de E2B 2.x (clone, status, commit, push...)
sobre commands.run; se construye en el primer uso.
create(template: str | None = None, *, template_version: str | None = None, timeout: int = DEFAULT_TIMEOUT_SECONDS, max_lifetime: int | None = None, on_timeout: TimeoutActionName | None = None, idle: IdlePolicy | None = DEFAULT_IDLE_POLICY, envs: Mapping[str, str] | None = None, metadata: Mapping[str, str] | None = None, cpu_time_limit: int | None = None, execution_role_arn: str | None = None, allowed_ports: Sequence[PortLike] | None = None, ingress: Sequence[str] | None = None, egress: Sequence[str] | None = None, network: NetworkPolicy | NetworkOptions | None = None, allow_internet_access: bool = True, logging: LoggingOption = 'disabled', region: str | None = None, session: boto3.session.Session | None = None, access_token: str | None = None, ready_timeout: float = DEFAULT_READY_TIMEOUT_SECONDS, request_timeout: float = DEFAULT_REQUEST_TIMEOUT_SECONDS, reconnect_timeout: float = DEFAULT_RECONNECT_TIMEOUT_SECONDS, keep_on_failure: bool = False, control_plane: ControlPlane | None = None, transport: TransportSettings | None = None, persist: S3Prefix | None = None, persist_timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS, pool: SandboxPool | None = None, transfer: S3Staging | None = None, logger: logging.Logger | None = None, secrets: Mapping[str, str | SecretRef] | None = None, secret_cache: SecretCache | None = None, index: DynamoDbIndex | None = None, tracer_provider: TracerProviderLike | None = None, mounts: Mapping[str, Any] | None = None, volumes: Mapping[str, Any] | None = None, size: str | SizeRequest | None = None, events: Any | None = None, telemetry: Any | None = None, gateways: Mapping[str, Any] | None = None, domain: Any | None = None) -> Self
classmethod
¶
run-microvm → token del proxy → sondeo de Health hasta
agent_ready y kernel_ready (el kernel por defecto ya rotado).
Sin max_lifetime ni on_timeout, timeout es la vida máxima
(running + suspended, tope 8 h) y no se puede cambiar después.
Con cualquiera de los dos (exige una imagen 0.3.0 o posterior),
timeout es el plazo lógico que impone rayd aunque el cliente
muera, movible con set_timeout() y connect(timeout=), y
max_lifetime (120..=28800, por defecto timeout + 60) es
maximumDurationInSeconds: el plazo nunca pasa de max_lifetime -
60 s desde el arranque. Al vencer, on_timeout='kill' (por defecto)
termina el sandbox y on_timeout='pause' lo suspende (necesita
idle; idle.auto_resume decide si una petición posterior lo
reanuda con un plazo nuevo de max(timeout, 300 s)). Una imagen
anterior a 0.3.0 falla con LifecycleUnsupportedException y el VM se
termina (salvo keep_on_failure). idle=None desactiva la
auto-suspensión. Sin idle, la de 300 s por defecto se desactiva si
no cabe antes del timeout (o de max_lifetime), y en modo pause
baja a 60 s; un idle explícito que no cabe es
InvalidArgumentException. Sin execution_role_arn no hay logs de
runtime.
reconnect_timeout acota cuánto espera el SDK a que el agente vuelva
tras un corte (pausa, auto-resume, 502 del proxy) antes de fallar.
metadata son etiquetas no secretas (viajan en el runHookPayload
junto a envs, dentro de sus 4096 caracteres) que el agente devuelve
en Health: inmutables durante la vida del sandbox, legibles con
sbx.metadata, get_info() y Sandbox.list(metadata=...).
cpu_time_limit son segundos de CPU, no de pared (1..=28800): cada
proceso y PTY del sandbox recibe RLIMIT_CPU con ese tope (SIGXCPU
al alcanzarlo, SIGKILL 5 s después); un proceso dormido no lo
consume y el kernel de run_code nunca lo recibe. Para un tope de
pared usa timeout en cada comando.
pool= es azúcar de pool.take(): el sandbox sale de una plaza
suspendida del SandboxPool (ya arrancado) con la configuración de
lanzamiento de su PoolConfig; cualquier otro kwarg de lanzamiento o
de plano distinto de su valor por defecto es InvalidArgumentException.
Pasan los tres timeouts del handle (ready_timeout, request_timeout,
reconnect_timeout), secrets/secret_cache, transfer, logger
y tracer_provider; gateways= no: llama a pool.take(gateways=...).
persist=S3Prefix(...) (requiere execution_role_arn) enlaza el
HOME del sandbox a s3://bucket/prefix/name/: con name dado, tras
Health el SDK restaura el checkpoint que haya bajo el prefijo
(sbx.last_restore; None si no había ninguno) y sin name lo fija al
sandbox_id. persist_timeout es el deadline del restore automático
y de reincarnate(). Un restore que falla (salvo "no hay checkpoint")
cierra y termina el sandbox como un fallo de readiness.
allow_internet_access=False y network={"allow_out", "deny_out",
"egress_proxy"} (semántica de E2B: sin deny_out todo está
permitido y allow_out gana a deny_out; ALL_TRAFFIC es todo) se
aplican en el guest y exigen una imagen 0.3.0 o posterior de rayito-base-caps:
rayd instala deny-all antes de /run y create() manda la política
real con UpdateNetwork antes de devolver. Sobre una imagen que no la
aplica (Health.egress_enforcement NONE), el SDK termina el VM
aunque haya keep_on_failure y lanza UnimplementedError. Una
entrada de nombre de host ("api.example.com", "*.example.com") o
egress_proxy activan el proxy local de rayd, que sólo alcanzan los
clientes que respetan HTTPS_PROXY/ALL_PROXY; el resto falla cerrado.
transfer=S3Staging(...)(oRAYITO_TRANSFER_BUCKETconNone) es el- bucket de
files.upload_url/download_urly de los ficheros grandes - configuración del cliente, nada viaja al VM, también con
pool=. Conpersisten el mismo bucket, los prefijos deben ser disjuntos o esInvalidArgumentExceptionantes de llamar a AWS.
secrets={"ENV": "nombre" | SecretRef} guarda en el handle
sólo las referencias y entrega los valores como variables de entorno
de cada commands.run, pty.create, run_code (contextos Python) y
create_code_context, nunca en el runHookPayload, metadata ni
el entorno de la imagen. Se resuelven (y quedan en SecretCache)
antes de run-microvm: un secreto que falta falla sin lanzar un VM.
Se admite con pool= (lo enlaza take()).
Coste y activación
Activa: secrets= inyecta secretos de Secrets Manager como variables
de entorno; secret_cache=SecretCache(ttl_seconds=300) fija la
caché (si no, una compartida por región y sesión, TTL 300 s).
Recursos y llamadas AWS: secretsmanager:GetSecretValue una vez por
secreto y TTL (un acierto de caché no llama a AWS); ningún recurso
nuevo. Sin secrets= no se crea ningún cliente secretsmanager.
Coste aproximado: $0,05 por 10 000 llamadas + $0,40 por secreto y mes
(Secrets Manager, us-east-1, 2026-09-30); ≈ $0,04/mes por secreto
y proceso con el TTL por defecto.
IAM: secretsmanager:GetSecretValue sobre ...:secret:rayito/* en las
credenciales del llamante (no el execution role).
Cómo apagarla: secrets=None y secret_cache=None (por defecto).
Ejemplo:
SecretStore().create("openai", key)
sbx = Sandbox.create(secrets={"OPENAI_API_KEY": "openai"})
sbx.commands.run("python agent.py")
index=DynamoDbIndex("tabla") escribe, tras run-microvm y
antes de la sonda de readiness, una fila inmutable con metadata, la
imagen y startedAt en la tabla opcional del índice, para que
Sandbox.list(metadata=..., index=...) encuentre el sandbox también
suspendido y sin sondearlo. Si PutItem falla, con
on_write_failure='terminate' (por defecto) el VM se termina (salvo
keep_on_failure=True) y se lanza IndexWriteException; con
'warn' sólo se avisa. Con pool= es InvalidArgumentException:
se configura en PoolConfig(index=...). kill() no toca el índice.
Coste y activación
Activa: index=DynamoDbIndex(...) escribe la fila del índice de
metadatos de este sandbox.
Recursos y llamadas AWS: dynamodb:PutItem una vez (condicional
attribute_not_exists(pk)); ningún recurso nuevo (la tabla la
despliegas tú con infra/metadata-index.yaml). Sin index=
ningún cliente dynamodb.
Coste aproximado: ~1 WRU ≈ $0,000000625 por sandbox + $0,25/GB-mes
(DynamoDB on-demand, us-east-1, consultado 2026-09-30).
IAM: dynamodb:PutItem sobre la tabla (RayitoIndexWriter) en las
credenciales del llamante.
Cómo apagarla: index=None (por defecto).
Ejemplo:
idx = DynamoDbIndex("rayito-sandboxes")
sbx = Sandbox.create(metadata={"user": "42"}, index=idx)
sbx.pause()
items = list(Sandbox.list(metadata={"user": "42"}, states=["SUSPENDED"], index=idx))
tracer_provider= guarda en el handle una Instrumentation
que instrumenta sus operaciones (commands.run, run_code,
files.*, kill/pause/resume de instancia); create() en sí es
un único span rayito.sandbox.create que envuelve run-microvm, la
espera de Health, la escritura del índice y la política de red.
Con pool= se enlaza al handle que entrega take(), sin span propio
(no hay lanzamiento que medir). None (por defecto) es NOOP: cero
import de opentelemetry y cero coste por llamada.
Coste y activación
Activa: tracer_provider= (un TracerProvider de
opentelemetry.trace, o cualquier objeto con
get_tracer(name, version)).
Recursos y llamadas AWS: ninguno; rayito sólo crea spans en el
proveedor del llamante.
Coste aproximado: $0 de AWS; el coste (si lo hay) es el del backend
de exportación que configure el llamante.
IAM: ninguno adicional.
Cómo apagarla: no pases tracer_provider= (por defecto None).
Ejemplo:
from opentelemetry import trace
sbx = Sandbox.create(tracer_provider=trace.get_tracer_provider())
sbx.commands.run("echo hola") # span "rayito.commands.run"
sbx.kill()
De las siete opciones 0.6 (M15), sólo domain= sigue sin cablear
(para un dominio propio usa CustomDomain, experimental): ponerla
a algo distinto de None lanza UnimplementedError nombrando
m15-custom-domain, antes de run-microvm (_feature_options.plan_features) y sin
ninguna llamada a AWS. mounts=, volumes=, size=, events=,
telemetry= y gateways= ya son reales: cada una lleva su bloque "Coste y
activación" aquí debajo o en su clase (SecretGateway). Con todas
en None (su valor por defecto) el comportamiento es exactamente
el de 0.5.x.
mounts= (m15-s3-mounts) monta cada S3Mount en su ruta (bajo
/mnt/ o /home/user/, como mucho 4) con mount-s3, en el mismo
ConfigureSandbox que el resto de secciones; sólo en
rayito-base-caps (o una variante por tamaño) y sólo los buckets
del allowlist de la imagen. Si un montaje falla, termina el sandbox
(salvo keep_on_failure) y relanza el error; sbx.mounts da el
estado en vivo.
Coste y activación
Activa: mounts={"/mnt/data": S3Mount(bucket="...")} en create(),
con execution_role_arn= y una imagen rayito-base-caps cuyo
RAYITO_ALLOWED_MOUNT_BUCKETS incluya el bucket.
Recursos y llamadas AWS: ningún recurso nuevo; mount-s3 hace las
peticiones S3 normales (GetObject/ListObjectsV2, y
PutObject/DeleteObject con read_only=False) con el
execution role. La política sale de la pila s3-mounts
(rayito stack deploy s3-mounts, sólo IAM).
Coste aproximado: $0 propio de Rayito; pagas las peticiones y el
almacenamiento normales de S3 del bucket montado (us-east-1,
consultado 2026-10-01); la pila s3-mounts es $0 (sólo IAM).
IAM: RayitoS3MountAccess (infra/s3-mounts.yaml) en el execution
role, acotada a un bucket y a sus prefijos.
Cómo apagarla: no pases mounts= (por defecto None); rayito
stack destroy s3-mounts quita la política (no borra objetos).
Ejemplo:
from rayito import S3Mount
sbx = Sandbox.create("rayito-base-caps", execution_role_arn=role_arn,
mounts={"/mnt/data": S3Mount(bucket="mi-bucket")})
sbx.commands.run("ls /mnt/data")
volumes= (m15-efs-volumes, experimental) monta cada EfsVolume
en su ruta (bajo /mnt/ o /home/user/, como mucho 4) con
amazon-efs-utils (TLS + IAM), en el mismo ConfigureSandbox que
el resto de secciones y antes de que create() vuelva. Exige
execution_role_arn=, exactamente un conector propio en egress=
(un MicroVM sólo admite uno, así que el sandbox no tiene
INTERNET_EGRESS) y una imagen con amazon-efs-utils
(rayito-base-caps-efs); si un volumen no monta, termina el
sandbox (salvo keep_on_failure) y lanza VolumeMountException, y
sobre otra imagen UnimplementedError. sbx.volumes da el estado
en vivo y reincarnate() los vuelve a montar en el sucesor.
Coste y activación
Activa: volumes={"/mnt/datos": vol} en create(), con
execution_role_arn=, egress=[<ConnectorArn>] y la imagen
opcional rayito-base-caps-efs (rayito image publish
--with-efs --os-capabilities ALL).
Recursos y llamadas AWS: ningún recurso nuevo por create(); si un
EfsVolume no trae mount_target_ip, una DescribeMountTargets
por sistema de ficheros y create(), con las credenciales del
llamante. El sistema de ficheros, sus mount targets y el
conector los crea la pila efs-volumes (EfsVolumes.deploy()),
aparte; el tráfico NFS va con el execution role.
Coste aproximado: $0 propio de Rayito; pagas el almacenamiento y el
rendimiento normales de EFS (Elastic) de lo que leas y escribas,
y la imagen con amazon-efs-utils ocupa ≈ 198 MB más de código
instalado (us-east-1, consultado 2026-10-04,
https://aws.amazon.com/efs/pricing/).
IAM: el llamante, elasticfilesystem:DescribeMountTargets (sólo sin
mount_target_ip); el execution role, la política
CallerPolicyArn de la pila efs-volumes (ClientMount, y
ClientWrite salvo sólo lectura).
Cómo apagarla: no pases volumes= (por defecto None);
EfsVolumes.destroy() quita la pila.
Ejemplo:
vol = VolumeStore(file_system_id=fs_id).create("datos-agente-7")
sbx = Sandbox.create("rayito-base-caps-efs", execution_role_arn=role_arn,
egress=[connector_arn], volumes={"/mnt/datos": vol})
sbx.commands.run("ls /mnt/datos")
size= (m15-sizes-catalog) elige, en el cliente y sin ninguna
llamada a AWS, la imagen de ese tamaño del catálogo cerrado
(512mb/1gb/2gb/4gb/8gb; SizeRequest(memory_mib=...) redondea
hacia arriba): rayito-base con size="4gb" lanza
rayito-base-4gb, que tiene que estar publicada. No cambia la
memoria de ninguna imagen ni de un sandbox en marcha; ver
rayito._sizing.
Coste y activación
Activa: size="4gb" (o size=SizeRequest(memory_mib=...)) en
create(), tras rayito image publish --sizes 4gb.
Recursos y llamadas AWS: ninguno nuevo al lanzar (el tamaño va en
el nombre de la imagen); get_info() hace como mucho una
GetMicrovmImageVersion gratuita por versión de imagen y
proceso. Cada tamaño publicado es una imagen más en tu cuenta.
Coste aproximado: un MicroVM más grande cuesta más por hora, de
$0,0315/h (512 MiB) a $0,5044/h (8192 MiB) en baseline
(limits.md, us-east-1, consultado 2026-09-30); cada tamaño
publicado añade storage de snapshot, ≈ $0,04/semana por versión.
IAM: ninguno adicional; la pila opcional sizes-guard niega
RunMicrovm fuera de las imágenes que listes.
Cómo apagarla: no pases size= (por defecto None); las versiones
de cada imagen de tamaño se borran con rayito image prune
--image-name rayito-base-4gb.
Ejemplo:
sbx = Sandbox.create(size="4gb")
sbx.get_info() # size="4gb", baseline_memory_mib=4096
events= (m15-events-webhooks, ADR-020) ya es real: un
LifecycleEvents/AsyncLifecycleEvents (con su pila
events-webhooks ya desplegada) hace que el SDK derive la clave
de este sandbox (k_sbx, de la clave del stack y el sandbox_id)
y la mande a rayd en el mismo ConfigureSandbox que el resto de
secciones, justo después de que el agente esté listo; desde ahí
rayd emite created/paused/resumed/killed firmados. Exige
un logging= que llegue a CloudWatch (InvalidArgumentException
antes de lanzar si no). Si la pila no está desplegada, la clave no
se puede leer o la imagen es anterior a 0.6.0, termina el sandbox
(salvo keep_on_failure) y relanza el error.
Coste y activación
Activa: events=LifecycleEvents(...) en create(), tras
LifecycleEvents().deploy(...) (o rayito events deploy).
Recursos y llamadas AWS: un secretsmanager:GetSecretValue de la
clave del stack por instancia de LifecycleEvents (más un
cloudformation:DescribeStacks si no se desplegó con esa
misma instancia); la pila hace el resto (forwarder,
deliverer, reconciliador).
Coste aproximado: el de la pila (~$0,40/mes el secreto, el resto
por uso; ver LifecycleEvents.deploy); la opción en sí, una
lectura de Secrets Manager ($0,05 por 10 000).
IAM: EventsLauncherPolicy (salida de la pila) en las
credenciales del llamante; el execution role necesita escribir
en el log group de la imagen (logging="cloudwatch").
Cómo apagarla: no pases events= (por defecto None);
LifecycleEvents().destroy() borra la pila.
Ejemplo:
from rayito import LifecycleEvents
events = LifecycleEvents()
sbx = Sandbox.create(execution_role_arn=role_arn,
logging="cloudwatch", events=events)
events.get_events(sandbox_id=sbx.sandbox_id) # created, ...
telemetry= (m15-rayd-otlp, ADR-021) es la séptima y ya es real:
un TelemetryExport hace que rayd exporte 7 gauges de CPU,
memoria y disco a CloudWatch cada interval_s (15-300 s, 60 por
defecto), firmados con OtlpAuth.execution_role() (SigV4 sobre el
execution role, exige rayito-base-caps) o con
OtlpAuth.bearer(secret_name=...) (experimental: una API key de
CloudWatch Metrics, funciona en rayito-base). Se envía como una
sección de ConfigureSandbox justo después de que el agente esté
listo; una imagen anterior a 0.6.0, o una 0.6.0 sin el exportador
todavía implementado, termina el sandbox (salvo keep_on_failure)
y lanza UnimplementedError.
Coste y activación
Activa: telemetry=TelemetryExport(...) en create().
Recursos y llamadas AWS: ninguno propio más allá de lo que tú
adjuntes: con OtlpAuth.execution_role() necesitas la política
RayitoOtlpExport (infra/otlp-export.yaml,
rayito stack deploy otlp-export) en el execution role;
con OtlpAuth.bearer(...) no hace falta ninguna política nueva
en el execution role, pero sí el permiso para leer el secreto.
rayd hace un PutMetricData por lote exportado (uno por
interval_s, agrupando las 7 gauges).
Coste aproximado: $0 por la opción en sí; CloudWatch factura la
ingesta OTLP a $0,50/GB: ≈ $0,00002 por sandbox-hora con
interval_s=60 (639 bytes por lote, AWS_API_NOTES.md Q120).
IAM: cloudwatch:PutMetricData sobre el dataset OTLP por defecto
de la cuenta (no se puede acotar por namespace, research OT9);
con OtlpAuth.bearer(...), en su lugar el permiso de lectura
del secreto que guarda el token.
Cómo apagarla: no pases telemetry= (por defecto None); borra la
pila otlp-export si ya no la usa ningún sandbox.
Ejemplo:
from rayito import OtlpAuth, TelemetryExport
sbx = Sandbox.create(
"rayito-base-caps",
execution_role_arn=role_arn,
telemetry=TelemetryExport(interval_s=60, service_name="agente",
auth=OtlpAuth.execution_role()),
)
sbx.get_telemetry_status() # TelemetryHealth(exported, dropped, last_error_class)
connect(*, timeout: int | None = None, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None, secret_cache: SecretCache | None = None, tracer_provider: TracerProviderLike | None = None) -> Sandbox
¶
Reabre este handle: get-microvm, resume-microvm si está
SUSPENDED sin auto-resume, el sondeo de Health y la extensión del
plazo de Sandbox.connect(sandbox_id, timeout=). Devuelve self.
secrets=/secret_cache= sustituyen los del handle; None los
conserva y secrets={} los borra todos. tracer_provider=
sustituye la Instrumentation del handle; None conserva la que ya
tenía ($0 de AWS: ver el bloque de create()).
Coste y activación¶
Activa: secrets= (y secret_cache=) inyectan secretos de Secrets
Manager en cada comando, PTY, celda Python y contexto de este
handle; sin ellos, connect() no construye ningún cliente
secretsmanager (el camino de 0.4.0).
Recursos y llamadas AWS: GetSecretValue una vez por secreto y TTL de
SecretCache (300 s por defecto), resuelto aquí antes de
get-microvm; ningún recurso nuevo.
Coste aproximado: $0,05 por 10 000 llamadas (≈ $0,04/mes por secreto
y proceso con TTL 300) + $0,40 por secreto y mes (us-east-1,
2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante
(RayitoSecretsReader de infra/secrets-access.yaml); kms:Decrypt
con una CMK.
Cómo apagarla: no pases secrets= ni secret_cache=; secrets={}
quita los que el handle ya tenía.
Ejemplo:
sbx.connect(secrets={"OPENAI_API_KEY": "openai"})
sbx.commands.run("python agent.py") # 0 llamadas: ya en caché
list(*, template: str | None = None, template_version: str | None = None, states: Iterable[str] | None = None, metadata: Mapping[str, str] | None = None, started_after: datetime | None = None, order: ListOrder | None = None, region: str | None = None, session: boto3.session.Session | None = None, control_plane: ControlPlane | None = None, transport: TransportSettings | None = None, request_timeout: float = METADATA_PROBE_TIMEOUT_SECONDS, index: DynamoDbIndex | None = None) -> Iterator[SandboxListItem]
classmethod
¶
Pagina list-microvms (páginas de 50) de forma perezosa. Sin
states omite TERMINATING|TERMINATED, que AWS sigue listando ~20 min
después de morir. template viaja como filtro de servidor; states y
started_after ("en o después") se filtran en cliente.
Con metadata filtra en cliente y es O(n): list-microvms no
conoce los metadatos, así que por cada sandbox RUNNING hace, en
orden y uno a uno, get-microvm + create-microvm-auth-token + un
Health (5 s de plazo, canal dedicado) ≈ 0,5-1 s por sandbox, y cada
sonda cuenta como tráfico para la política de idle de ese sandbox
(pospone su auto-suspensión una ventana). Devuelve sólo los items
cuyo agente respondió agent_ready y cuyos metadatos contienen cada
par pedido (subconjunto exacto), con metadata relleno; un sandbox
que dejó de estar RUNNING o que aún arranca se omite; un Health
que falla es SandboxException con su id (nunca una lista incompleta
en silencio). states sólo admite RUNNING: sondear un sandbox
suspendido lo despertaría. Filtra por template antes si hay muchos.
order ("asc"/"desc" por startedAt) se calcula en cliente: AWS
no ordena, así que recorre todas las páginas antes del primer item.
Para reanudar un listado usa paginate().
Con metadata e index=DynamoDbIndex(...) no hay sondas: por
cada página de list-microvms, un BatchGetItem de los candidatos y
la unión con sus filas; ningún get-microvm, token ni Health, así
que nada se despierta. states admite cualquier estado no terminal
(por defecto todos). El estado es siempre el de list-microvms; sólo
aparecen los sandboxes creados con ese índice (un sandbox sin fila se
omite). index sin metadata no cambia nada.
Coste y activación¶
Activa: index=DynamoDbIndex(...) junto a metadata=.
Recursos y llamadas AWS: dynamodb:BatchGetItem una vez por página
de list-microvms (≤ 50 claves, eventualmente consistente).
Coste aproximado: 0,5 RRU por candidato ($0,125 por millón de RRU,
DynamoDB on-demand, us-east-1, consultado 2026-09-30).
IAM: dynamodb:BatchGetItem sobre la tabla (RayitoIndexReader).
Cómo apagarla: index=None (por defecto): la sonda O(n) de siempre.
Ejemplo:
idx = DynamoDbIndex("rayito-sandboxes")
for item in Sandbox.list(metadata={"user": "42"}, states=["SUSPENDED"], index=idx):
print(item.sandbox_id, item.state, item.metadata)
paginate(*, template: str | None = None, template_version: str | None = None, states: Iterable[str] | None = None, metadata: Mapping[str, str] | None = None, started_after: datetime | None = None, order: ListOrder | None = None, limit: int | None = None, next_token: str | None = None, region: str | None = None, session: boto3.session.Session | None = None, control_plane: ControlPlane | None = None, transport: TransportSettings | None = None, request_timeout: float = METADATA_PROBE_TIMEOUT_SECONDS, index: DynamoDbIndex | None = None) -> SandboxListPaginator
classmethod
¶
Los filtros de list() como un listado reanudable: cada
next_items() devuelve hasta limit items y next_token (opaco,
ligado a estos filtros) continúa en un paginate() nuevo. Valida todo
sin llamar a AWS; el template se resuelve en el primer next_items().
Al reanudar vuelve a pedir la página del cursor y salta por identidad
los items ya servidos de ella. Con order el primer next_items()
recorre todas las páginas (O(páginas)) y la reanudación es por clave
(startedAt, id). index= como en list() (dynamodb:BatchGetItem
por página, sin sondas); el next_token queda ligado a la tabla.
kill() -> bool
¶
terminate-microvm (idempotente). False sólo si ya no existe.
get_info() -> SandboxInfo
¶
get-microvm fresco y, si el sandbox está RUNNING con plazo
lógico gestionado, un Health (registrado) que lo
refresca: expires_at es el plazo vigente aunque otro cliente lo
haya movido. metadata y los hechos del guest vienen del último
Health sin RPC extra (quedan fijos en /run), y nunca se sondea
un sandbox que no está RUNNING (la sonda lo despertaría). Los
hechos del guest sólo van en el valor devuelto: sbx.info los deja
en None. size/baseline_memory_mib/baseline_cpu sólo
aparecen cuando create(size=...) se usó (m15-sizes-catalog): esa
única llamada a GetMicrovmImageVersion se cachea por versión de
imagen (_size_catalog.DEFAULT_SIZE_CATALOG), así que repetir
get_info() no repite la llamada a AWS. Esto vive en
self._launch_options (relleno sólo por create()/take()):
Sandbox.connect(id).get_info() deja size/baseline_memory_mib/
baseline_cpu en None aunque la imagen tenga el sufijo de un
tamaño, porque el handle de connect() nunca pasó por create()
en este proceso (no hay un requested_size que confirmar). No se
deriva del sufijo del nombre de la imagen a propósito: un nombre
que termine en -4gb por convención propia del operador, no por
--sizes, confirmaría un tamaño que nadie pidió.
pause(*, wait: bool = True) -> bool
¶
suspend-microvm (2 TPS). False si ya estaba SUSPENDING|SUSPENDED
(get-microvm se lee antes: la API acepta un suspend repetido).
El agente cierra todos los streams abiertos con un final suspending
y los handles vivos se reenganchan solos tras resume() (o tras el
auto-resume) la próxima vez que se lean. Mientras este Sandbox tenga
la pausa pendiente, ningún stream en curso (ni siquiera un run_code
o un run en foreground) sondea Health: la pausa no se deshace sola.
resume(*, wait: bool = True) -> None
¶
resume-microvm, reacuña el JWE y espera a Health con
kernel_ready, registrando la nueva resume_generation.
Un ConflictException (el sandbox ya estaba RUNNING, por ejemplo
porque el auto-resume se adelantó) no es un error. Los handles,
watches y run_code en curso se reenganchan por su cuenta. Con
wait, un sandbox reanudado después de su plazo lógico (resume_grace
o expired) se reabre con su propio timeout, como connect().
set_timeout(timeout: int, *, request_timeout: float | None = None) -> None
¶
Fija el plazo lógico en ahora + timeout segundos (SetTimeout
EXACT): puede alargarlo o acortarlo, y reabre un sandbox en
modo pause cuyo plazo venció pero que aún no se suspendió. El tope
es max_lifetime (fijo desde create(), como mucho 28800 s): más
allá, InvalidArgumentException con el plazo intacto y
reincarnate() como salida. Sin max_lifetime/on_timeout en
create() también es InvalidArgumentException.
is_running(*, request_timeout: float | None = None) -> bool
¶
True si rayd responde a Health con agent_ready.
request_timeout acota esa sonda (nunca por encima de 5 s).
get_health(*, request_timeout: float | None = None) -> SandboxHealth
¶
HealthService.Health: readiness, resume_generation,
clock_offset_ms y kernel_state_lost del agente.
get_telemetry_status(*, request_timeout: float | None = None) -> TelemetryHealth
¶
ConfigureService.ConfigureStatus → TelemetryExportStatus
(m15-rayd-otlp). Siempre TelemetryHealth() (todo ceros) si nunca
pasaste telemetry= a create()/connect(), o si la imagen no
soporta la función: nunca lanza por eso. Llamada explícita, no parte
de get_health(), para que el camino sin telemetry= nunca pague
esta llamada extra.
upload_url(path: str, user: str | None = None, use_signature_expiration: int | None = None) -> UploadTicket
¶
La forma de E2B de files.upload_url: use_signature_expiration
son los segundos de vida de la URL (3600 con None; <= 0 es
InvalidArgumentException, una URL de S3 siempre caduca).
download_url(path: str, user: str | None = None, use_signature_expiration: int | None = None) -> DownloadLink
¶
La forma de E2B de files.download_url, con la misma regla para
use_signature_expiration que upload_url.
get_host(port: int) -> HostAccess
¶
Hostname + cabeceras del proxy para port (token acuñado bajo demanda).
get_metrics(*, request_timeout: float | None = None) -> SandboxMetrics
¶
HealthService.Metrics (procfs). Cuesta ≈ 100 ms: el agente toma dos
muestras de /proc/stat para calcular cpu_used_pct.
get_metrics_history(*, start: datetime | None = None, end: datetime | None = None, max_points: int | None = None, request_timeout: float | None = None) -> builtins.list[SandboxMetrics]
¶
HealthService.MetricsHistory: la serie que rayd muestrea cada
5 s desde /run (un anillo de 8 h), en orden ascendente.
start y end son inclusivos (un datetime naive es hora local);
max_points reduce la serie a ese número de tramos: cada punto es la
última muestra de su tramo con cpu_used_pct promediado. En cada
muestra cpu_used_pct es la media desde la anterior (≈ 5 s), no la
ventana de 100 ms de get_metrics(). Mientras el sandbox está
suspendido no se muestrea: la serie tiene un hueco. Una imagen
anterior a 0.3.0 es UnimplementedError.
close() -> None
¶
Libera recursos locales (hilo del refresher, canales). No toca el
MicroVM. Una reconexión en curso termina con SandboxException.
update_network(network: NetworkPolicy | NetworkOptions | None = None, *, allow_internet_access: bool | None = None, request_timeout: float | None = None) -> NetworkState
¶
NetworkService.UpdateNetwork: sustituye la política
entera de forma atómica y afecta a las conexiones nuevas (las abiertas
siguen). None o {} es sin restricciones; allow_internet_access=
False añade ALL_TRAFFIC a deny_out. Una imagen sin CAP_NET_ADMIN
o con un rayd anterior a 0.3.0 es UnimplementedError; una entrada mal
formada, InvalidArgumentException con la lista y el índice.
get_network(*, request_timeout: float | None = None) -> NetworkState
¶
NetworkService.GetNetwork: la política vigente y cómo se aplica,
sin la dirección ni las credenciales del proxy del operador.
run_code(code: str, *, language: str | None = None, context: ContextLike | None = None, on_stdout: StdoutCallback | None = None, on_stderr: StdoutCallback | None = None, on_result: ResultCallback | None = None, on_error: ErrorCallback | None = None, envs: Mapping[str, str] | None = None, timeout: float | None = DEFAULT_CODE_TIMEOUT_SECONDS, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None) -> Execution
¶
Ejecuta código en un kernel Jupyter con estado (CodeService.Execute).
language elige el kernel: python (por defecto), bash,
javascript (alias js) o typescript (alias ts). bash y los
dos últimos, que sirve el kernel Jupyter de Deno, viven en la variante
de imagen rayito-base-poly y arrancan en la primera celda de ese
lenguaje (≈ 1 s dentro del timeout); en rayito-base la llamada
falla con UnimplementedError (el mensaje nombra rayito-base-poly).
language y context son excluyentes; envs por ejecución sólo en
contextos Python.
Devuelve una Execution con results (mime bundles: text, png,
chart, data...), logs.stdout/logs.stderr, error y
execution_count; execution.text es el valor de la última expresión.
Un error del kernel es dato en error, nunca excepción. timeout
(300 s por defecto) lo impone el agente sobre el reloj corrido (una
pausa no lo consume) y termina en error.name == "ExecutionTimeout"
con el contexto intacto salvo que el kernel no responda al interrupt.
context es un CodeContext o su id; None es el contexto por
defecto. Si el sandbox se pausa a mitad de la celda, el SDK espera al
resume y continúa con Reattach sin volver a ejecutarla.
secrets= (y los del handle) viajan en ExecuteRequest.envs sólo
durante esta celda y sólo en contextos Python: con otro language es
InvalidArgumentException (usa create_code_context(secrets=)), y
los del handle no se añaden a celdas de otros lenguajes. Con
context= dado como id (str), los del handle sólo van si el contexto
es default o uno que este handle creó o listó como Python; un id
desconocido (creado desde otro handle) va sin ellos.
Coste y activación¶
Activa: secrets= inyecta secretos como variables de entorno de la celda.
Recursos y llamadas AWS: secretsmanager:GetSecretValue sólo en un
fallo de SecretCache (TTL 300 s); un acierto no llama a AWS.
Coste aproximado: $0,05 por 10 000 llamadas (us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None (por defecto).
Ejemplo:
sbx.run_code("import os; os.getenv('OPENAI_API_KEY') is not None",
secrets={"OPENAI_API_KEY": "openai"})
checkpoint_files(*, target: S3Prefix | None = None, exclude: Sequence[str] = (), timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS, on_progress: CheckpointProgressCallback | None = None, user: str | None = None) -> CheckpointResult
¶
FilesystemService.Checkpoint: rayd empaqueta el HOME del usuario
(tar.gz, sin .cache, __pycache__, .ipynb_checkpoints ni el runtime
de Jupyter) y lo sube como root con el execution role a
s3://bucket/prefix/name/home.tar.gz + manifest.json. target
por defecto es sbx.persist. exclude son directorios relativos al
HOME (sin globs, máx. 64). Un solo checkpoint o restore a la vez por
sandbox (PersistenceException(code="failed_precondition")). Los
procesos que escriban durante el checkpoint pueden dejar copias
truncadas: pausa tu trabajo antes.
restore_files(*, source: S3Prefix | None = None, timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS, on_progress: RestoreProgressCallback | None = None, user: str | None = None) -> RestoreResult
¶
FilesystemService.Restore: descarga el checkpoint de source (por
defecto sbx.persist) y lo extrae sobre el HOME (los ficheros
existentes se sobrescriben, los directorios se fusionan, nada sale del
HOME). NotFoundException si no hay checkpoint. Un fallo a mitad
deja el HOME parcialmente restaurado: kill() + create(persist=)
es la recuperación.
reincarnate(*, exclude: Sequence[str] = (), persist_timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS) -> Self
¶
La respuesta a lo que set_timeout no puede dar, pasar de
max_lifetime: checkpoint_files() → create(persist=)
con las mismas opciones de lanzamiento (que restaura) → kill() de este
sandbox, y devuelve el nuevo. El nuevo tiene 8 h frescas, otro
sandbox_id, otro access token (salvo que el original fuera explícito)
y los mismos metadata (con index= en el create(), el nuevo escribe
su propia fila en el mismo índice) y las mismas opciones que
acaban en ConfigureSandbox (mounts=, volumes=, events=,
telemetry=, gateways=, domain=; size= ya va en el ARN de la
imagen): el sucesor las vuelve a planear y aplicar en su único
Configure por el mismo camino que create(), con sus propios
hechos — events= deriva k_sbx del nuevo sandbox_id, mounts=
espera otra vez a mounted, volumes= resuelve otra vez las IPs de
los mount targets, telemetry= usa la imagen y la memoria del
sucesor y cada cabecera de gateways= se resuelve otra vez, nunca
reenviando un valor ya leído; las
variables del kernel, los procesos y las PTY no sobreviven, sólo los
ficheros del HOME. Si el
create() falla, este sandbox sigue vivo y la excepción lleva una nota
con la uri del checkpoint ya completo. Sólo sobre un sandbox de
create(persist=): un handle de connect() no conoce el lanzamiento.
create_code_context(*, cwd: str | None = None, language: str | None = None, envs: Mapping[str, str] | None = None, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None) -> CodeContext
¶
Kernel nuevo con su propio scope, cwd y envs (máximo 8 por
sandbox); language es python, bash, javascript (alias js)
o typescript (alias ts). Los tres últimos sólo existen en
rayito-base-poly (JS y TS con el kernel de Deno, arrancado al
pedirlo, nunca antes de /ready). secrets= (y los del handle)
quedan en el entorno del kernel de este contexto, de cualquier
lenguaje, mientras viva.
Coste y activación¶
Activa: secrets= inyecta secretos en el entorno del kernel nuevo.
Recursos y llamadas AWS: secretsmanager:GetSecretValue sólo en un
fallo de SecretCache (TTL 300 s).
Coste aproximado: $0,05 por 10 000 llamadas (us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None (por defecto).
Ejemplo:
ctx = sbx.create_code_context(language="bash", secrets={"TOKEN": "gh"})
sbx.run_code("echo ${#TOKEN}", context=ctx)
remove_code_context(context: ContextLike, *, request_timeout: float | None = None) -> None
¶
Mata el kernel del contexto; el default no se puede borrar.
restart_code_context(context: ContextLike, *, request_timeout: float | None = None) -> None
¶
Kernel nuevo con el mismo id; el estado del contexto se pierde.
AsyncSandbox(*, info: SandboxInfo, access_token: str, control_plane: ControlPlane, transport: TransportSettings, refresher: AsyncTokenRefresher, request_timeout: float, ready_timeout: float, reconnect_timeout: float = DEFAULT_RECONNECT_TIMEOUT_SECONDS, logger: logging.Logger | None = None)
¶
Un MicroVM con rayd dentro. Se crea con await AsyncSandbox.create().
launch_info: SandboxInfo
property
¶
La SandboxInfo con la que se abrió el handle, nunca refrescada.
persist: S3Prefix | None
property
¶
El S3Prefix (con name) enlazado por create(persist=) o
connect(persist=); None si el sandbox no persiste.
transfer: S3Staging | None
property
¶
Misma semántica que Sandbox.transfer.
last_restore: RestoreResult | None
property
¶
El resultado del restore automático de create(persist=); None si
no hubo (primera vida de ese name) o si el sandbox no persiste.
gateways: GatewayHandle
property
¶
Misma semántica que Sandbox.gateways.
agent: AsyncAgent
property
¶
El agente de IA de este sandbox (ai-agent-core): run,
stream, prepare. Tocar esta propiedad no manda ningún RPC.
Se construye en el primer uso, así que import rayito no carga
rayito._agent.
git: AsyncGit
property
¶
El módulo git de E2B 2.x (clone, status, commit, push...)
sobre commands.run; se construye en el primer uso.
create(template: str | None = None, *, template_version: str | None = None, timeout: int = DEFAULT_TIMEOUT_SECONDS, max_lifetime: int | None = None, on_timeout: TimeoutActionName | None = None, idle: IdlePolicy | None = DEFAULT_IDLE_POLICY, envs: Mapping[str, str] | None = None, metadata: Mapping[str, str] | None = None, cpu_time_limit: int | None = None, execution_role_arn: str | None = None, allowed_ports: Sequence[PortLike] | None = None, ingress: Sequence[str] | None = None, egress: Sequence[str] | None = None, network: NetworkPolicy | NetworkOptions | None = None, allow_internet_access: bool = True, logging: LoggingOption = 'disabled', region: str | None = None, session: boto3.session.Session | None = None, access_token: str | None = None, ready_timeout: float = DEFAULT_READY_TIMEOUT_SECONDS, request_timeout: float = DEFAULT_REQUEST_TIMEOUT_SECONDS, reconnect_timeout: float = DEFAULT_RECONNECT_TIMEOUT_SECONDS, keep_on_failure: bool = False, control_plane: ControlPlane | None = None, transport: TransportSettings | None = None, persist: S3Prefix | None = None, persist_timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS, pool: AsyncSandboxPool | None = None, transfer: S3Staging | None = None, logger: logging.Logger | None = None, secrets: Mapping[str, str | SecretRef] | None = None, secret_cache: SecretCache | None = None, index: DynamoDbIndex | None = None, tracer_provider: TracerProviderLike | None = None, mounts: Mapping[str, Any] | None = None, volumes: Mapping[str, Any] | None = None, size: str | SizeRequest | None = None, events: Any | None = None, telemetry: Any | None = None, gateways: Mapping[str, Any] | None = None, domain: Any | None = None) -> Self
async
classmethod
¶
Misma semántica que Sandbox.create (incluidos metadata, pool=,
persist=, transfer=, el plazo lógico de max_lifetime/on_timeout
y la política de egress de network=/allow_internet_access, que
termina el VM aunque haya keep_on_failure si la imagen no la aplica,
y secrets=/secret_cache=, resueltos antes de run-microvm).
Coste y activación¶
Activa: secrets= inyecta secretos de Secrets Manager como variables
de entorno de cada comando, PTY o celda; secret_cache= fija la
caché (si no, una compartida por región y sesión, TTL 300 s).
Recursos y llamadas AWS: secretsmanager:GetSecretValue una vez por
secreto y TTL; ningún recurso nuevo y ningún cliente sin secrets=.
Coste aproximado: $0,05 por 10 000 llamadas + $0,40 por secreto y mes
(us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None y secret_cache=None (por defecto).
Ejemplo:
sbx = await AsyncSandbox.create(secrets={"OPENAI_API_KEY": "openai"})
await sbx.commands.run("python agent.py")
index=DynamoDbIndex(...) como en Sandbox.create (fila del índice
tras run-microvm, IndexWriteException y VM terminado si falla con
on_write_failure='terminate').
Coste y activación¶
Activa: index=DynamoDbIndex(...) escribe la fila del índice.
Recursos y llamadas AWS: dynamodb:PutItem una vez por sandbox.
Coste aproximado: ~1 WRU ≈ $0,000000625 (on-demand, us-east-1,
consultado 2026-09-30).
IAM: dynamodb:PutItem sobre la tabla (RayitoIndexWriter).
Cómo apagarla: index=None (por defecto).
Ejemplo:
idx = DynamoDbIndex("rayito-sandboxes")
sbx = await AsyncSandbox.create(metadata={"user": "42"}, index=idx)
tracer_provider= como en Sandbox.create: create() en sí
es un único span rayito.sandbox.create; el handle instrumenta sus
demás operaciones. None (por defecto) es NOOP.
Coste y activación¶
Activa: tracer_provider= (un TracerProvider de
opentelemetry.trace, o cualquier objeto con
get_tracer(name, version)).
Recursos y llamadas AWS: ninguno.
Coste aproximado: $0 de AWS.
IAM: ninguno adicional.
Cómo apagarla: no pases tracer_provider= (por defecto None).
Ejemplo:
from opentelemetry import trace
sbx = await AsyncSandbox.create(tracer_provider=trace.get_tracer_provider())
telemetry= (m15-rayd-otlp, ADR-021) hace que rayd exporte 7
gauges de CPU, memoria y disco a CloudWatch cada interval_s
(15-300 s), como en Sandbox.create.
Coste y activación¶
Activa: telemetry=TelemetryExport(...) en create().
Recursos y llamadas AWS: PutMetricData por lote exportado; con
OtlpAuth.execution_role() necesitas la política
RayitoOtlpExport (rayito stack deploy otlp-export) en el
execution role.
Coste aproximado: $0 por la opción; CloudWatch factura la ingesta
OTLP a $0,50/GB: ≈ $0,00002 por sandbox-hora con interval_s=60
(AWS_API_NOTES.md Q120).
IAM: cloudwatch:PutMetricData sobre el dataset OTLP por defecto de
la cuenta (no se puede acotar por namespace, research OT9).
Cómo apagarla: no pases telemetry= (por defecto None); borra la
pila otlp-export si ya no la usa ningún sandbox.
Ejemplo:
from rayito import OtlpAuth, TelemetryExport
sbx = await AsyncSandbox.create(
"rayito-base-caps", execution_role_arn=role_arn,
telemetry=TelemetryExport(auth=OtlpAuth.execution_role()),
)
domain= sigue sin cablear (UnimplementedError antes de
run-microvm; para un dominio propio usa AsyncCustomDomain,
experimental); mounts=, volumes=, size=, events=,
telemetry= y gateways= son reales, como en Sandbox.create.
volumes= (m15-efs-volumes, experimental) monta cada EfsVolume
con amazon-efs-utils antes de que create() vuelva, igual que
Sandbox.create (mismas exigencias: execution_role_arn=, un solo
conector propio en egress=, imagen rayito-base-caps-efs);
await sbx.volumes() da el estado en vivo.
Coste y activación¶
Activa: volumes={"/mnt/datos": vol} en create(), con
execution_role_arn=, egress=[<ConnectorArn>] y la imagen
opcional rayito-base-caps-efs.
Recursos y llamadas AWS: ningún recurso nuevo; una
DescribeMountTargets por sistema de ficheros y create() si un
EfsVolume no trae mount_target_ip (credenciales del
llamante); la pila efs-volumes va aparte.
Coste aproximado: $0 propio; almacenamiento y rendimiento de EFS, y
≈ 198 MB más de código instalado en la imagen (us-east-1,
consultado 2026-10-04, https://aws.amazon.com/efs/pricing/).
IAM: el llamante, elasticfilesystem:DescribeMountTargets; el
execution role, CallerPolicyArn de la pila efs-volumes.
Cómo apagarla: no pases volumes= (por defecto None).
Ejemplo:
sbx = await AsyncSandbox.create(
"rayito-base-caps-efs", execution_role_arn=role_arn,
egress=[connector_arn], volumes={"/mnt/datos": vol},
)
mounts= (m15-s3-mounts) monta cada S3Mount con mount-s3, sólo
en rayito-base-caps y sólo los buckets del allowlist de la imagen.
Coste y activación¶
Activa: mounts={"/mnt/data": S3Mount(bucket="...")} en create(),
con execution_role_arn= y el bucket en
RAYITO_ALLOWED_MOUNT_BUCKETS de la imagen.
Recursos y llamadas AWS: ningún recurso nuevo; las peticiones S3
normales de mount-s3 con el execution role; la política sale de
la pila s3-mounts (sólo IAM).
Coste aproximado: $0 propio; las peticiones y el almacenamiento de
S3 del bucket montado (us-east-1, consultado 2026-10-01).
IAM: RayitoS3MountAccess (infra/s3-mounts.yaml) en el execution
role.
Cómo apagarla: no pases mounts= (por defecto None); rayito
stack destroy s3-mounts quita la política.
Ejemplo:
sbx = await AsyncSandbox.create(
"rayito-base-caps", execution_role_arn=role_arn,
mounts={"/mnt/data": S3Mount(bucket="mi-bucket")},
)
size= (m15-sizes-catalog) elige en el cliente la imagen de ese
tamaño (rayito-base-4gb), que tiene que estar publicada.
Coste y activación¶
Activa: size="4gb" (o SizeRequest(memory_mib=...)) en
create(), tras rayito image publish --sizes 4gb.
Recursos y llamadas AWS: ninguno nuevo al lanzar; cada tamaño
publicado es una imagen más en tu cuenta.
Coste aproximado: de $0,0315/h (512 MiB) a $0,5044/h (8192 MiB) en
baseline (limits.md, us-east-1, consultado 2026-09-30), más
≈ $0,04/semana de snapshot por versión de imagen publicada.
IAM: ninguno adicional (sizes-guard es opcional).
Cómo apagarla: no pases size= (por defecto None).
Ejemplo:
sbx = await AsyncSandbox.create(size="4gb")
events= (m15-events-webhooks, ADR-020) manda a rayd la clave de
este sandbox (k_sbx) en el mismo ConfigureSandbox, como en
Sandbox.create; acepta AsyncLifecycleEvents o LifecycleEvents
y exige un logging= que llegue a CloudWatch.
Coste y activación¶
Activa: events=AsyncLifecycleEvents(...) en create(), con la
pila events-webhooks ya desplegada.
Recursos y llamadas AWS: un secretsmanager:GetSecretValue de la
clave del stack por instancia (más un DescribeStacks si no se
desplegó con ella); la pila hace el resto.
Coste aproximado: el de la pila (~$0,40/mes el secreto, el resto por
uso); la opción en sí, una lectura de Secrets Manager.
IAM: EventsLauncherPolicy en las credenciales del llamante.
Cómo apagarla: no pases events= (por defecto None).
Ejemplo:
from rayito import AsyncLifecycleEvents
events = AsyncLifecycleEvents()
sbx = await AsyncSandbox.create(
execution_role_arn=role_arn, logging="cloudwatch", events=events,
)
connect(*, timeout: int | None = None, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None, secret_cache: SecretCache | None = None, tracer_provider: TracerProviderLike | None = None) -> AsyncSandbox
async
¶
Misma semántica que sbx.connect() de Sandbox: reabre este
handle y extiende el plazo (AT_LEAST). Devuelve self.
secrets=/secret_cache= sustituyen los del handle; None los
conserva y secrets={} los borra todos. tracer_provider=
sustituye la Instrumentation del handle; None conserva la que ya
tenía ($0 de AWS: ver el bloque de create()).
Coste y activación¶
Activa: secrets= (y secret_cache=) inyectan secretos de Secrets
Manager en cada comando, PTY, celda Python y contexto de este
handle; sin ellos, connect() no construye ningún cliente
secretsmanager (el camino de 0.4.0).
Recursos y llamadas AWS: GetSecretValue una vez por secreto y TTL de
SecretCache (300 s por defecto), resuelto aquí antes de
get-microvm; ningún recurso nuevo.
Coste aproximado: $0,05 por 10 000 llamadas (≈ $0,04/mes por secreto
y proceso con TTL 300) + $0,40 por secreto y mes (us-east-1,
2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante
(RayitoSecretsReader de infra/secrets-access.yaml); kms:Decrypt
con una CMK.
Cómo apagarla: no pases secrets= ni secret_cache=; secrets={}
quita los que el handle ya tenía.
Ejemplo:
await sbx.connect(secrets={"OPENAI_API_KEY": "openai"})
await sbx.commands.run("python agent.py") # 0 llamadas: ya en caché
list(*, template: str | None = None, template_version: str | None = None, states: Iterable[str] | None = None, metadata: Mapping[str, str] | None = None, started_after: datetime | None = None, order: ListOrder | None = None, region: str | None = None, session: boto3.session.Session | None = None, control_plane: ControlPlane | None = None, transport: TransportSettings | None = None, request_timeout: float = METADATA_PROBE_TIMEOUT_SECONDS, index: DynamoDbIndex | None = None) -> builtins.list[SandboxListItem]
async
classmethod
¶
Misma semántica y mismo coste O(n) con metadata que Sandbox.list;
las sondas de Health van por grpc.aio, una tras otra. Con
index=DynamoDbIndex(...) y metadata, sin sondas: un
dynamodb:BatchGetItem por página (ver Sandbox.list).
paginate(*, template: str | None = None, template_version: str | None = None, states: Iterable[str] | None = None, metadata: Mapping[str, str] | None = None, started_after: datetime | None = None, order: ListOrder | None = None, limit: int | None = None, next_token: str | None = None, region: str | None = None, session: boto3.session.Session | None = None, control_plane: ControlPlane | None = None, transport: TransportSettings | None = None, request_timeout: float = METADATA_PROBE_TIMEOUT_SECONDS, index: DynamoDbIndex | None = None) -> AsyncSandboxListPaginator
classmethod
¶
Sandbox.paginate con next_items() asíncrono. No es async:
construir el paginador valida sin hacer E/S.
get_info() -> SandboxInfo
async
¶
Misma semántica que Sandbox.get_info: un Health sólo si el
sandbox está RUNNING con plazo lógico gestionado, para refrescarlo.
size/baseline_memory_mib/baseline_cpu sólo aparecen cuando
create(size=...) se usó (m15-sizes-catalog); ver la versión sync
para el porqué de la única llamada cacheada a
GetMicrovmImageVersion, y para por qué AsyncSandbox.connect(id)
los deja en None aunque la imagen lleve sufijo de tamaño.
pause(*, wait: bool = True) -> bool
async
¶
Misma semántica que Sandbox.pause: mientras la pausa esté
pendiente ningún stream en curso sondea Health.
resume(*, wait: bool = True) -> None
async
¶
Misma semántica que Sandbox.resume (incluida la reapertura de un
sandbox reanudado después de su plazo lógico).
set_timeout(timeout: int, *, request_timeout: float | None = None) -> None
async
¶
Misma semántica que Sandbox.set_timeout (SetTimeout EXACT).
is_running(*, request_timeout: float | None = None) -> bool
async
¶
Como Sandbox.is_running.
get_telemetry_status(*, request_timeout: float | None = None) -> TelemetryHealth
async
¶
Como Sandbox.get_telemetry_status (m15-rayd-otlp).
mounts() -> dict[str, MountStatus]
async
¶
Estado en vivo de cada mounts= (m15-s3-mounts): una
ConfigureStatus por lectura, nunca cacheada. Vacío si
create()/take() no recibió mounts=.
volumes() -> dict[str, VolumeStatus]
async
¶
Estado en vivo de cada volumes= (m15-efs-volumes): una
ConfigureStatus por lectura, nunca cacheada — tras un resume()
un volumen puede pasar por "remounting"/"degraded". Vacío si
create() no recibió volumes=.
upload_url(path: str, user: str | None = None, use_signature_expiration: int | None = None) -> AsyncUploadTicket
async
¶
Misma semántica que Sandbox.upload_url.
download_url(path: str, user: str | None = None, use_signature_expiration: int | None = None) -> DownloadLink
async
¶
Misma semántica que Sandbox.download_url.
get_metrics_history(*, start: datetime | None = None, end: datetime | None = None, max_points: int | None = None, request_timeout: float | None = None) -> builtins.list[SandboxMetrics]
async
¶
Misma semántica que Sandbox.get_metrics_history.
update_network(network: NetworkPolicy | NetworkOptions | None = None, *, allow_internet_access: bool | None = None, request_timeout: float | None = None) -> NetworkState
async
¶
Misma semántica que Sandbox.update_network: sustituye la política
entera (None o {} es sin restricciones) y afecta a las conexiones
nuevas.
get_network(*, request_timeout: float | None = None) -> NetworkState
async
¶
Misma semántica que Sandbox.get_network.
run_code(code: str, *, language: str | None = None, context: ContextLike | None = None, on_stdout: StdoutCallback | None = None, on_stderr: StdoutCallback | None = None, on_result: ResultCallback | None = None, on_error: ErrorCallback | None = None, envs: Mapping[str, str] | None = None, timeout: float | None = DEFAULT_CODE_TIMEOUT_SECONDS, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None) -> Execution
async
¶
Misma semántica que Sandbox.run_code; los callbacks son síncronos.
Coste y activación¶
Activa: secrets= inyecta secretos en el entorno de la celda (sólo
contextos Python).
Recursos y llamadas AWS: secretsmanager:GetSecretValue sólo en un
fallo de SecretCache (TTL 300 s).
Coste aproximado: $0,05 por 10 000 llamadas (us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None (por defecto).
Ejemplo:
await sbx.run_code("import os", secrets={"OPENAI_API_KEY": "openai"})
checkpoint_files(*, target: S3Prefix | None = None, exclude: Sequence[str] = (), timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS, on_progress: CheckpointProgressCallback | None = None, user: str | None = None) -> CheckpointResult
async
¶
Misma semántica que Sandbox.checkpoint_files.
restore_files(*, source: S3Prefix | None = None, timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS, on_progress: RestoreProgressCallback | None = None, user: str | None = None) -> RestoreResult
async
¶
Misma semántica que Sandbox.restore_files.
reincarnate(*, exclude: Sequence[str] = (), persist_timeout: float = DEFAULT_PERSIST_TIMEOUT_SECONDS) -> Self
async
¶
Misma semántica que Sandbox.reincarnate: checkpoint → create(persist=)
con las mismas opciones (restaura, y reaplica mounts=/volumes=/
events=/telemetry=/gateways=/domain= en el Configure del
sucesor; size= ya va en el ARN) → kill() de este sandbox.
create_code_context(*, cwd: str | None = None, language: str | None = None, envs: Mapping[str, str] | None = None, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None) -> CodeContext
async
¶
Misma semántica que Sandbox.create_code_context, lenguajes,
variante de imagen y secrets= incluidos.
Coste y activación¶
Activa: secrets= inyecta secretos en el entorno del kernel nuevo.
Recursos y llamadas AWS: secretsmanager:GetSecretValue sólo en un
fallo de SecretCache (TTL 300 s).
Coste aproximado: $0,05 por 10 000 llamadas (us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None (por defecto).
Ejemplo:
ctx = await sbx.create_code_context(language="bash", secrets={"T": "gh"})