Skip to main content

Changelog

0.1.61

Slack notifications work on hosted APIs

anycloud notifications now configures the API you are pointed at, storing the webhook there encrypted so it survives restarts and upgrades. Hosted APIs could not previously send anything. test now posts from the API. Re-run enable against each API; local APIs migrate automatically.

Vast VM cleanup recognizes released instances

Vast VM termination now recognizes both omitted destroyed-instance records and provider-retained unloaded records as fully released, allowing deployment cleanup to complete promptly instead of repeatedly issuing delete requests after the host is already gone.

Terminated deployments show when the machine is still running

Status and list now mark a terminated deployment whose cloud machine has not been released yet, so a tombstone is never mistaken for stopped spend. Release also retries far sooner after a failed attempt instead of waiting a fixed five minutes, cutting billed time and freeing capacity for your next run.

Long-running logs no longer block VM operations

Long-running log followers and exec sessions no longer block later VM operations. Anycloud now isolates user commands from platform monitoring through OpenSSH multiplexing, reaps retired connections, and returns an immediate capacity error above ten concurrent user sessions.

Shared API output identifies a single teammate's activity

Shared hosted API list and cost output now identifies another member's activity even when every returned deployment or dollar belongs to that one person. Caller-only results remain compact, and machine-readable output retains its existing shape.

Region pin warnings work with saved credentials

Jobs, Services, and VMs now warn when a saved cloud credential is combined with --region, making the loss of regional capacity failover visible before submission while continuing to honor intentional region constraints.

Hosted API upgrades now require durable owner identity

Hosted API upgrades now require the complete owner identity written by current releases. APIs not migrated through 0.1.60 must use that release first; current hosted APIs continue updating normally.

Hosted API guidance covers the complete lifecycle

Platform documentation now walks through creating, selecting, sharing, updating, and retiring a hosted API, while clearly distinguishing the local api start command from the hosted api serve workflow.

API requests carry their client version in a header

Requests now send the client version in an AnyCloud-Client-Version header instead of a version body or query field, and JSON endpoints return errors as {code, status, message}. Streaming and bucket-transfer endpoints keep their old error bodies. The CLI and Python SDK handle both; direct API scripts need the header.

0.1.60

Hosted APIs created before durable owner IDs upgrade normally

anycloud api update now carries the authenticated owner's durable identity forward when upgrading older hosted APIs, preventing legacy owner metadata from surfacing as a server error while retaining ownership checks.

GitHub outages no longer interrupt authenticated API use

Hosted APIs now keep a successfully validated GitHub identity during temporary GitHub outages while continuing to enforce their current access list. An explicit credential rejection still clears the identity.

Managed Kubernetes clusters now own workload placement

Hosted APIs with managed control planes can now operate fixed-capacity Kubernetes clusters on AWS, Azure, and GCP. Jobs and Services target a Ready cluster with --cluster, and their placement survives API restarts. AWS users should enable the anycloud_resource cost-allocation tag for settled costs.

0.1.59

VM digests no longer repeat terminal counts

Daily Slack digests now list VM terminal outcomes directly, without a redundant ended total. Jobs and Services keep their ended totals because they can finish in several ways.

Unpinned regions are ranked globally by price

When --region is omitted, Anycloud ranks eligible regions globally by catalog price instead of preferring US regions. Explicit region selection, failure-driven rotation, and curated quota-request regions are unchanged.

High is the default root disk tier

high is now the default --disk-tier on AWS, GCP, and Azure; pass medium for standard performance. On AWS, Anycloud also prevents high-performance root disks from being smaller than the selected AMI.

GCP disk tiers no longer gate the VM catalog

GCP now resolves disk tiers when building the VM, allowing newly published machine families through the catalog. Hyperdisk-only machines use Hyperdisk Balanced; other families use pd-ssd for fast tiers, with incompatible fallback targets removed before selection.

Slack notifications identify their source API

Slack notifications now identify their source API. Local APIs show the account, host, and non-default port; hosted APIs show their stable hostname and GitHub owner, making shared-channel alerts distinguishable.

anycloud login no longer reports a browser failure on every sign-in

anycloud login now shows the manual URL message only when opening the browser fails, and no longer crashes on hosts without a browser handler.

Slack setup now starts from the CLI

anycloud notifications connect slack now opens Slack setup and securely prompts for the channel webhook. The callback offers a copy button, while notifications enable slack --webhook remains available for automation.

Release update notifications remain deduplicated on Linux

Linux APIs now track successful release notifications separately from the host-shared version cache, preventing CLI refreshes from making Slack receive the same release twice.

Hosted APIs can be shared with a team

anycloud api access add, remove, and list share hosted APIs with individual GitHub users. Members are equal peers who can manage shared workloads and resources; list, cost, and spend alerts attribute activity by user. Removing access blocks future requests without stopping existing workloads.

Slack notifications group large numbers

Daily usage digests and spend-cap alerts now add thousands separators to currency, workload counts, VM attempts, and aggregate durations, making busy accounts easier to scan in Slack.

Hosted API ownership uses durable GitHub account IDs

Hosted APIs, new deployments, and quota operations now authorize with immutable GitHub account IDs, so username changes do not break access. Existing records without an account ID continue using their captured username and may become unreachable after a rename.

VM creation uses the direct workload syntax

anycloud vm [image] now creates a persistent VM directly, matching Job and Service syntax. Omitting the image opens the GHCR picker in interactive terminals; anycloud vm new has been removed.

Service is the canonical long-running workload name

Service is now the canonical name across the CLI, docs, notifications, and Python SDK. anycloud serve, Python's deprecated Server alias, stored server values, and --type server remain compatible. A new workload guide compares Jobs, Services, VMs, and Buckets.

Python Git repository sync removed

The Python SDK no longer clones Git repositories or exports function, serve, Function, ServiceFunction, or ServeFunction. Package code in an image, then use Client.submit(), submit_many(), get_or_submit(), or serve() with an explicit command.

AWS and Azure generated credentials are ready on first use

Generated AWS and Azure credentials now authenticate and verify required storage and role access before saving. Azure Blob operations use a current ARM account key, while workload VMs retain scoped Entra permissions; disabled Shared Key access produces an actionable error.

0.1.58

Cost reports cover the complete reporting window

anycloud cost now handles reporting windows with more than 1,000 deployments by aggregating in SQLite. Exact deployment lookups and the 1,000-row limits for anycloud list and pickers are unchanged.

Persistent VMs

anycloud vm new <image> creates a persistent, SSH-only VM on AWS, Azure, GCP, Lambda, or Vast. The container and host share /workspace; use anycloud ssh <id> for the container or --host for the host. VMs reject spot, buckets, startup commands, custom Docker options, resubmit, and snapshots.

Compute credentials no longer switch accounts automatically

Remote deployments now choose one compute credential before submission and keep it for their lifetime. The CLI selects the only saved credential, prompts when several exist, and requires an explicit non-interactive choice. Region and target failover stay within that account; supported spot Jobs reuse it for checkpoint storage.

Docker runtime options fail before provisioning

Docker option names and values are now validated before cloud resources are created, including GPU compatibility and bucket-mount conflicts. Fallback pools skip incompatible VMs. Kubernetes Jobs and Services translate GPU and shared-memory options and reject unsupported options.

Kubernetes Jobs now use native batch workloads

Kubernetes Jobs now use native batch/v1 workloads, exposing real scheduling and exit state while retaining Anycloud retries, logs, exec, and cleanup. Images without commands preserve their ENTRYPOINT and CMD. GPU, shared memory, registry authentication, and buckets remain supported; bucket Jobs still require a command.

Local Docker execution is no longer a public feature

The Job and Server --local flag and API --enable-local-docker option have been removed. Local API containers no longer mount the host Docker socket or run the Docker-control stack.

api update follows the local-to-hosted control chain

anycloud api update now updates or starts the local API first, then replaces the active hosted API's backing VM through that local manager. It preserves the hosted URL, retained state, active selection, and any custom local API port; deployment IDs are no longer accepted.

Terminal outcomes stay visible while resources are released

Jobs and Servers now keep their terminal outcome visible while provider cleanup runs. Status JSON separates completedAt from cleanedAt, cost continues through each VM's actual lifetime, and resubmission waits for cleanup to finish.

Generated Google Cloud credentials are ready before use

Generated GCP credentials now wait for the new key to propagate and prove project access before saving. New controller accounts use specific compute, security, and storage roles instead of project-wide Editor, with Service Account User limited to the default Compute service account.

Large input buckets can finish hydrating before startup

Input-bucket hydration no longer has a fixed 14-minute limit. Healthy rclone transfers can run as long as needed, a 15-minute silence watchdog stops stalled work, and API restarts reattach to active VM-side synchronization instead of restarting it.

Lambda cleanup waits for actual instance termination

Lambda VMs now remain in teardown until Lambda confirms termination or no longer finds the instance, avoiding premature cleanup while the VM may still be billable.

Vast workloads now run on KVM hosts

Vast workloads now run on Ubuntu KVM hosts through Anycloud's standard Docker path, supporting commandless images, secrets, shell access, logs, and bucket sync. They require 130 GB of disk. Existing Vast deployments are not migrated; terminate and resubmit them after upgrading.

0.1.57

Google Cloud GPU retries now use exact zones

Region-pinned GCP deployments now select an exact compatible zone and rotate zones after capacity failures. Explicit targets refresh the catalog once before rejection. Each attempt retains its zone, and status or cleanup can find historical VMs even when the current catalog no longer lists their placement.

Google Cloud root disk tiers

--disk-tier medium, high, and ultra now work on GCP. Compatible machines use pd-ssd or Hyperdisk Balanced, with high-performance defaults for IOPS, throughput, and size. Invalid sizes and unqualified machine families fail before provisioning.

