Run Pi with GLM 5.3 (z-ai/glm-5.3) through OpenRouter in an AWS Lambda
MicroVM. Start jobs from the command line, email, or @cloudbox-agent on GitHub.
CLI -> Lambda supervisor -> MicroVM runner -> Pi -> OpenRouter
| |
| +-> own files + log stream
| +-> S3 report -> Lambda supervisor
+-> trusted records + stop VM
EventBridge -> Lambda supervisor -> recover unfinished cleanup
Email -> SES -> S3 inbox -> email Lambda -> Lambda supervisor
+-> SES -> original sender
GitHub -> Function URL -> webhook Lambda -> S3 request
+-> Lambda supervisor -> MicroVM
+-> GitHub reply
Commands require --env test or --env prod. Use test for disposable resources
and prod for a persistent deployment.
Set your account ID, region, and AWS profile in
infra/environments/<env>.tfvars.json. These local files are Git-ignored.
Each environment has separate bootstrap and main state under
.cloudbox/environments/<env>/. Back up inputs and state. Never change the
account or region of existing state. The wrappers check the selected account;
the CLI reads Terraform outputs in memory.
TESTS.md defines test suites, commands, commit checks, environment handling, and measured results.
Configure the cloudbox-agent App and allowed user IDs through
GitHub setup. Tag @cloudbox-agent in a new
issue, issue/PR comment, inline review comment, or submitted review. Edits do
not start work. Add a new comment to request another run. Bot messages and
mentions in quoted text or code do not start work.
Fork PR requests are blocked in this version. Each job receives read and write access only to its target repo.
The receiver checks the signature, installation, repository, and user before saving a request in S3. Delivery retries reuse one run. Requests for the same issue or PR run one at a time. The scheduled supervisor retries saved requests and replies. No GitHub queue or workflow file is required.
The supervisor posts an acknowledgement and a result on GitHub. Replies use saved source details; inline requests receive replies in the review thread. Saved comment IDs and bot markers identify earlier replies on retry. If a scan reaches 1,000 comments without finding a prior reply or the end, the reply remains pending for inspection. Inspect source and reply state with:
uv run cloudbox --env test status RUN_ID --jsonLocal tests simulate GitHub and AWS. Live issue and PR checks require a separate deployment and test run.
Every accepted email job receives a reply. Intake saves its checked From
address under control/email-runs/ before launch. The supervisor sends the
saved answer to that address through SES. Reply-To, forwarded addresses, and
agent text cannot change the recipient. The guest has no email send permission.
Failed, blocked, cancelled, and timed-out jobs also receive a reply.
The supervisor uses the configured email_address as its sending address.
IAM restricts recipients to email_allowed_senders. SES requires a verified
sending identity; sandbox accounts also require verified recipients.
Automatic replies and mail from the system address cannot start jobs.
Email retries continue after VM cleanup. A saved send record prevents normal duplicate sends. A lost SES response can still cause a duplicate. SES acceptance does not prove inbox delivery. Published file links keep their existing expiry.
Find an email job and inspect its reply:
uv run cloudbox --env prod list --email-from alex@kurilin.net
uv run cloudbox --env prod list --email-subject "Tax Newsletter"
uv run cloudbox --env prod status RUN_ID --jsonEmail jobs include email.sender, subject, receipt_id, message_id, and
reply. Reply state is awaiting_result, pending, or sent. A sent reply
includes the SES message ID and send time. sent means SES accepted the reply.
The job can succeed while its reply remains pending. wait waits for the job,
not email delivery. Rejected messages have no job and do not appear in list.
Use the same filters when you continue with --cursor.
In test, set email_address to testrun@cloudbox.kuril.in and allow
tester@cloudbox.kuril.in. Terraform creates an S3-only receipt rule for the
test sender. It stores replies under email-replies/ without starting jobs. In
prod, use run@cloudbox.kuril.in and omit the test sender from the allowlist.
Run:
uv run python scripts/smoke_email.py --env testThe test sends a task, checks its attachments and output, then reads the returned
email from S3 and checks for the answer KURILIN. It saves the received email as
reply.eml under .cloudbox/email-smoke/<test-id>/. Test inbox mail expires after
seven days. No third-party inbox is required. This verifies SES delivery, not
delivery to an external provider such as Gmail.
The agent calls finish with status (completed or blocked), a short
summary, either response text or a response_file path, and optional JSON
object result. The tool reads a response file under output/ into response
without edits. It validates the report and ends the agent run. Invalid calls
return an error for correction. Call finish alone after other tools finish. The response
must contain text; files are optional.
If the agent returns text without finish, the harness sends one completion
reminder. A missing report after that reminder still fails the run.
The guest saves report.json; Lambda writes the final result.json, with
finish fields under report, runtime status, timing, and usage. The local runner
marks crashes and timeouts as failures even
if a report claims completion. A blocked report also ends the run. The supervisor
still revokes credentials and stops the VM. Reports are limited to 1 MiB of JSON
and 128 nesting levels. Top-level fields are fixed; result has arbitrary fields
whose values can contain any JSON data.
The agent publishes selected files with publish_file(path) before completion.
Files must be regular files under the workspace's output/ directory. The tool
checks paths and limits, uploads to this run's private S3 prefix, and returns file
metadata without signed URLs. Upload errors remain correctable tool errors.
The supervisor saves the agent's answer with a download section made from the
published file manifest. Links and expiry times are inserted by code, without
passing through model text. The agent still selects which files to publish.
Signed links expire with their signing credentials, at most one hour. Use
links RUN_ID for fresh URLs or download RUN_ID for authenticated downloads.
Stored object keys remain available until normal retention removes the files.
New runs use internal schema 7. Update the supervisor and worker image together. User input specifications remain schema 1. Historical result files still download; live status and cancellation require a trusted launch record.
The Lambda supervisor owns launch, cancellation, final records, and cleanup.
The guest runner starts Pi, publishes files, and sends logs. Job VMs have no
execution role. Each guest receives temporary access to its own S3 prefix and
one pre-created CloudWatch stream. Guest writes allow only artifacts and
report.json; spec.json, launch.json, result.json, and control/ stay
outside guest write access.
S3 completion and trusted launch events invoke cleanup. A scheduled check recovers lost launch responses and missed events. Recovery reuses the exact launch request and stops retrying before credentials could expire during a new run. The AWS hard timeout remains independent of the supervisor.
Private control/active/ records contain the launch payload and task credentials
for retry and revocation. They are encrypted in S3, inaccessible to guest
credentials, and deleted after shutdown or the hard timeout, once token access ends.
Never use a worker-supplied VM ID for cloud control. The first final result wins
completion/cancellation races.
Final records are not revised after later token cleanup attempts.
Before upgrading an existing deployment, stop its active runs. Setup disables the old runtime role but retains the denied role to avoid destructive migration. Review and approve deployment separately from local implementation. See cloud validation for deployment checks.
uv run python scripts/check_resources.py --env test
uv run python scripts/check_resources.py --env test --require-clean
uv run python scripts/check_resources.py --env test --audit --require-clean
uv run python scripts/teardown.py --env test --plan
uv run python scripts/teardown.py --env test --force-delete-secretTeardown asks for approval; --yes skips the prompt. It stops VMs, deletes the
image and bucket contents, then destroys main infrastructure and IAM bootstrap.
It waits for active image builds before deletion and verifies absence. Local
keys, inputs, state files, and downloads stay.
Without --force-delete-secret, secrets keep seven-day recovery and the
checker does not report a clean deployment. Keep state until deletion completes.
Terraform's parsed plan and state define managed resources, including modules. Checks retain account, ownership, and deletion limits. Direct AWS checks cover image cleanup, active VMs, bucket data, and secrets.
Use --audit to search supported AWS services for project resources outside
state. Setup and teardown do not run this broad audit. “Clean” applies only to
the reported scope; it always requires empty local state. Teardown reports
checked_resources_absent for that scope. See infrastructure notes.