A private runtime with controlled public entry points
OpenAnvil separates the web app, run control plane, mobile compute, and durable run data. Deployment validates each boundary before cloud mutation begins.
How the web app is hosted
The Next.js app runs privately in ECS behind an internal ALB. API Gateway with VPC Link is the controlled public entry. https://openanvil.ai is the canonical public URL, manually managed outside IaC.
Cloud topology
Public clients enter through API Gateway. The app, workers, control plane, and data remain behind managed private boundaries.
Three planes keep responsibilities clear
The architecture is easier to reason about when storage, control, and execution are separated.
S3 is the durable run record
The runs bucket stores manifests, machine state, transcripts, generated code, grading evidence, and reward. Versioning protects the record.
Events coordinate the lifecycle
EventBridge, SNS, SQS, and Lambda route start, submit, stop, clone, and grader actions without coupling clients to compute.
Workers build and grade apps
Linux EC2 workers run agent and Android images. Dedicated Mac hosts run Tart and iOS Simulator workloads.
How a cloud run reaches compute
The client starts a run without holding AWS credentials or launching EC2 directly.
- 1The client calls POST /runsAPI Gateway (default prod https://j54iumeh78.execute-api.us-west-2.amazonaws.com/prod from yaml cloud.api_url) forwards the request to the API Lambda. The request includes trial, platform, model, and safety limits.
- 2The API records intentThe Lambda creates the run identifier, writes initial machine.json status queued to S3 so GET returns queued immediately (fix for not_found persisting), and emits run_start.
- 3Events fan outEventBridge openanvil-orchestrator-bus forwards the event through SNS. Filtered SQS queues isolate app updates, run launch, grader boot, and indexing.
- 4The control Lambda launches computeThe run-launch queue invokes the control Lambda. It creates an EC2 worker in a private subnet, writes machine.json status provisioning → running, waits for SSM Online.
- 5SSM starts the runtimeThe Lambda sends an asynchronous nohup command that pulls the immutable image and starts the OpenAnvil agent loop inside docker.
- 6S3 reports progressThin CLI now live-follows via GET /runs/{id} and /runs/{id}/logs polling every 3s, showing 📥 Queued → 🔧 Provisioning (instance_id) → 🖥️ Machine Booted → 🤖 Agent Loop → 🧪 Grading, with transcript events, not just single snapshot.
CI and deployment workflows
Three workflows form the app deployment chain. A fourth workflow builds reusable runtime and grader artifacts independently.
GitHub Actions control plane
The app deployment chain is sequential. Builder images run on an independent path-triggered and scheduled workflow.
Validate Repo
Trigger: push or pull request to main
Proves: code, trials, app, infra, image input
Cloud Predeploy
Trigger: 01 completed successfully or manual
Proves: live account readiness and change sets
Deploy Platform
Trigger: 02 completed successfully or manual
Proves: immutable image, ECS, health, ingress
Build Images
Path changes, manual dispatch, or Monday schedule.
Publishes Android grader, agent runtime, iOS pantry, and code bundle artifacts.
01Validate Repo
Fast, deterministic, no AWS mutation
Validate Repo
Trigger and permissions
Runs on every push and pull request to main. The ubuntu-latest label resolves through the internal Actions runner, and this workflow does not request AWS credentials.
What must pass
Secret and dash checks, Python tests on 3.11 and 3.12, every trial validator (now checks description required, category, platforms), the Next.js build, workflow parsing, CloudFormation lint, shellcheck, infra contracts, and a Docker build without push. CI validate-trials loops openanvil validate $trial for each trial.
main emits the workflow completion event that starts Cloud Predeploy. Pull requests stop after repository validation.02Cloud Predeploy
Live account proof, no execution
Cloud Predeploy
Automatic trigger
Runs only after 01 Validate Repo completes successfully on main. A manual dispatch can start it directly.
Authentication
GitHub OIDC assumes the openanvil-infra-deployer role. No long-lived AWS key is stored in the workflow.
03Deploy Platform
Only cloud-mutating app path
Deploy Platform
Tag with 8-character commit SHA, push SHA and latest, reject images below 10 MB.
Require VPC outputs, ensure the log group, then update the ECS and internal ALB stack.
Poll ECS up to ten times and inspect load balancer target health.
Run only when verify-ecs emits READY=true. Manual dispatch cannot bypass this gate.
Always print final stack states, endpoints, and the public health-check result.
90Builders: Build Images
Independent artifact pipeline
Builders: Build Images
Triggers
Runs when runtime specifications, Dockerfiles, iOS build inputs, ECR templates, or code-bundle files change. It also supports manual dispatch and runs Mondays at 02:00 UTC.
Four parallel products
Android grader image, agent runtime image, iOS pantry package, and versioned OpenAnvil source bundle.
openanvil.zip, uploads a current key plus dated history, and retains a GitHub artifact for 14 days.Deployment is a three-stage safety ladder
Static errors, live account problems, and cloud mutations fail in different ways. The workflows keep those risks separate.
Deployment confidence ladder
Each stage proves a stronger claim. Cloud mutation begins only after static and live-account checks pass.
lint, contracts, tests, builds
outputs, ownership, dry runs
image, ECS, verify, ingress
Validate repository
Parse YAML, lint CloudFormation and shell, run contracts and tests, build the app, and validate Docker inputs. No AWS mutation.
Cloud predeploy
Read live stack state, require real upstream outputs, detect ownership collisions, and create no-execute change sets.
Deploy platform
Build and push an immutable app image, deploy ECS, verify the task and ALB target, then expose it through API Gateway.
deploy-platform.yml is the only workflow that mutates the app hosting path. Shared scripts hold reusable logic, while the workflow owns ordering and gates.The AWS account is private by default
OpenAnvil does not assume public subnets, an internet gateway, or an internet-facing load balancer.
Current deployment boundary
The infrastructure contract is clearer than the complete runtime path. These states should remain visible in the docs.