Repos, secret files & setup
Besides variables, your account's environment says what every new sandbox starts with: GitHub repos cloned into ~, secret files such as .npmrc or app/.env, and a setup script.
$ froog environment add-repo https://github.com/you/app # optionally #branch
$ froog environment add-file app/.env ./app/.env # or pipe it on stdin
$ froog environment add-file .npmrc ~/.npmrc
$ echo 'npm ci' | froog environment repo-setup app - # runs in ~/app after the clone
$ echo 'docker compose up -d' | froog environment setup -
$ froog environment show
At every start (create, start, fork, restore), before the sandbox counts as running, the secret files are written, mode 600. Then a background command clones each repo whose directory has no checkout yet, runs each repo's own setup script in its directory (froog environment repo-setup REPO FILE, REPO being its directory or URL, --clear removes it), and then the setup script from ~, all in login shells. A secret file inside a repo directory, like app/.env, stays when the repo is cloned around it. The setup script runs at every start, so make it safe to run again. Its output is a background command: froog jobs box, then froog logs box JOB. Setup doesn't hold off auto-stop. froog info box and the API's setup_status say how the last start's setup went: none (nothing to do), running, done or failed, with setup_error saying why (a repo that didn't clone, a script's exit code). A sandbox stopped mid-setup shows failed.
Private repos: connect GitHub (each sandbox then gets a short-lived token), or set a GH_TOKEN variable (setup runs gh auth setup-git, so git and gh both use it), or add a .git-credentials secret file. URLs can be https://, ssh:// or git@host:org/repo. SSH URLs need a key you add as a secret file (e.g. .ssh/id_ed25519).
One sandbox's files: froog new box --file app/.env=.env (repeat it) writes a local file into ~ before the sandbox counts as running, after your secret files, so it wins over one with the same path. Mode 600, up to 20 files and 1 MiB together, kept encrypted until the first boot and then forgotten. Forks don't get them again (the disk already has them).
One sandbox's repo: froog new pr-42 --repo https://github.com/you/app#pr-42 clones that repo and branch into ~/app of this sandbox only (--repo-dir src/app puts it elsewhere under ~). API: "repo": {"url", "branch"?, "dir"?} on create. It's cloned by the same setup job as your account's repos, first, and also with --no-environment. Private repos need credentials in the sandbox: -e GH_TOKEN=…, or your environment's. Don't put a token in the URL (it's refused, since the URL shows in froog info). Forks don't clone it again (the disk already has it).
One-off setup: froog new box --setup-file setup.sh runs a script once, after the first boot, after the environment's own setup. Forks don't rerun it.
Nothing of yours: froog new box --no-environment starts a sandbox without your variables, repos, secret files, setup scripts or in-sandbox froog key. Use it for code or people you don't trust with your credentials. Its forks get none either.
Removing your logins. A disk that had your environment still holds what it wrote and what you did there. So when a sandbox starts without the environment from such a disk (froog fork box copy --no-environment, froog start box --no-environment, or froog new copy --from SAVED --no-environment), and whenever a sandbox starts from a share code, froog first removes these from its disk, before it counts as running. If that fails, the start fails (error) rather than open the sandbox with them.
- git and GitHub:
~/.config/gh,~/.git-credentials,~/.config/git/credentials,~/.config/hub, and everycredentialsection of~/.gitconfig. - SSH: everything in
~/.sshbutauthorized_keysandknown_hosts*(keys under any name,config,config.d).authorized_keysstays: froog writes the keys allowed in at every boot (yours, or for a share code the other account's) and its own control key. - Coding agents:
~/.claude/.credentials.jsonand theoauthAccount,primaryApiKeyandcustomApiKeyResponseskeys of~/.claude.json(the rest of it stays),~/.codex/auth.json, Kimi Code's~/.kimi-code/credentials/kimi-code.jsonandconfig.toml, Mistral Vibe's~/.vibe/.env,~/.gemini/oauth_creds.jsonandgoogle_accounts.json,~/.local/share/opencode/auth.json,~/.local/share/amp/secrets.json,~/.pi/agent/auth.json, Cursor's~/.cursor/cli-config.jsonand~/.config/cursor/auth.json,~/.config/github-copilot,~/.aider.conf.yml. - Registries and containers:
~/.npmrc,~/.yarnrc.yml,~/.pypirc,~/.netrc,~/.cargo/credentialsandcredentials.toml,~/.gem/credentials,~/.docker/config.json. - Clouds, secrets managers and model hubs:
~/.aws/credentials,~/.aws/sso/cache, gcloud'scredentials.db,access_tokens.db,legacy_credentialsandapplication_default_credentials.json, Azure's token caches, all of~/.kube,~/.vault-token,~/.terraform.d/credentials.tfrc.json, 1Password's~/.config/op, Hugging Face's~/.cache/huggingface/tokenand~/.huggingface/token. - froog's in-sandbox key (
~/.config/froog/config.json, which reached the source sandbox), the variables file~/.froog/env(the new boot writes its own), and shell and REPL history (~/.bash_history,~/.zsh_history, fish's~/.local/share/fish/fish_history,~/.python_history,~/.node_repl_history,~/.psql_history,~/.mysql_history,~/.sqlite_history,~/.rediscli_history). - All of the above under
/roottoo, plus/root/.claude,/root/.claude.jsonand/root/.awswhole. - Every secret file any version of any of your environments has had, and the setup inputs in
~/.froog/setup. For a share code also the directories of the repos your environments clone. - cloud-init's copies of earlier boots' settings (
/var/lib/cloud/instances/*but the current boot's) and its logs (/var/log/cloud-init*.log). - System logs, which can hold secrets (sudo command lines, programs' output): the journal is rotated and its archives deleted, rotated logs are deleted, and the rest of
/var/logis emptied.
Files are overwritten before they're removed (up to 64 MiB each), and the scrub ends with fstrim, which hands the disk's free space back to the host: whoever gets root in the sandbox can't read removed files back off the raw disk, nor anything deleted on it earlier. If fstrim fails, the start fails. The boot also gets a new SSH host key (the API's ssh answer shows it), so the disk's earlier user can't pose as this sandbox.
Your variables never reach such a sandbox: froog writes ~/.froog/env over SSH at every boot, before the sandbox counts as running, and never puts it in the boot settings cloud-init keeps on the disk. Later starts of the same sandbox remove nothing again: logins made in it are its user's. Forks of it need nothing removed. Removing a file deletes it, so keep anything you need from such a disk elsewhere first.
Several environments
Your account starts with one environment, default, which froog environment show and /v1/environment work on. Make more for different kinds of sandboxes (a staging stack, CI jobs, users' sandboxes) and pick one per sandbox.
$ froog environment create ci --copy-from default # or empty
$ froog environment add-file .npmrc ./ci.npmrc --env ci
$ froog new job-1 --environment ci
$ froog environment list # default marker, latest version, sandboxes per version
$ froog environment show ci
$ froog environment default ci # what new sandboxes use when they name none
$ froog environment rename ci jobs
$ froog environment rm jobs
add-repo,rm-repo,repo-setup,setup,add-fileandrm-filetake--env NAME(default: your default environment). Names are 1–40 lowercase letters, digits and dashes. Up to 20 environments.- Account variables (
froog env) go to every environment. A sandbox's own variables (-e) come on top. froog infoand the API'senvironment_namesay which one a sandbox is in. A sandbox with--no-environmentis still in one, and gets none of it.- Deleting an environment keeps its sandboxes running on their version. New sandboxes can't use it. The default can't be deleted (
409 environment_is_default): make another the default first. - API:
GET · POST /environments,GET · PATCH · DELETE /environments/{env},PUT · DELETE /environments/{env}/files. Create withenvironment_nameonPOST /sandboxes.
Versions and upgrades
Every change to an environment (repos, scripts, secret files) makes a new version, and versions never change. A sandbox stays on the version it was created with, at every start, until you move it:
$ froog environment versions ci # v3 "file .npmrc set", v2 "repos", …, with sandboxes on each
$ froog environment upgrade ci # every sandbox of ci to the latest (also: froog env upgrade ci)
$ froog environment upgrade ci --sandbox job-1
$ froog start job-2 --environment default # onto another environment's latest version
- An upgrade applies at once to running sandboxes: it writes the new secret files, removes the ones the new version dropped, and runs the setup job again. Stopped ones get it at their next start.
POST /environments/{env}/upgradeanswers{version, applied, at_next_start}. - A fork gets exactly its source's environment and version (
--environment NAME: that one's latest). A sandbox from a saved snapshot gets the latest version of the environment it names. - Sandboxes created before environments had versions join the latest version at their next start.
- Removing a file in a new version deletes it from a sandbox's disk when the sandbox moves to that version. Going back to an older version doesn't bring a deleted file back until the next apply writes it.
- The last 50 versions are kept, and any older one a sandbox is still on.
Secret file contents and the setup scripts are encrypted at rest, and file contents are never shown again. Up to 20 repos, 50 files (64 KiB each, 1 MiB in total), and 64 KiB per script. The dashboard edits all of it too.