Docs/Sandboxes v2 (Beta)
#

Sandboxes v2 (Beta)

What a Sandboxes v2 sandbox is, its two delivery modes, versions, environments, the claim lifecycle and limits.

A Sandboxes v2 sandbox is a live, isolated copy of your application: running on its own https URLs, seeded with known data, with a working login for every role your tests need. You describe it once in a cofactor.sandbox.yaml; after that, anyone (a person, a test run, a coding agent) can claim a fresh copy in seconds, use it, and throw it away.

Sandboxes are fast to claim because they are restored, not rebuilt: installing, building and seeding happen once per version and environment, are captured in a ready snapshot, and every claim restores its own copy of it.

Sandboxes v2 is enabled per organization. If a command answers "Sandboxes v2 is not enabled for this organization", ask us to turn it on.

Setting one up? Copy this prompt and give it to your agent. It checks the CLI and your sign-in, reads the sandbox guide, asks you how you want it set up, then builds and proves a sandbox:

Set up Cofactor sandboxes for my app

01Authentication in native flows

Each native flow run gets its own copy. When its Login node needs a persona, Cofactor invokes the copy’s private authentication script and installs the returned app session. Matching persona names let existing flows run without editing their Login nodes; no session is shared between tests. This does not automatically configure authentication for external Playwright suites.

Provider sign-in tests start without an app session and exercise the app’s login UI and callback. See Google OAuth and third-party login for callback configuration, the default identity and Beta rollout limits.

02How it relates to Sandboxes (Beta)

Sandboxes (Beta) are built from templates you author inside Cofactor (artifacts, a checklist, template actions) and provisioned as instances. Sandboxes v2 is a separate model:

Sandboxes (Beta)Sandboxes v2
Defined byA template authored in CofactorOne cofactor.sandbox.yaml, in your repository or pushed with your image
Belongs toA templateAn application
Code comes fromA linked GitHub repositoryA connected GitHub repository, or images you push (no repository access)
Getting oneProvision an instanceClaim a copy of a ready snapshot
CLIcofactor sandbox create, provision, logs…cofactor sandbox validate, push, connect, claim, run…
Built-in guidecofactor sandbox guidecofactor sandbox guide v2

Both share the cofactor sandbox command group. The Sandbox CLI page lists the v2 commands.

03Delivery: where the code comes from

Every sandbox belongs to a Cofactor application. How the application's code reaches its sandboxes is its own setting, and an application has exactly one:

GitHubPushed images
Set up withcofactor sandbox connect --application A --repo owner/name [--dir D]cofactor sandbox push --application A <image> (the first push sets it up)
Cofactor's accessYour repository, through the GitHub AppNone: you build and push the image
The definitionAt the repository root or a definition directory, read at each commitPushed with each image
BuildingCofactor runs your setup and lifecycle.buildAlready built into the image
A version isA commitA push
Pull request previewsAutomatic, one per pull requestPush with a tag per pull request
GuideSandboxes from GitHubSandboxes from a pushed image

An application connected to GitHub refuses pushed images. A monorepo can connect one application per definition directory.

04Versions and tags

  • GitHub: each commit is a version. A claim without --at copies the default branch's current ready snapshot of the environment, which Cofactor rebuilds at the head every 6 hours while the environment is in use (claimed in the last two weeks), so it can be up to 6 hours behind. A snapshot more than 12 hours old counts as stale, and the claim builds the head instead. --at <sha> claims a specific commit (the full 40-character SHA).
  • Pushed images: each push is a version, with its own id. A claim without --at uses the newest ready push. --at takes a push id or a tag.
  • Tags (pushed images): a push can carry up to 10, each letters, digits, ., _ and -, at most 64 characters, starting with a letter or digit. A tag names the newest ready push that carries it, so pushing --tag nightly again moves the tag; older pushes stay claimable by their id.

05Environments

An environment (a "flavor") is the same sandbox, same code, started with different data and config: default, free-plan, beta-features. Every definition has a default environment, and it's what a claim gets when it doesn't name one. An environment can extend another, running its parent's seeds first.

Each environment in the definition becomes a sandbox environment of the application, alongside its other environments. Each persona in the definition becomes one of the application's personas, matched by name (case doesn't matter), so a test run on a sandbox environment signs in with that sandbox's own logins, with no mapping to set up.

This sync only adds:

  • an environment the definition no longer declares stays on the application until you delete it, and claims of it fail, naming the missing environment;
  • if the application already has an environment with that name, the new one is named <name> (sandbox);
  • the name, variables and default flag you give a synced environment are kept.

A test run can target a sandbox environment like any other environment of the application, and runs on its own copy.

06The claim lifecycle

  1. Snapshot. A claim needs the ready snapshot for its version and environment. If there isn't one yet, it's built first, once, however many claims are waiting on it: (GitHub) the nearest layer is restored and the outstanding build steps run; prepare runs; the environment's seeds run in order; the sandbox is captured with its services running.
  2. Restore. A copy of the ready snapshot is restored. Nothing is built or seeded; the copy starts where the snapshot left off, data included.
  3. Prepare. lifecycle.prepare runs on the copy. This is where it becomes this sandbox: its own public URLs, freshly generated persona passwords and, with emulation declared, a fresh emulator configuration.
  4. Ready. The sandbox reports its URLs, persona logins and seed outputs. A copy is never reused.

cofactor sandbox show breaks the time to ready down into these phases (snapshot, restore, prepare).

Failures. A failure while building a ready snapshot (a build step, prepare or a seed) fails the claims that were waiting on that build. A claim made after the failure builds the snapshot again. So a passing problem clears with the next claim, but a seed or build bug that fails every time keeps failing until you fix it and push or commit again. See When a seed fails.

Statuses. A sandbox is claiming, ready, failed or destroyed. A push is uploading, importing, ready or failed.

How long a sandbox lasts

  • A sandbox you claim has a two-hour lease, shown as expires by cofactor sandbox show. It isn't extended. Destroy it as soon as you're done (cofactor sandbox destroy <id>), and claim a new one for more time.
  • A pull request preview is kept alive by each push to the pull request, for up to two weeks, and is destroyed when the pull request closes.

07Logins

Each persona gets a freshly generated password in every sandbox. lifecycle.prepare receives them as COFACTOR_PERSONAS and must make each login work in the app. People and agents read them with cofactor sandbox show <id> (or cofactor sandbox preview for a pull request). They never appear in a pull request comment.

08In the app

The Sandboxes page has a v2 view, with:

  • Applications: each application's delivery and latest version, and its environments, each with a readiness state (ready, warming, stale or none) and a Claim button;
  • Live sandboxes: application, environment, version, status, who claimed it, and when it expires, with links to its URLs, its logins, and Destroy;
  • Pushes (pushed-image applications): each push's tags, status and any import error, with a button to claim that version.

A sandbox's detail page shows its status and timing, URLs, persona logins, seed outputs and expiry, and runs actions from a form built from each action's input schema.

09API keys

A scoped API key needs the sandbox scope's matching action for each Sandboxes v2 call: read, publish (push), create (claim), run (actions), delete (destroy) and edit (connect a repository). sandbox:read includes persona logins. A CI job that pushes images needs sandbox:read, sandbox:publish and property:read. See API Keys and Sandbox CLI → API key scopes.

10Limits

LimitValue
Ports per sandbox, implicit emulation and object-storage included8
resources.vcpus1–32
resources.memory_mib1024–65536
Definition size256 KB
Action timeout1–1800 seconds (default 60)
Service healthhealthy within 5 minutes of starting
Image platform (pushed)linux/amd64, glibc, with bash
One image layer (pushed)5 GB
Tags per push10
Layers reused by a re-pushthose uploaded in the last 30 days
Claimed sandbox lease2 hours
Object storage providers per application1

11Reference

12Guides