tavya

Cloud computers

Every task runs on its own cloud computer. tavya can run it on its own accounts (charged to your plan's compute), or on yours: connect an account under Settings → Computers, and your tasks use it at the provider's price, with nothing added.

DiskPausedGood for
E2Bup to ~29 GBmemory kept, resumes in a secondthe fastest start; a desktop or an outbound allowlist
Daytonaup to 10 GBresumes in secondsthe same, smaller disks
Fly.ioup to 500 GBdisk kept, wakes in ~5 slarge disks
Hetznerup to 10 TBdisk kept, wakes in ~30–60 sthe lowest price (EU)
AWSup to 16 TBdisk kept, wakes in ~20–40 syour own AWS account, any region
Google Cloudup to 64 TBdisk kept, wakes in ~20–40 syour own Google Cloud project; machines of exactly the size you choose

On Fly.io, Hetzner, AWS and Google Cloud a computer's disk keeps everything, including files Git ignores, and grows while the task runs. They have no desktop and no outbound allowlist.

On tavya's own accounts each computer has a size limit, shown as each field's maximum in the Computer form. For bigger machines, connect your own account.

Any (the default)

Leave a task's provider on Any and give it the size it needs (and, under More, a desktop, an outbound allowlist or a region). tavya then uses the first computer that fits and has room: your own accounts first, then its own by price. When one is full, it takes the next, and waits only when all are. A task keeps its computer once it has one; it moves only if you ask for more than that account allows. Choose a provider instead to run on it and nothing else. The task page shows where it runs and why.

AWS

tavya makes each computer in the region's default VPC: an instance with a public address (only SSH on port 2222 is open), and a gp3 volume for its files. A paused computer is a stopped instance, so you pay only for its disks.

  1. In the IAM console, create a user (no console access), for example tavya.
  2. Give it this inline policy. It may create only what it tags, and change only what tavya tagged:
{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "Read", "Effect": "Allow", "Action": ["ec2:Describe*", "pricing:GetProducts", "servicequotas:GetServiceQuota"], "Resource": "*" },
    { "Sid": "LaunchTagged", "Effect": "Allow", "Action": ["ec2:RunInstances", "ec2:CreateVolume"],
      "Resource": ["arn:aws:ec2:*:*:instance/*", "arn:aws:ec2:*:*:volume/*"],
      "Condition": { "Null": { "aws:RequestTag/karmaxHome": "false" } } },
    { "Sid": "LaunchFrom", "Effect": "Allow", "Action": "ec2:RunInstances",
      "Resource": ["arn:aws:ec2:*::image/*", "arn:aws:ec2:*::snapshot/*", "arn:aws:ec2:*:*:subnet/*",
        "arn:aws:ec2:*:*:network-interface/*", "arn:aws:ec2:*:*:security-group/*"] },
    { "Sid": "TagWhileCreating", "Effect": "Allow", "Action": "ec2:CreateTags", "Resource": "*",
      "Condition": { "StringEquals": { "ec2:CreateAction": ["RunInstances", "CreateVolume", "CreateSecurityGroup", "CreateImage"] } } },
    { "Sid": "ManageTagged", "Effect": "Allow",
      "Action": ["ec2:StartInstances", "ec2:StopInstances", "ec2:TerminateInstances", "ec2:ModifyInstanceAttribute",
        "ec2:AttachVolume", "ec2:DeleteVolume", "ec2:ModifyVolume", "ec2:CreateTags"],
      "Resource": ["arn:aws:ec2:*:*:instance/*", "arn:aws:ec2:*:*:volume/*"],
      "Condition": { "Null": { "aws:ResourceTag/karmaxHome": "false" } } },
    { "Sid": "SecurityGroup", "Effect": "Allow", "Action": "ec2:CreateSecurityGroup",
      "Resource": ["arn:aws:ec2:*:*:vpc/*", "arn:aws:ec2:*:*:security-group/*"] },
    { "Sid": "OpenSsh", "Effect": "Allow", "Action": "ec2:AuthorizeSecurityGroupIngress", "Resource": "arn:aws:ec2:*:*:security-group/*",
      "Condition": { "Null": { "aws:ResourceTag/karmaxSecurityGroup": "false" } } },
    { "Sid": "BuildImage", "Effect": "Allow", "Action": "ec2:CreateImage",
      "Resource": ["arn:aws:ec2:*:*:instance/*", "arn:aws:ec2:*::image/*", "arn:aws:ec2:*::snapshot/*"] },
    { "Sid": "RemoveOldImages", "Effect": "Allow", "Action": ["ec2:DeregisterImage", "ec2:DeleteSnapshot"],
      "Resource": ["arn:aws:ec2:*::image/*", "arn:aws:ec2:*::snapshot/*"],
      "Condition": { "Null": { "aws:ResourceTag/karmaxImage": "false" } } }
  ]
}
  1. Under the user's Security credentials, create an access key ("Application running outside AWS").
  2. In tavya, Settings → Computers → AWS → Connect: paste the access key ID and the secret access key. Under Advanced, choose the region (default eu-central-1).

The first computer in a region builds tavya's machine image there (about 10 minutes, once); until then computers set themselves up from Debian, which takes a few minutes more. A new AWS account may run only a few CPUs at once: ask for more under Service Quotas → Amazon EC2 → Running On-Demand Standard instances. tavya reads that quota (and your gp3 storage quota) to queue tasks instead of letting AWS refuse them. A region without a default VPC needs one (VPC → Your VPCs → Actions → Create default VPC).

Google Cloud

tavya makes each computer in the project's default network: an E2 machine of exactly the size you choose, with a public address (only SSH on port 2222 is open), and a balanced persistent disk for its files. Machines get no service account, so nothing on them can act on your project.

  1. Create a project for tavya (or use one), with billing on, and enable the Compute Engine API. Enabling the Cloud Billing API too lets tavya show your region's prices.
  2. IAM & Admin → Service accounts → Create service account, for example tavya, with the role Compute Admin.
  3. On the service account, Keys → Add key → Create new key → JSON.
  4. In tavya, Settings → Computers → Google Cloud → Connect: paste the key file, or drop it on the field. Under Advanced, choose the zone (default europe-west3-a).

A new project may run only a few CPUs at once: ask for more under IAM & Admin → Quotas (CPUs in your region).