Jobs always release their VM when they finish

Jobs now always release their VM after completing or failing, following final bucket sync. The --persist flag and prompt are removed, including for older retained Jobs after upgrade. Resubmission waits for cleanup; use a persistent VM instead of a finished Job for shell access.

Slack release notifications now contain a short update prompt and link to the public GitHub release, keeping the full notes in one place and allowing Slack previews.

Ctrl-C stops the remote command it was running

Pressing Ctrl-C during anycloud logs --follow or anycloud exec now stops the corresponding remote command instead of leaving it running on the VM.

Bucket downloads detect and retry incomplete files

CLI and Python bucket downloads now validate received byte counts, retry incomplete transfers twice, and atomically replace destination files only after success. The API preserves object size through X-Anycloud-Object-Size when intermediaries remove Content-Length; replacement files retain their permissions.

0.1.56

Server upgrades no longer drop the public URL

anycloud service upgrade and anycloud api update move a server's public URL onto its replacement machine. That handover used to remove the URL before re-publishing it, so requests arriving in the gap failed to resolve. The URL is now moved in place and keeps answering for the whole upgrade.

Automatic spot checkpoint buckets are always cleaned up

The --persist-bucket Job option has been removed. Automatic checkpoint buckets still preserve a spot Job across preemptions, but AnyCloud now deletes them when the Job finishes. To retain checkpoint state across separate Jobs, create a bucket first and pass it with --checkpoint-bucket; explicitly named checkpoint buckets remain user-owned and are never deleted by AnyCloud.

Live logs now appear promptly for Python deployments

anycloud logs --watch could show no output for a running Python deployment because Python buffered stdout when no terminal was attached. Python output is now unbuffered by default; set PYTHONUNBUFFERED="" to opt out.

NVIDIA RTX PRO 6000 on Google Cloud

anycloud gpus gcp now lists RTX PRO 6000, and --gpu-type rtxpro6000 (or rtxpro6000:2, :4, :8) launches it on the matching whole-GPU machine. Google Cloud GPU machines now also request the boot disk and network interface their hardware requires, and the Google Cloud GPU listing is rebuilt from Google's own machine data. Newly released GPU families are detected and held from publication until their launch path is explicitly qualified.

New releases post their changelog to Slack

When Slack notifications are configured, the Anycloud API now checks for a new public release at startup and hourly. If an update is available, it posts that version's full changelog and the anycloud update command once. Successful delivery is recorded in the existing version cache, so API restarts do not repeat the same release; failed webhook posts retry on a later check.

anycloud cost <id> works for older deployments

anycloud cost <deployment-id> reported "not found" for a deployment that finished more than 24 hours ago. It now looks the deployment up directly and reports its full lifetime cost, regardless of age. Aggregate reports with --period are unchanged.

Bucket discovery across AWS, GCP, and Azure

anycloud bucket list now enumerates every natively discoverable bucket for a saved AWS, GCP, or Azure credential, with sorted table and compact JSON output. The authenticated GET /v1/bucket/list API preserves provider pagination with opaque cursors, and the Python SDK adds Client.list_buckets() plus bucket name, nullable region, and nullable created_at metadata. Listings default to 1,000 results; --all or limit=None exhausts all pages.

Azure discovery reads containers from Anycloud's deterministic storage account without creating missing infrastructure. Discovery is provider-native and does not filter out customer-created resources that lack Anycloud tags.

Bucket object and prefix browsing

anycloud bucket list <bucket> [prefix] now browses one slash-delimited level of files and virtual folders, while --recursive returns a flat object tree. The new authenticated GET /v1/bucket/objects API and Bucket.list_objects() Python method expose provider-native pagination and nullable size and modification metadata. Prefixes are passed literally, and complete CLI and SDK results are sorted by key.

Recursive bucket directory operations

anycloud bucket upload, download, and rm now accept --recursive for complete directory or prefix operations. They preflight deterministic manifests, use bounded configurable concurrency, reject unsafe filesystem mappings, attempt every object after partial failures, and preserve existing single-object behavior. Recursive deletion requires confirmation or --yes and cannot target an empty prefix.

The Python SDK adds Bucket.upload_directory(), download_directory(), delete(), and delete_prefix(). Recursive methods return BucketOperationResult; partial failures raise BucketOperationError with the partial summary and ordered per-key exceptions. These clients compose the existing authenticated listing and single-object APIs, so no new server route or provider bulk capability is required.

Hosted APIs can be updated from the CLI

anycloud api update [id] now upgrades a hosted API to the image matching the installed CLI while preserving its public URL and retained checkpoint state. The command runs through the API that manages the hosted deployment, supports an interactive picker, and can negotiate an older controller version so the upgrade path remains available after the CLI moves forward.

Daily Slack digests break down usage by user

Daily Slack digests now give each contributing Anycloud user a separate section with their Jobs, Servers, VM usage, compute spend, outcomes, and median Job duration. The host-wide compute-spend total remains at the top of the message, and structured Slack lists keep outcome details reliably nested across clients.

Clearer names for the deploy commands

anycloud submit is now anycloud job, and anycloud serve is now anycloud service. The old names keep working: submit and run are aliases for job, and serve is an alias for service.

0.1.55

Hosted API state stays private after a restore

A hosted API keeps its database and encryption key in its state bucket. Object storage does not carry file permissions, so after the backing VM was replaced or restarted those files were restored readable by other accounts on the VM. The restored state directory and key are now returned to owner-only access, and the state mount is created owner-only before the restore runs. Checkpoint mounts for ordinary Jobs and Servers are unchanged, so images that run as a non-root user can still read their own checkpoint.

Checkpoint buckets preserve VM-backed Server state

Jobs and VM-backed Servers can now attach a pre-existing, user-owned bucket at /mnt/checkpoint, independently of spot. Anycloud restores it before startup, uploads changes periodically, and never creates or deletes an explicitly named checkpoint bucket. The existing automatic deployment-named bucket for spot Jobs is unchanged.

Server replacement and termination now stop the workload, stop continuous sync, and complete a final checkpoint upload before removing the VM. Replacement still has downtime while a new VM starts; if the final upload fails, cleanup retains the old VM for retry rather than proceeding with stale state. Kubernetes-backed Servers reject checkpoint buckets in this phase.

anycloud api serve now requires a pre-existing, user-owned checkpoint bucket and stores its SQLite database and cipher key in /mnt/checkpoint, preserving its deployment ledger across backing-VM replacement. Hosted API creation, upgrade, and termination validate that stored bucket before mutation; Anycloud never creates or deletes it. Hosted API deployments created before this release are not migrated and must be redeployed with anycloud api serve.

0.1.54

API updates bound local Docker image storage

After a local API update succeeds, anycloud now keeps the current API image and one previous version for rollback while removing older versioned AnyCloud API images. Cleanup is limited to canonical version tags in the AnyCloud API image repository, never uses forced or Docker-wide pruning, and cannot fail an otherwise successful update.

Throttle alerts show the rate they actually compare

Spend-cap block reasons and Slack alerts now report the projected hourly rate, including the queued deployment, instead of showing only the current live rate. This keeps the displayed rate consistent with the throttle decision.

GitHub tokens no longer appear in Docker launch commands

VM and Local Docker workloads now deliver the authenticated GitHub token through a root-only, memory-backed secret env-file instead of embedding it in a docker run -e argument. Secret contents travel over SSH stdin rather than inside a retry-logged command, and Local Docker control containers use a dedicated tmpfs for the staging directory. Workload code still receives GITHUB_TOKEN, so private repository cloning and existing integrations continue to work.

Daily digest separates jobs from servers

The daily notifications digest now reports jobs and servers as separate sections, each with its own compute spend and VM usage, so it's clear which kind of workload drove the day's bill. Lines with a zero count are omitted instead of padding the message with zeros.

0.1.53

Queued deployments now share provisioning slots across credentials

A large backlog pinned to one credential no longer takes every available provisioning slot before another credential gets a turn. Queued deployments are scheduled in FIFO lanes per credential, with less-busy lanes considered first; deployments that choose credentials automatically share one lane. A single lane can still use the full global provisioning limit when no other lane has work.

Provisioning retries now use one state-based retry curve instead of separate admission gates and diagnosis-specific cooldowns. Failure history retains the selected credential and quota scope, so a regional AWS or Azure Spot quota failure slows retries for the affected credential and region without penalizing another healthy credential.

Serve can run on a fixed Kubernetes cluster

Opt-in Serve deployments can now run on one pre-existing Kubernetes cluster. AnyCloud creates a one-replica workload and stable internal service, waits for the workload to become ready, and handles replacement and termination through the Kubernetes runtime. This first phase does not publish a public URL.

Job logs are saved to your output bucket

Previously, a job's container logs were only available while its instance was running. Now, when a job runs with an output bucket, AnyCloud copies the workload container's logs — everything it writes to standard output and standard error — into that bucket alongside your other output. Because the logs live in your bucket, you can review or search a completed run's logs long after its instance has been terminated.

Slack digests report compute spend when it was incurred

The daily Slack usage digest now counts every provisioned VM that overlapped the UTC reporting day, including long-running deployments that finished later. Multi-day VM costs are prorated into each day instead of being charged entirely to the day the deployment ended. VM usage, initial submissions, resubmissions, and deployments ended are reported separately so canceled or invalid deployments are not mistaken for billed instances. The digest lists every user whose activity contributed to the host-wide totals and makes clear that preemption is measured over the full run of deployments that ended that day.

Kubernetes provider configuration is automatic

The Kubernetes provider now discovers its cluster from the in-cluster service account or the standard local kubeconfig instead of AnyCloud-specific environment variables. Namespace, SSH protocol, routing, and pull-policy settings are now deterministic runtime defaults. The SSH sidecar image remains the only temporary provider-specific environment override.

0.1.52

Azure spot uses the spot quota pool only

Azure gates spot VMs by a single regional spot vCPU quota that is separate from the per-VM-family quota gating on-demand VMs. anycloud previously required the on-demand family quota for spot as well: candidate regions with spot quota but no family quota were skipped, and anycloud quota request --spot filed a family increase that spot deployments never needed. Spot candidate regions are now gated by the regional spot quota alone, and --spot requests only that quota — the one Azure typically auto-approves. anycloud quota request selections that resolve to the same Azure quota — several spot types in one region, or same-family sizes — are combined into a single request sized for the largest need. anycloud quota status --spot likewise shows only the quotas that gate spot; VM-family rows — current limits and previously filed requests — appear under the on-demand view.

Quota increases now happen only when requested

The background quota monitor no longer files AWS or Azure quota increases or posts follow-up messages on old support cases by itself. Quota changes now come from an explicit anycloud quota request, so operators stay in control of every provider-side request. Explicit requests still work, but requested limits now add one VM of headroom instead of doubling the current limit, Azure skips writes when the current limit already has enough capacity, and reruns that find an existing support ticket report it without posting another communication.

Stopped local API servers stay stopped during update

anycloud api stop now cancels pending restart state, so a later anycloud update no longer relaunches a local API server that was deliberately stopped. When an update does need to replace a running local API server, restart recovery state is written after the internal stop step so failures still leave a clear retry path.

0.1.51

GPU images now use one full-pull delivery path

eStargz lazy loading has been removed. Every image now follows the normal OCI full-pull path, and status no longer shows lazy-loading labels. Images published with eStargz metadata still work as ordinary OCI images and are pulled by their normal pinned linux/amd64 digest.

On capable GPU VM images, containerd concurrent range transfer is now the default: several parts of one large layer can download at once. The optimization is automatic, model-agnostic, and requires no image changes or submit options. Unsupported runtimes, unsafe host configuration, registry throttling, or a failed transfer fall back to the normal Docker pull.

Base VM images moved to Ubuntu 24.04

anycloud now provisions machines on Ubuntu 24.04 (Noble) instead of 22.04. Every CPU base image across AWS, Azure, and GCP moves to 24.04, as do the AWS and GCP GPU images — GCP GPU hosts also pick up CUDA 12.9 with the NVIDIA 580 driver. This is a transparent infrastructure change that brings a newer kernel and system libraries to the machine your container runs on; most workloads need no changes.

0.1.50

Disk tiers now work on Azure

--disk-tier (medium/high/ultra) now works on Azure in addition to AWS. On Azure, high and ultra provision a Premium SSD root disk while medium (the default) keeps Standard storage; ultra behaves the same as high, since Premium is Azure's fastest root-disk tier. Premium tiers require a Premium-capable VM size, which most modern GPU instances are.

GPU jobs retry a not-ready host instead of failing

When a GPU machine's NVLink fabric hasn't finished initializing, a job can crash at startup with CUDA error 802 ("system not yet initialized") before your code runs. anycloud now treats this as a problem with the machine rather than a fault in your container, and retries the job on a fresh machine — which almost always clears it. It most often shows up on multi-GPU machines such as H100 pairs.

Lambda deployments reach newer regions and fall back across instance types

Lambda GPU deployments can now use regions that Lambda offers but that weren't yet in anycloud's catalog (for example us-southeast-1) — anycloud now reads Lambda's own catalog directly instead of a slower third-party snapshot, so newly available regions show up within hours. A GPU request such as H100:1 also falls back across equivalent instance types automatically, so a deployment lands on whichever is available instead of failing on the cheaper one.

Modern Lambda GPU instances now explicitly select the rolling Lambda Stack 24.04 image family, letting Lambda resolve its newest compatible build in each region. V100 instances remain on Lambda Stack Legacy 22.04, which supplies the closed-source NVIDIA driver that hardware requires.

0.1.49

Large images start sooner with SOCI v2

Large GPU and machine-learning images can spend most of their launch time just downloading. If your image is pushed to GHCR in SOCI v2 format, anycloud can start it lazily where the runtime supports it: the container runs while its layers are fetched on demand, so it doesn't wait for the whole image to download first. anycloud status marks the running event [lazy-loaded] when this happens, or [full pull] otherwise. Small or ordinary images pull as before.

Azure bucket sync data now avoids temporary VM storage

Azure VM-host deployments now place host-side input, output, and checkpoint bucket directories under /var/lib/anycloud/deployments on the managed OS disk instead of Azure's temporary /mnt resource disk, so bucket data survives VM deallocation during in-place spot recovery. Other providers keep the existing /mnt layout. The host paths are stored per VM so already-running deployments keep their original bucket directories after an API upgrade.

Region-pinned deployments retry capacity sooner

When a cloud reports insufficient capacity for an explicitly pinned region, anycloud schedules another launch attempt after about one minute instead of waiting behind the shared ten-minute capacity observation. Unpinned deployments keep the longer observation window so they can fail over without repeatedly probing an exhausted target, and regional and account quota protections remain unchanged. While waiting, anycloud status confirms that an automatic capacity retry is scheduled.

Lambda launch retries clean up duplicate instances

Lambda deployments now tag launched instances and sweep stale same-deployment instances around launch retries. This prevents duplicate or orphaned Lambda instances when the provider accepts a launch request but the client only sees a transient failure.

anycloud cost includes long-running servers

Cost reports now keep active servers in the selected reporting window even when those servers started before it. Human-readable summaries and provider / agent tables distinguish jobs from servers, while their compute duration and cost are included in the same totals. JSON reports add totalServers and a servers count to each provider and agent bucket; single-deployment JSON now includes deploymentType. Reporting periods are limited to 1–90 days, and the API rejects reports matching more than 1,000 deployments instead of running an unbounded read or returning a partial total.

Workload image baking has been removed

Jobs and servers now always boot from a provider base VM and pull the resolved Docker image. The CLI and Python SDK no longer expose workload-image baking, cache reuse, or image warm-up controls, and status no longer includes a baking lifecycle phase. The entire anycloud baked command group, including its list, copy, and prune operations, has also been removed. Earlier changelog entries below describe the behavior of those historical releases.

Existing baked workload AMIs and their snapshots are not automatically discovered or deleted by this release. They remain in the owning cloud account until an account owner removes them with provider-native tooling; generic AnyCloud base/runtime images must be retained.

0.1.48

Preempted spot deployments no longer stay falsely running

If the API restarted while a cloud provider was bringing a preempted VM back online, the deployment could remain recorded as running even though its only VM was already recorded as preempted. Those stale deployments then appeared in anycloud list and anycloud terminate indefinitely. Recovery is now committed before waiting on the cloud restart, interrupted attempts resume through the normal recovery queue, and upgraded API servers automatically repair existing running deployments whose live VM records are all preempted.

Failing bucket syncs back off between retries

When a continuous output or checkpoint sync failed (expired storage token, revoked bucket access, network trouble), it retried immediately in a tight loop instead of waiting for the normal sync interval — hammering the storage API and burning VM CPU next to the workload until the problem cleared. Failed attempts now wait the same interval as successful ones. Applies to deployments launched after this release; already-running VMs keep the sync script they launched with.

Bucket sync health now comes from rclone's own errors

anycloud status derived bucket-sync health by keyword-matching service logs, so a harmless systemd warning could make a healthy output sync render as failed — both live and in a past deployment's event history. Sync health is now read from the rclone log itself and only rclone's explicit errors count as sync failures; the harmless warning is also stripped when showing older deployments' history.

Clearer terminal status for jobs with output buckets

Terminal events now show the final output sync result separately from the workload's own exit code (e.g. errored [exit: 137] [final sync: succeeded, attempt: 1]), a stopped sync service now shows as stopped instead of disappearing from status entirely, and sync diagnostics are no longer duplicated into termination events.

0.1.47

anycloud update actually restarts the local API server again

Since 0.1.46, anycloud update silently failed to restart a running local API container onto the new version: it printed the target version and exited as if it had succeeded, but the container was left on its old image. anycloud update now restarts it correctly. If a local API server has been stuck on an old version, run anycloud update again after upgrading.

Cross-cloud input buckets no longer get stuck in syncing

Deployments with a cross-cloud input bucket (e.g. compute on one provider, an S3 input bucket on another) could get stuck retrying in syncing indefinitely. The pre-sync connectivity check now verifies read access for input buckets instead of attempting a write, matching the read-only credentials those buckets are already granted.

0.1.46

Bake-hit boots wait for the warm-up, and it targets the right files

On a cache-hit boot from a baked image, the container now waits (up to 60 seconds) for the boot-time page-cache warm-up to finish before starting, so the workload's first reads land warm instead of racing an in-progress warm-up. The warm-up itself also skips large files a running container never actually reads — copies and caches left over from pulling and building the image, along with libraries the image ships but doesn't use at runtime — so its limited time budget goes to the files that matter. Re-bake existing images to pick up both changes.

0.1.45

Faster initialization on baked-image boots

VM initialization now confirms Docker readiness through the init system's native ready signal instead of repeatedly querying the daemon, reaches new VMs with a connection-level probe before attempting SSH logins, and the boot-time warm-up reads the container runtime's bookkeeping first. Together these decouple initialization from the background warm-up: multi-minute initialization on large baked images drops to under a minute. The readiness and connection improvements apply to all deployments immediately; re-bake to pick up the warm-up ordering change.

0.1.44

Boot-stable warm-up for large baked images

The boot-time warm-up introduced in 0.1.42 now reads boot-critical files first and large image data last, reducing contention with VM startup. For large images, pair --bake with --disk-tier high: baked-image boots are fastest there and model loads start warm. On the default disk tier, booting very large baked images can still delay or retry provisioning — prefer a normal pull (--no-bake-cache) or the high tier for those. Re-bake existing images to pick up the new warm-up ordering.

Target selection

When the interactive submit and serve VM picker can't fetch quota limits in time, it now says so and shows the full catalog, instead of silently dropping the quota-aware ranking. Quota lookups are also cached longer, so repeat picks and anycloud quota status checks return faster.

0.1.43

Baked-image warm-up now covers GPU base images

The boot-time warm-up introduced in 0.1.42 read only Docker's classic storage directory. GPU base images store cached layers through Docker's containerd image store, which keeps its data in a separate location — so GPU-family bake hits warmed almost nothing and still started cold. The warm-up now reads both storage locations. Re-bake existing images to pick up the fix; the bake e2e suite now also verifies that the warm-up did proportional work on a live bake-hit VM.

0.1.42

Faster container starts on baked-image cache hits

VMs booted from a baked image now read the cached Docker image into memory in the background at boot, restoring the warm state a fresh Docker pull leaves behind. Large images (model weights, CUDA libraries) previously paid cold-disk reads on first access, which could make a cache-hit start slower than a fresh pull. Applies to images baked from this version onward; older baked images start cold until re-baked.

AWS disk tiers

anycloud submit, anycloud serve, cloud config, and the Python SDK now support an AWS diskTier / --disk-tier option for choosing gp3 root-volume performance independently from root disk capacity. The initial tiers are medium, high, and ultra.

On baked-image cache hits, high and ultra also request the fastest supported EBS volume initialization rate for the root volume. Workloads that still start faster with a normal Docker pull should use --no-bake-cache; disk tiers are a root-disk performance knob, not a guarantee that prebaked AMIs beat registry pulls.

gp3 root volumes by default

AWS deployments now always launch with a gp3 root volume. Previously, deployments that did not set a disk size or disk tier could fall back to the base image's gp2 default, which is slower — especially at small disk sizes — and 25% more expensive per GB.

Baked-image cache opt-out

anycloud submit, anycloud serve, anycloud serve upgrade, and the Python SDK now support a no-bake-cache option for runs that should force a normal base VM boot and Docker pull even when a matching baked image exists. It can be combined with legacy --bake to pull normally and refresh the baked image after the pull.

Release hardening

Unit test runtime was reduced for status and Azure gateway coverage, keeping the release validation path faster without reducing behavioral checks.

0.1.40

AWS baked-image startup reliability

AWS bake-hit launches now request a bounded EBS volume initialization rate for the root volume, reducing unpredictable snapshot lazy-load latency when booting from prebaked AMIs. If AWS rejects that optimization because of regional quota or capacity pressure, provisioning retries without it instead of failing the deployment.

The AWS serve-bake integration test now verifies that bake-hit VMs launch from the baked image and request the bounded initialization rate while the instance is still live.

Local Kubernetes release hardening

The local Kubernetes provider contract now uses a Never pull policy for the locally built SSH sidecar image after importing it into k3d, preventing CI from falling back to Docker Hub for a test-only image tag.

0.1.39

Bake reliability

Explicit bake now flushes Docker filesystem state before snapshotting and records whether bake failures happened during flush or image creation. Failed bakes no longer fall through into workload execution, and same-tag baked images with different digests are kept until an explicit prune removes them.

Quota and status

anycloud quota status now prompts for spot or on-demand quota in interactive mode and supports explicit --spot / --on-demand filters while keeping JSON output script-friendly. Quota integration coverage now checks AWS and Azure provider parity against cloud API data.

Status telemetry is now throttled per user and deployment so watch and wait polling loops do not flood analytics.

Updates and release hardening

anycloud upgrade is now an alias for anycloud update, with clearer output when the CLI is current and there is no local API server to restart. Homebrew-managed installs now update through Homebrew from anycloud update; when Homebrew is already on its latest formula, the command still restarts a stale local API server to match the installed CLI.

Nightly bake e2e jobs have longer timeout headroom and stricter phase checks, so release-adjacent bake regressions surface before publishing.

0.1.38

Quota and status internals

Quota resource resolution now uses shared AWS and Azure resolvers, improving quota lookup consistency across provider gateways, API handlers, and the CLI.

Internal provider status domains now use enums across API and CLI paths, keeping status handling consistent as quota and deployment flows evolve.

0.1.37

Local Docker-control

AnyCloud can now run Local workloads through a Docker-control container on the API host, using the same workload path as VM deployments.

anycloud logs works for Local deployments, streaming through the API without exposing SSH material. Local missing-GPU failures now stop instead of retrying the same fixed host.

Serve upgrades

anycloud serve upgrade <id> <image> [command...] replaces a running serve deployment while preserving its existing https://<id>.anycloud.sh URL.

Target selection

The interactive submit and serve VM picker now shows quota-aware ranking and spot pricing while keeping region selection unpinned.

Image inspection now filters CUDA/ROCm-incompatible GPU fallback targets and rejects images whose compressed layers cannot fit on the selected disk.

Baked images and registries

Private GHCR manifest inspection now reports real auth failures for --bake instead of falling back to misleading digest errors.

anycloud baked list has shorter age formatting, more stable picker columns, and safer regional caching that avoids reusing partial scans.

Local API reliability

The CLI now discovers local API containers on non-default host ports. anycloud update checks /v1/version, verifies the target API image before stopping the old container, and can recover a failed restart on the next update.

Operational hardening

Catalog refresh falls back to usable cache when available. Lambda serve rotates away from regions without required firewall rulesets. Container startup health now catches unhealthy, restarting, and missing-GPU states before publishing endpoints.

0.1.36

Choose which API server the CLI talks to

The CLI now remembers a preferred API server, so you don't need to set API_URL on every command.

  • anycloud api use <url> saves a hosted API as the active server (stored in ~/.anycloud/api-url). Pass a deployment ID to pick one of your hosted APIs, local to return to http://localhost:8080, or run it with no argument for an interactive picker of healthy, compatible servers.
  • anycloud api list shows your local and hosted API servers with their health, version, and which one is active. --json emits the same data for scripting.
  • anycloud api info shows the active server, where the setting came from, and whether its version matches your CLI.
  • anycloud api serve --use makes a newly created hosted API active once it's healthy.

API_URL still works as a one-command override and takes precedence over the saved setting.

CLI and API versions must match

The CLI and the API server it talks to must now be the same version. If they differ, commands fail fast with a clear message — run anycloud update for a local API, or anycloud api list then anycloud api use <target> to switch to a matching server.

anycloud logs for VM-host deployments

anycloud logs [id] prints workload container stdout/stderr logs for VM-host deployments, and anycloud logs [id] --watch streams them. At this release, the then-current container-mode Vast integration was reported as unsupported.

anycloud list distinguishes jobs and servers

anycloud list now includes a TYPE column and a type-aware summary, so mixed job/server history is easier to scan. Use anycloud list --type job or anycloud list --type server to filter. --json includes deploymentType, and --csv keeps the existing columns in order while appending deploymentType as the final column.

Credential prompts are more consistent

Commands that need saved credentials now share the same resolver behavior: one eligible credential is selected automatically, multiple eligible credentials open the same autocomplete picker on a TTY, and non-interactive runs fail with a message naming the flag to pass.

Bare interactive anycloud submit, anycloud serve, and anycloud api serve now prompt for saved credentials before opening the compute target picker, then pin the selected credential on the deployment. Bucket commands can also omit --credentials in interactive flows and still send the resolved credential name to the bucket API.

anycloud baked list uses the same credential selection behavior. Its default table now includes a Cloud column, while both --by-region and --json remain available.

0.1.35

anycloud baked manages baked VM images

A new anycloud baked command group manages the prebaked VM images that --bake creates:

  • anycloud baked list shows the baked images discovered in a selected named credential/account, grouped by the container image they were baked from.
  • anycloud baked copy (AWS) copies a baked image to other regions so deployments there boot warm without re-baking. Copies are idempotent, and --wait blocks until each copy is ready.
  • anycloud baked prune removes baked images you no longer need from a selected named credential/account, with --unused-for to keep recently-used ones and --region, --image, and --digest filters to scope the sweep. This replaces anycloud images prune.

anycloud list filters by credential

anycloud list --provider <cloud> has been removed. Use anycloud list --credential <name> to narrow deployment history to a specific saved credential. The filter matches both deployments pinned to that credential and unpinned deployments whose VMs were later provisioned with it.

Quota commands require an explicit credential

anycloud quota request and anycloud quota status now operate against one named credential at a time. Interactive runs still pick or auto-select a matching credential, but scripted runs should pass --credential <name> so quota reads and requests cannot accidentally scan the wrong cloud account.

anycloud status --verbose shows VM diagnostics

anycloud status --verbose now includes container exit details, container logs, and bucket-sync diagnostics when a VM health check finds a problem. The default status view stays concise and points you to --verbose when logs are available. Read-only status checks also no longer append noisy same-state deployment events or API log errors just because a user inspected a deployment.

Clearer GPU runtime handling

AnyCloud now resolves the runtime a GPU VM needs as CUDA, ROCm, or unsupported. NVIDIA CUDA VM-host targets still default Docker GPU access to --gpus all, but AMD/ROCm and other unsupported accelerator targets now fail clearly instead of silently booting a CUDA base image. The GPU docs were updated to match the automatic GPU access behavior.

Hosted API owner checks run before lookups

Hosted API requests now enforce the owner policy before named credential, secret, catalog, or image lookups. Denied callers receive the authorization failure without being able to probe saved server state first.

0.1.34

Local API Docker access is opt-in

anycloud api start binds the API port to 127.0.0.1 and mounts the host Docker socket only when explicitly started with --enable-local-docker. To run anycloud submit --local, restart the local API with anycloud api start --enable-local-docker; that opt-in is preserved by anycloud update.

anycloud ssh restored

anycloud ssh <id> is available again for VM-host jobs and servers. It opens an interactive shell in the workload container by default, with --vm for host VM diagnostics and --snapshot for exited-container inspection. SSH keys are not returned from status; the CLI requests explicit, audited SSH access from the API when the command runs.

Configurable anycloud serve listen port

Server deployments still default to PORT=8088, but you can now override it with --env PORT=<port> (CLI) or env={"PORT": "<port>"} (Python SDK). The public URL and HTTPS routing are unchanged.

anycloud serve always runs servers on-demand

Server deployments (anycloud serve and anycloud api serve) no longer ask you to choose between on-demand and spot pricing when you pick a spot-capable VM type — they always run on-demand, so picking a target is one fewer prompt. Passing --spot to a server deployment is now rejected with a clear error instead of being applied.

Interactive target picker shows disk sizes

When you pick a compute target interactively for anycloud submit or anycloud serve, each option now lists the instance's local disk size alongside its vCPU, memory, and price. The picker aligns every option into stable columns, so machine type, compute, CPU, memory, disk, and rate line up down the list and are easier to scan and compare.

anycloud status shows spot and disk size

anycloud status now lists the spot setting and disk size as their own rows in a deployment's summary. Previously a spot deployment was only hinted at by a small marker next to the VM type, and the disk size was not shown at all — so you can now confirm both choices without digging through your deploy configuration.

anycloud status shows why an image pull failed

When a VM-side Docker image pull fails, anycloud status now surfaces the underlying Docker daemon output — for example manifest unknown, or an authentication or disk-space error — in a "Docker output" block beneath the concise failure line, instead of a bare "Failed to pull image". This applies to both remote-VM and direct pulls, and to failures recorded earlier, so you can tell why a pull failed without digging into the VM.

--bake accepts single-arch and digest-pinned amd64 images

anycloud submit --bake and anycloud serve --bake now work with more kinds of images. Previously --bake could only resolve a linux/amd64 digest from a multi-arch image; it now also handles plain single-manifest linux/amd64 images and images referenced by digest (image@sha256:...), inspecting the image's config to confirm it really targets linux/amd64 before baking. When an image genuinely has no linux/amd64 build, the rejection message is now clearer about what to do.

anycloud exec captures complete output more reliably

anycloud exec no longer drops trailing standard error: it waits for all buffered error output to flush before finishing, so the last lines of a failing command's diagnostics are reported instead of being cut off, and a slow output consumer no longer leaves the stream hanging. The Python SDK's Job.exec() now keeps streamed output as raw bytes and decodes it once at the end, so multibyte characters (emoji, accented or non-Latin text) that land on a chunk boundary are no longer corrupted.

Faster failures and cleaner failover for GPU and Lambda serve

A GPU deployment whose container image needs a newer driver than the host provides now fails fast with the underlying driver-mismatch message, instead of silently retrying the same doomed target until the launch budget runs out. On Lambda, hitting your account instance limit is now reported as a quota issue (so the CLI points you at anycloud quota) rather than rotating through regions that can't help, and tearing down a Lambda server that failed over across regions now removes the firewall rules it created in every region, not just the last one.

0.1.33

anycloud serve on Lambda

Server deployments can now run on Lambda, alongside AWS, GCP, and Azure, with the same public https://<id>.anycloud.sh URL and HTTPS routing as the other providers.

anycloud serve --bake

Server deployments can now opt into baked VM images. Serve uses the same server-resolved image digest as jobs, so a baked image created by a job can be reused by a server, and a baked image created by a server can be reused by a job when the image digest, cloud account, region, and base image family match.

Hosted API restricted to its owner

A hosted AnyCloud API (anycloud api serve) now serves only the account that deployed it and rejects requests from anyone else, instead of being reachable by any caller who has the URL.

0.1.32

anycloud api serve deploys a hosted AnyCloud API

Runs the AnyCloud API as a long-running server on your own cloud compute instead of locally, printing the public URL and API_URL once it's healthy (--no-wait to skip the wait). anycloud api start now refuses to start when a database exists without its key, instead of generating a mismatched one.

Python SDK get_or_submit() for restart-safe workflows

A restarted workflow step reattaches to the deployment it already submitted instead of duplicating it, using a stable ID derived from the workflow id, step name, and submission spec.

anycloud quota status shows new requests immediately

A request you just made with anycloud quota request now appears right away with its state, instead of disappearing until the provider's own history catches up.

anycloud serve origins locked to Cloudflare

Server HTTP ports are now firewalled to Cloudflare's edge ranges instead of open to the whole internet; existing servers are tightened on their next firewall reconcile.

anycloud serve deployments on Azure are reachable again

anycloud serve runs on any supported provider. On Azure specifically, some HTTP requests to a server's https://<id>.anycloud.sh URL could be dropped before reaching it, so the deployment looked unreachable even when healthy — now fixed for both IPv4 and IPv6.

GCP skips regions that can't see the requested machine type

Unpinned GCP deployments drop candidate regions where the requested machine type isn't visible before provisioning, so they fail over to a working region faster.

Azure terminations clean up leftover network resources more reliably

If an Azure termination fails partway through, the deployment's network interface and public IP are now marked for cleanup up front, so the next cleanup pass reclaims them rather than leaving them behind in your subscription.

0.1.31

CLI installs now use public release assets and Homebrew

The anycloud CLI now ships as platform tarballs in the public anycloud-sh/releases repo instead of through npm. The installer downloads the matching tarball and verifies it against checksums.txt before installing.

macOS and Linuxbrew users can install with brew install anycloud-sh/tap/anycloud and upgrade with brew upgrade anycloud-sh/tap/anycloud. anycloud update now checks GitHub Releases for newer versions and points Homebrew-managed installs back to Homebrew instead of overwriting them.

anycloud quota request GPU picker starts empty

The interactive anycloud quota request GPU picker no longer preselects curated GPU instance types. Curated options still appear first, but users now explicitly choose every GPU VM type they want to request.

anycloud status can watch a deployment until it finishes

anycloud status <id> --watch now polls and redraws the status view until the deployment reaches a terminal state. Use --interval <seconds> to adjust the poll cadence. For scripts, anycloud status <id> --watch --json emits one compact status object per line.

0.1.30

anycloud list gets a time window and a result limit; -a/--all is removed

anycloud list now shows your most recent deployments by default, newest first, instead of only the last 24 hours — so a bare anycloud list no longer comes up empty when your latest work is a few days old. Two new flags adjust the view, on both list and the status picker:

  • -p, --period <window> — only deployments started within a window, e.g. anycloud list -p 7d or -p 24h.
  • -n, --limit <count> — how many to show, newest first.

The -a, --all flag has been removed. To reach older deployments, widen the window with -p or raise the count with -n. Every list query is now bounded, so listing stays responsive on accounts with long histories.

The --status, --provider, and -f/--filter filters now search your full history rather than only the page being shown, so filtering for an older deployment no longer comes up empty when it falls outside the recent window.

anycloud cost --period all is removed

anycloud cost no longer accepts --period all. Cost is always computed over a recent window of deployments rather than your entire history, so "all-time" was misleading. Pass an explicit window instead — e.g. anycloud cost --period 90d (the default is still 30d).

Azure bucket sync no longer loses storage access after cleanup

On Azure, deployments in a subscription share a single identity that grants their VMs read/write access to bucket storage. Routine cleanup of orphaned resources could mistakenly remove that shared access, after which bucket sync failed with permission errors on every running and new deployment until the API was restarted. Cleanup now preserves the shared access grant, and each deployment restores it automatically if it is ever missing — so bucket sync recovers on its own.

Invalid cloud credentials are flagged instead of failing on every deployment

When a saved cloud credential starts failing authentication — for example after its secret is rotated or expires — anycloud now marks it invalid instead of retrying the same failing call on every deployment and cleanup pass. New work that would use it is skipped, and cleanup for affected deployments pauses (so it stops re-hitting the provider and flooding logs) until the credential is fixed. anycloud credentials list shows which credential is failing and since when, and with notifications enabled anycloud sends a one-time alert so a broken credential surfaces instead of failing silently. Re-entering a valid secret clears the flag; affected deployments can then be resubmitted.

0.1.29

anycloud list stays responsive on accounts with long histories

The list and cost commands now select the deployments to display first, then total their VM usage, cost, and latest status only for those — instead of aggregating across every deployment an account has ever created and trimming afterward. Accounts with thousands of past deployments no longer pay whole-history cost on each list. Results are unchanged except that deployments sharing an exact start time now sort in a stable order.

Cleanup fails fast on broken cloud credentials

When a cloud credential is rotated, expired, or missing required permissions, resource teardown now gives up immediately instead of retrying the same failing delete for several minutes, and Azure requests that would otherwise hang now time out. This clears stuck cleanup work sooner; a genuinely broken credential still needs to be corrected before its leftover resources can be removed.

API containers use vanilla Node memory defaults again

The API Docker image no longer starts through a shell entrypoint that auto-sizes V8 heap memory from the host or container memory limit. Local API containers now use Node.js's default memory behavior unless operators explicitly provide NODE_OPTIONS.

0.1.28

Large queued batches no longer overwhelm the API server

Before dispatching a queued deployment, the server checks cloud quota and availability across candidate regions. Each queued deployment used to run that check independently, so a deep queue of similar jobs could issue thousands of simultaneous cloud API calls every few seconds — enough to starve the server and slow every command. Identical checks are now shared: a batch of similar deployments performs one sweep together, and a failed sweep logs a single warning instead of flooding the logs. Region filtering behavior is unchanged.

0.1.27

Releases now ship as one forward-only public line

The release flow no longer has separate latest and stable channels. Each release publishes the matching API image before publishing public CLI assets, then publishes the Python SDK and agent skill from the same version-bump commit. This prevents an updated CLI from pointing at an API image that has not been published yet.

anycloud update now moves forward to the current public release and restarts a running local API server automatically. Version arguments, channel selectors, and --no-restart have been removed so CLI/API installs stay in lockstep. Local API databases also record the newest app version that touched them, and older API containers refuse to start against newer forward-migrated data.

0.1.26

More history reads are bounded to live work or explicit windows

The local API now adds indexes for the other recurring database reads that can grow with deployment history: live VM checks, spend windows, pending cost reconciliation, active-state monitors, and daily digest ranges. Retry and startup-recovery monitors now start from the small set of active deployments and probe their events, rather than grouping all historical events.

These changes keep full history in SQLite; they make the common reads pay for the live fleet or the requested time window instead of the lifetime size of the database. Slow SQLite queries are also logged, rate-limited, so future unbounded reads show up in API logs before they become outages.

0.1.25

The local API server restarts itself after crashes and reboots

anycloud api start now runs the server with Docker's unless-stopped restart policy: if the process crashes or the machine reboots, the API comes back on its own instead of staying down until someone notices — while jobs run unsupervised, a dead API means completed VMs keep billing. An explicit anycloud api stop still keeps it stopped.

Crashes also stay diagnosable now: the server's recent logs are saved to ~/.anycloud/api-last.log before the container is replaced or removed (they were previously destroyed with it), container logs rotate instead of growing without bound, and anycloud api status shows a restart count when the server has been crashing.

Deployment listings no longer include secrets

The deployment list API response included each deployment's decrypted SSH private key, environment variables, and GitHub token — none of which anycloud list ever displayed. Listings are now redacted. Flows that genuinely need the key, like anycloud exec, are unaffected: they fetch it through the single-deployment status endpoint.

The API server stays responsive with a large deployment history

A background check that runs every minute used to scan the server's entire deployment history; once that history reached hundreds of thousands of records (large, long-running fleets) it could stall the server for seconds at a time, slowing every command. The scan is now indexed — about 60× faster on a real customer database — so anycloud list and anycloud status stay snappy during big runs.

The API server uses your machine's memory instead of a fixed ~4GB cap

The server previously ran with Node.js's default heap ceiling (~4GB) no matter how much memory the machine had, which could crash it under heavy fleet load even on large machines. It now sizes its heap to 75% of available memory.

anycloud status separates billable time from wall-clock duration, and shows cost

The status header used to show a single Duration measured from submission to completion — including time spent queued or retrying before any VM existed. It now also shows Billable, the time VMs actually existed (summed across spot replacements) — the time your cloud charges you for — and a Cost row with the deployment's spend and hourly rate, marked "(est.)" while it's estimated from catalog prices rather than reconciled against your cloud bill. All three update live for running deployments.

0.1.24

Fixed: image validation no longer depends on local Docker

anycloud submit used to verify your image with a local Docker pull, which could wrongly reject a valid image on Apple Silicon Macs (a "no matching manifest for linux/arm64/v8" error) and depended on tools not present on a default macOS install. Image validation now happens server-side, so it behaves the same from the CLI, the Python SDK, and CI, and no longer needs Docker on your machine.

Clearer errors for bad images, before your job starts

Before provisioning, anycloud now checks your image and fails fast with an actionable message when it has no linux/amd64 build (anycloud VMs run x86_64 — with docker buildx build --platform linux/amd64 … --push guidance), doesn't exist, or isn't accessible — instead of failing partway through the deployment.

anycloud update restarts a running API server

If a local API server is running when you run anycloud update, it now offers to restart it on the new version (on the same port) so you pick up the update right away. At a terminal you're asked to confirm (default yes); in non-interactive contexts it restarts automatically. Previously you had to remember to run anycloud api stop and anycloud api start yourself, or the server kept serving the old version.

anycloud submit is now fully interactive

Running anycloud submit in a terminal without the cloud flags used to exit with a "Cloud config required" error. It now guides you through the whole job: it prompts for credentials (auto-selecting when you only have one), then for a compute type from a searchable list of your cloud's instances — GPU options first, then CPU instances labeled with vCPUs, memory, and price — and, when the instance supports it, whether to run on-demand or spot. Pass --credentials, --vm-type, --gpu-type, or --spot to skip the matching prompt.

Fixed: clearer error when requesting spot on a cloud that doesn't support it

Submitting a spot job to a provider without spot instances now returns a clear client error instead of a generic server error.

0.1.23

Fixed: slow failover when a region is out of capacity

When a region had no capacity for the requested instance type, a deployment could spend several minutes on each retry before trying another region. Deployments now fail over to the next region with availability promptly.

Fixed: deployments could get stuck while downloading the image

If the SSH connection dropped while the container image was being pulled, a deployment could wedge in the downloading state. Image pulls now run detached on the VM, so a dropped connection no longer stalls progress.

0.1.22

Fixed: CLI failed to start on fresh installs

A packaging bug in 0.1.21 caused the anycloud CLI to exit immediately on startup with a Cannot find module error. The CLI now starts normally. If you're on 0.1.21, reinstall with:

curl -fsSL https://get.anycloud.sh | bash

0.1.21

anycloud ssh and anycloud logs removed

The anycloud ssh and anycloud logs commands have been removed. Use anycloud exec <id> "<command>" to run a command in your job's execution environment, and anycloud status <id> --verbose for lifecycle, errors, and captured output. On providers that run your image directly as the workload, anycloud exec now runs your command in that environment rather than wrapping it in a container exec.

Vast spot (interruptible) instances

anycloud submit --spot now works on Vast. Spot runs bid on Vast's interruptible marketplace at the live offer price, and anycloud detects when an instance is reclaimed and reprovisions a fresh one to keep the job going.

Vast hosts have no storage of their own, so spot on Vast requires a checkpoint bucket on a cloud that does. Point it at storage credentials with the new flags:

anycloud submit my-image --spot
--checkpoint-storage-credentials my-aws
--checkpoint-storage-region us-east-1

Checkpoints your job writes sync to that bucket, so a reprovisioned instance restarts with them already in place. The bucket is named after the deployment and is removed when the deployment ends — keep it with --persist-bucket.

Vast also now appears in anycloud gpus and anycloud pricing, including the cross-cloud anycloud gpus --type comparison.

Bring your own Docker image

anycloud build, Client.build(), and the Python anycloud.Image builder API have been removed. Build and push Docker images locally or in CI, then submit the resulting image reference with anycloud submit or Client.submit(). See Container Images — Build and publish for local and GitHub Actions examples.

anycloud login now also attempts a best-effort local docker login ghcr.io when Docker is installed, using the same GitHub token, so GHCR pushes work without setting up a separate registry credential.

Explicit image baking and pruning

anycloud submit --bake and Client.submit(..., bake=True) now explicitly opt in to creating baked VM images. Normal submits can still reuse a matching baked image when one exists, but they no longer create new baked images by default. Use anycloud images prune to remove stale baked images from cloud accounts.

Stricter git source checks for @anycloud.function()

The Python function decorator now rejects dirty working trees and commits that are not pushed to origin before submission. Remote execution clones from GitHub at the submitted commit, so local-only changes cannot be reproduced on the VM.

Agent session labels use Claude Code titles

Agent-scoped CLI output now shows the readable Claude Code session title when one is available, instead of only showing the raw session identifier in list and spend-control views.

Interactive credential setup improvements

anycloud credentials new now better guides AWS and Azure setup from local CLI state, including browser login paths, profile selection, and clearer cleanup when deleting credentials.

anycloud quota request now raises Azure public-IP limits

Azure caps public IP addresses per subscription per region (100 by default), and every VM consumes one — so a fleet could stall on the IP cap even with plenty of vCPU quota. Two changes: anycloud quota request now files a public-IP increase alongside the vCPU request for each region, and hitting the public-IP cap is now treated as a quota error (the region backs off and the anycloud quota hint is shown) instead of being retried indefinitely.

Guided anycloud quota request picker

Running anycloud quota request with no arguments in a terminal now walks through credential → GPU quota target (choose specific types or all GPU families) → GPU instance type(s) when needed (searchable multi-select, with Ctrl-A to toggle all) → quota type(s) (on-demand, spot, or both) → region (or all regions), filing a request per selected type. Passing --spot or --region skips the matching prompt; explicit vmType/--gpu invocations and non-TTY/--json usage are unchanged.

0.1.20

Vast.ai provider support

Vast.ai is now available as a GPU marketplace provider. Add a Vast credential with anycloud credentials new, submit jobs against Vast GPU offers, and use the normal logs, exec, ssh, and bucket-sync flows through Vast's NAT'd SSH endpoints.

Config profiles removed in favor of inline flags

anycloud config and ANYCLOUD_CONFIG profiles have been removed. Pass submit settings directly with flags such as --credentials, --gpu-type, --vm-type, --region, and bucket options. Existing docs and tutorials now use inline submit flags.

anycloud images browses GHCR images

anycloud images now lists and filters images from GitHub Container Registry, with interactive selection in a TTY and --json / --only-refs output for scripts. The build flow also gained a credential picker so image builds can target the intended cloud account.

AWS, Azure, and prebake reliability

AWS provisioning now handles multi-VPC security group selection correctly and avoids default-VPC security group APIs. Azure capacity failures rotate more cleanly, and prebake image lookup now keys on image digest so reused tags resolve to the right baked image.

0.1.19

Agent-scoped list, cost, and spend controls

anycloud list and anycloud cost now scope to the detected agent session when appropriate, matching the per-session throttle and budget controls. Spend-cap block alerts are debounced so queued deployments do not spam repeated notifications while waiting for capacity or budget.

Quota and capacity retry routing

Quota failures are now classified by region versus account scope, so the optimizer blocks the right retry target instead of over- or under-rotating. AWS provisioning also handles shared IAM bootstrap retries and non-default networking paths more reliably.

Cross-cloud bucket and checkpoint credential fixes

Bucket sync, checkpoint restore, and cross-cloud storage credentials now use the credential scoped for the actual storage operation. This avoids leaking AWS S3 credentials across provider boundaries and makes cross-cloud checkpoint flows more predictable.

0.1.18

Auto-retry jobs whose container can't see the GPU

If a GPU job's container exits with CUDA_ERROR_NO_DEVICE in its logs — the host booted without visible GPUs — the deployment now retries on a fresh VM instead of being marked errored. The previous behavior required a manual anycloud resubmit for every occurrence. The retry uses the standard failed-deploy backoff and exhaustion limits.

Notifications digest skips the first-run backfill

The first time the digest monitor runs after enabling notifications on a host, it marks today as the starting point and posts nothing. Previously the next 15-minute tick would post a half-empty digest of whatever happened to be in the DB before notifications were configured. Your first real digest now lands the morning after your first full UTC day with notifications enabled.

Interactive prompts for budget, throttle, notifications

Running anycloud budget set, anycloud throttle set, or anycloud notifications enable slack with no arguments now prompts for the missing values (cap, window, webhook URL) when stdin is a terminal. Flag-only invocations behave the same as before, and piped or CI usage (no TTY, or CI=true) still exits with the previous error instead of hanging.

0.1.17

status now returns the full VM history (breaking)

/v1/status and anycloud status --json now return vms (every VM ever associated with the deployment, terminated rows included) instead of vmStatuses (active only). Each entry has a new endedAt field — null for live VMs, a millisecond timestamp for terminated ones. Live VMs still carry the container and rclone health-check fields; terminated rows are provisioning metadata only. This lets you read prebakedImageId, region, and cloudId for VMs after they've been cleaned up — previously those were only visible during the deployment's running window.

The human-formatted anycloud status output is unchanged by default (terminated VMs are hidden). Pass --verbose to see them, marked (terminated). The Python SDK's status_response.vm_statuses is now status_response.vms and includes terminated rows; SDK helpers like Job.exec() and Job.logs() filter to live VMs automatically.

If you have scripts that grep for vmStatuses in status --json output, rename to vms and add select(.endedAt == null) if you want the old "active VMs only" semantics.

Spend controls: anycloud throttle and anycloud budget

Two new commands cap spend by blocking new dispatches when usage exceeds a limit. Running jobs are never killed — only queued work pauses.

  • anycloud throttle set 20 — burn-rate cap ($/hr across in-flight VMs, plus the candidate). Set --agent-session to cap each agent run independently instead of account-wide.
  • anycloud budget set 100 --per day — calendar-window cap (day, week, or month). Same --agent-session toggle.

Blocked deployments stay queued with a reason shown inline in anycloud list and anycloud status, and auto-dispatch once running VMs end (throttle), the calendar resets (budget), or you raise the cap. See Spend Controls for the full surface.

anycloud db query / db schema for read-only DB inspection

Two new commands let you (or an agent) inspect the local API database without leaving the CLI. anycloud db query "<sql>" runs a read-only SELECT / WITH / EXPLAIN / PRAGMA — writes are refused at the SQLite engine level — and emits rows as JSON with --json. anycloud db schema [table] introspects tables, columns, foreign keys, and indexes; pair the JSON form with db query to answer "which deployments are stuck and why" without poking the SQLite file directly.

anycloud cost switches to real billed cost

anycloud cost <id> now shows the real cost pulled from your cloud provider's billing API once the bill settles (~24 hours after a deployment ends). Until then — or if your account doesn't have billing-read permissions — it falls back to the catalog estimate as before, marked (est.).

To enable this, the cloud credentials anycloud uses now need a small additional permission:

  • AWS: add ce:GetCostAndUsage to the IAM policy. Activate the anycloud_deployment cost-allocation tag once (Billing → Cost Allocation Tags → activate, or aws ce update-cost-allocation-tags-status --cost-allocation-tags-status TagKey=anycloud_deployment,Status=Active).
  • Azure: grant the service principal the built-in Cost Management Reader role on the subscription.
  • GCP: enable Cloud Billing BigQuery export with resource-level detail, grant the service account roles/bigquery.dataViewer on the billing dataset, and pass the dataset to anycloud setup gcp.

Without these, nothing breaks — anycloud cost keeps showing the estimate.

anycloud notifications enable slack — daily Slack digest of usage

The API container can now post a once-a-day summary to a Slack channel you choose, aggregated from your local deployment history (~/.anycloud/api.db) and sent directly from your machine to the webhook.

anycloud notifications enable slack --webhook https://hooks.slack.com/... posts a test message before saving so a typo'd webhook is caught immediately. The digest covers total spend, count by terminal state, preemption rate, median runtime, and active users. anycloud notifications status / test slack / disable slack round out the surface. Setup details are in Notifications.

0.1.16

MCP secrets tools

Three new MCP tools — secrets_list, secrets_create, secrets_delete — let an agent manage named secrets (env-var bundles used via secrets=[...] on submit). Mirrors the existing CLI secrets new/list/delete. secrets_delete accepts force=True to override the safeguard that blocks delete while non-terminal deployments still reference the secret.

CLI catalog introspection

Four new commands surface the same cloud catalog the Python SDK already exposed, so you can pick a region or VM type before you submit:

  • anycloud regions <provider> [--vm-type <type>] [--spot] — list available regions. With --vm-type, narrows to regions that offer that VM type, sorted cheapest first.
  • anycloud vm-types <provider> <region> [--accelerator <gpu>] — list VM types in a region, optionally filtered to ones with a specific accelerator.
  • anycloud gpus <provider> [--type <gpu>] — list available GPUs, or available counts for a specific GPU when --type is given.
  • anycloud pricing <provider> <vm-type> [--region <r>] [--spot] — on-demand or spot price per region.

All four accept --json for scripting and accept the provider name case-insensitively (aws, AWS, Aws all work).

anycloud bucket upload / download

New CLI commands stream files in and out of an S3, GCS, or Azure Blob bucket using a credential you've already registered with anycloud credentials new:

anycloud bucket upload my-bucket ./data.bin data/in.bin --credentials prod-aws
anycloud bucket download my-bucket data/out.bin ./out.bin --credentials prod-aws --region us-east-1

The same routes back the Python SDK's Bucket.upload() / Bucket.download(), so the CLI and SDK now go through one code path. As part of that switch, the Python SDK no longer needs cloud filesystem libraries — the [aws], [gcp], and [azure] extras have been removed from anycloud-sdk because s3fs, gcsfs, and adlfs are no longer used. Bucket I/O now requires the credential to be registered with anycloud credentials new (it could previously work with inline CloudConfig credentials passed to Client(...)); construct your client with Client(credentials="<name>") instead.

anycloud cost --json for scripts and agents

anycloud cost now accepts --json. Without an id, it emits the aggregate report { periodMs, totalCost, totalDurationMs, totalJobs, deploymentsWithoutPrice, byProvider }; with an id, it emits the per-deployment fields (id, image, cloudProvider, region, vmType, spot, totalCost, durationMs, ratePerHour). Previously the only output was a formatted table, so anything calling anycloud cost from a script had to grep currency strings out of stdout.

anycloud list gains exact-match filters and machine-friendly output modes

anycloud list now supports --status <state>, --provider <cloud>, --csv, and --only-ids in addition to the existing substring -f, --filter and --json. Multiple predicates AND together. --csv emits a header row plus one row per deployment (id,state,cloudProvider,region,vmType,image,spot,startedAt,completedAt,totalCost,deploymentType), useful for piping into spreadsheets or awk. --only-ids emits one deployment ID per line and skips the table, useful for anycloud list --only-ids --status running | xargs anycloud terminate and similar batch operations.

--json output is now compact

Every --json flag in the CLI (list, status, cost, credentials list, config list, quota) now emits a single line of compact JSON instead of pretty-printed JSON with two-space indents. Equivalent payload, ~30% fewer bytes. jq . and any other JSON parser handle it identically.

0.1.15

Failed provisioning attempts no longer orphan cloud resources or pollute anycloud list / cost

When a VM provisioning attempt failed partway through (for example, Azure created the NIC and Public IP but the VM create itself errored), the rows were marked "ended" in anycloud's bookkeeping even though the cloud-side resources were still there — slowly eating the 100-Public-IP-per-region Azure quota until new submits started failing on quota errors. The same rows also showed up as live VMs in anycloud list and accrued duration in anycloud cost. Cleanup now waits for the cloud to confirm each resource is gone before marking it ended (the cleanup monitor keeps retrying anything the cloud rejected), and failed-attempt rows are filtered out of the list and cost aggregates.

status always renders the deployment header

anycloud status <id> no longer falls back to ❓ unknown with a "deployment not found in deployments list" hint when the id is older than the picker window or otherwise missing from the recent list. The metadata (image, cloud, region, VM type, age) now comes back with the status response itself, so the header is correct on the first call and the second round-trip is gone.

Security: deployment IDs are no longer probeable across users

Knowing another user's deployment id no longer lets you fetch their SSH key (status), terminate their job (terminate), or resubmit it (resubmit). All three now reject cross-user ids with the same "deployment not found" response they return for ids that genuinely don't exist, so an authenticated caller can't enumerate other users' deployments either. Pre-existing pings against your own deployments are unchanged.

0.1.14

anycloud cost now works for jobs submitted without a pinned region

anycloud cost reported $0.00 for jobs submitted without an explicit region — the common case, since omitting a region enables multi-region failover. The hourly rate is now captured on each VM at provision time (when the region is finally known) and cost is summed across the deployment's VMs, instead of relying on a single rate stored at submit. Multi-region retries that land in different-priced regions are now reflected accurately in the total.

0.1.13

Multi-region Azure submits stop retrying regions the subscription can't use

When Azure rejects a region with a "not permitted for subscription" or "not available for resource group" error (e.g. Jio India regions on most commercial subscriptions), the deployment now skips that region for the rest of its lifetime instead of cycling back to it every few minutes. Previously, multi-region jobs could exhaust their retry budget bouncing between forbidden regions and never reach the regions the subscription actually has access to.

0.1.12

--persist-bucket retains the spot checkpoint bucket without keeping the VM

anycloud submit --spot --persist-bucket skips the auto-deletion of the checkpoint bucket on job completion. Independent of --persist — the common shape is an ephemeral VM (no --persist) plus a retained bucket, so a later anycloud resubmit <id> brings a fresh VM up against the same checkpoint contents without paying for an idle one in between. The flag is a no-op (with a warning) on non-spot deployments since they have no checkpoint bucket. Cleanup is manual: aws s3 rb s3://<id> --force or the equivalent for your provider — the existing orphan reaper leaves retained buckets alone because they aren't tagged as ended.

0.1.11

Legacy credential arrays

Earlier builds briefly accepted a list of named compute credentials. That shape has been superseded by pinned-or-unpinned compute credentials: pass one --credentials <name> to pin compute, or omit it so anycloud chooses from saved named credentials.

Legacy array rows are normalized to unpinned compute during migration.

0.1.10

Ordered fallback pools for vmType and gpuType

Both fields now accept an array as well as a single string. The provisioning scheduler expands every entry into the candidate pool — for gpuType, each alias is resolved into all interchangeable instance types — and falls over in order when the primary is quota-blocked or unavailable. CLI flags --vm-type / --gpu-type are now repeatable on submit, config new, and config edit; anycloud.yaml profiles accept a list under either field. The config new wizard now uses a multi-select picker (Space to mark, Enter to confirm — selection order is fallback order). The two fields are still mutually exclusive (only one of vmType / gpuType may be set, but each can itself be a list). The original list is preserved on the deployment row for display and retries.

quota request always asks for one more instance of headroom

anycloud quota <vmType> now files a ticket every time you run it (unless an in-flight request is already pending for the same family + region). The previous "only when exhausted" trigger missed the common fresh-subscription case — limit=0, usage=0 looked fine but the user couldn't launch a single VM. The new target is max(currentUsage + vCPUsPerVM, currentLimit × 2, vCPUsPerVM) — at minimum, one more instance's worth of capacity, with a doubling floor on top so re-running keeps growing the ceiling. AWS applies the same rule with currentUsage treated as 0 (Service Quotas doesn't expose live usage).

If every surveyed region already has a pending ticket for the family, the tail reads No new tickets filed — every surveyed region already has a pending quota request for <vmType> on <cloud>. instead of No actions taken..

quota picks credentials, not clouds

quota request and quota status now prompt for a credential rather than a cloud — credential implies cloud, so the second picker round-trip is gone. With a single AWS or Azure credential the picker is silent; with multiple, an autocomplete labelled <name> (<cloud>) appears. --credential <name> still bypasses the picker. Credentials for clouds without quota support (GCP, Lambda, Local) are filtered out and surface a clear error instead of running the picker only to fail later.

Breaking: --cloud removed from quota subcommands

anycloud quota --cloud <aws|azure> no longer accepts the flag on either request or status. Cloud is now derived from the resolved credential or, for request, the vmType prefix. Pass --credential <name> to pin to a specific account.

0.1.9

Picker fixups

  • Restore -a/--all on status (regressed when the picker came back) so the picker can widen past the last 24h.
  • --json now refuses the picker rather than dumping its stdout chrome into the JSON pipe.

Multi-region quota request / quota status

--region is now optional on both subcommands. Omit it to fan out across every region in the cloud's catalog (AWS narrows to regions where the vmType is offered; Azure narrows to regions where the family is exhausted). Per-region calls run in parallel via Promise.allSettled, so wall-clock matches a single-region invocation. Re-runs stay idempotent thanks to the existing per-region dedup.

When the fan-out hits an AWS region that is disabled-by-default (e.g. me-central-1, ap-east-1, af-south-1), anycloud submits the AWS EnableRegion call for it. Opt-in is asynchronous — the quota request for that region is deferred and the entry comes back as SUBMITTED with optInAction: enabling. Pass --region if you'd rather not opt anything new in.

Interactive GPU instance picker

Run anycloud quota request with no vmType and no --gpu in a TTY to get an interactive cloud picker followed by an autocomplete list of GPU instance types from the catalog (e.g. g6e.48xlarge — 8× L40S (192 vCPUs)). Non-TTY / --json flows are unchanged: an explicit vmType or --gpu is still required.

0.1.8

Smarter blocks for disabled regions

When a provision fails because the region's quota is 0 or the subscription can't deploy there at all (AWS OptInRequired, Azure ProvisioningDisabled / LocationIsOfferRestricted), the optimizer blocks that region for 6 hours instead of the 30-minute generic quota block — so retries stop hammering regions that won't come back without a support ticket.

Named Secrets

New primitive for env vars you don't want visible in API responses. anycloud secrets new|list|delete manages named bundles that are encrypted at rest, never returned by the API, and injected into containers at run time via --secret <name> (CLI) or secrets=[...] (Python SDK). Update a secret and resubmit to rotate — no need to edit every call site. See Secrets & Environment.

Sensitivity warning on --env

When you pass a likely-sensitive key via --env (e.g. HF_TOKEN, API_KEY, anything matching token / secret / password / key), the CLI prints a one-line warning pointing at anycloud secrets new. The submit still proceeds; the warning is advisory.

Version warning

The CLI checks its own version against the current public release and prints a warning when you're behind. Keeps users from debugging issues that were already fixed upstream.

anycloud quota status now surfaces structural console URLs (AWS Service Quotas, Azure portal) for each case, so you can jump straight to the provider's UI.

Smarter quota request

anycloud quota request detects partial grants and skips re-requesting quota that's already been submitted or granted, so re-runs are idempotent.

Broader Azure Region Coverage

Azure catalog now pulls the full list of physical regions via the subscription-wide /locations endpoint instead of per-SKU locationInfo, which was silently gated on per-SKU enrollment. Measured on one subscription: 43 → 58 regions, ~33k → ~55k SKU rows.

--json on read-shaped commands

status, list, config list, and credentials list now accept --json. Chrome output routes to stderr; stdout is the pure JSON payload, so anycloud list --json | jq just works. credentials list --json emits only {name, cloudProvider} — secret fields never cross the boundary. Empty results return [] instead of the prior "No X found" strings.

Interactive deployment picker (TTY only)

Deployment ID is now optional on status, logs, exec, ssh, terminate, and resubmit: omit it in a TTY for an interactive picker (multi-select on terminate and resubmit). This walks back part of the "Non-Interactive CLI" change from 0.1.7 — non-TTY/CI still requires an explicit ID or ANYCLOUD_DEPLOYMENT_ID, so scripts and agents are unaffected.

Azure-safe deployment ID cap

Max deployment ID length lowered 40 → 28 to leave room for the -${index} suffix Azure appends to VM/NIC/public-IP names. Auto-generated IDs also tightened so they fit under the new cap.

0.1.7

Batch Submission in the Python SDK

Submit many jobs in parallel from a single call, with first-class partial-failure handling. The decorator path gets a map helper for fan-out workloads.

More Resilient Prebakes

Cached images survive upstream base-image rotation, and bake outcomes now show up in deployment status instead of disappearing into logs. CLI status also surfaces when a deploy hits a prebake cache.

Quota Requests From the CLI

Request and check cloud quota directly from the CLI, with AWS now supported alongside Azure. Deployments that exhaust retries on a quota error point you at the new commands.

Credentials Through the API

The CLI and MCP no longer touch plaintext credentials on disk. New MCP tools cover importing existing cloud credentials and generating least-privilege ones.

Non-Interactive CLI

Every CLI command is now flag- and env-driven — no prompts, no pickers, no wizards. Better for scripts, CI, and agents.

Steadier Region Rotation

Region or SKU mismatches from a cloud no longer fail a deployment outright; the optimizer rotates instead.

0.1.6

More Resilient Image Pulls

Faster retries on transient pull failures and gentler post-provisioning backoff.

Expanded MCP Server

Added list_gpus, list_gpu_counts, credentials_get, bucket_upload, and bucket_download tools.

Smarter Region Rotation

When every target is temporarily blocked, the optimizer rotates across regions instead of stalling on the cheapest one. Block TTLs are also preserved at their maximum, and InvalidTarget blocks are capped at 6 hours.

Strict CloudConfig Validation (Python SDK)

CloudConfig now rejects unknown keyword arguments instead of silently ignoring them.

0.1.5

Per-Bucket Storage Credentials

Input and output buckets can now use different cloud credentials and regions. The shared storageCredentials/storageRegion fields have been replaced with per-bucket equivalents (inputStorageCredentials, outputStorageCredentials, etc.).