Skip to content

Repository files navigation

Cloudbox

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

Environments

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 and validation

TESTS.md defines test suites, commands, commit checks, environment handling, and measured results.

GitHub mentions

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 --json

Local tests simulate GitHub and AWS. Live issue and PR checks require a separate deployment and test run.

Email replies

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 --json

Email 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 test

The 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.

Agent completion and files

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.

Separate supervisor

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.

Check or delete resources

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-secret

Teardown 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.

About

Self-host and run agentic workflows in AWS

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages