Sign in

Environments

What a new box inherits, kept as versions: repos to clone, a setup script, env vars, secret files, and which of your credentials it may receive (CLI and API only).

On this page10

What a box receives

Pick an environment at create time (--environment on prized box new, environment on POST /api/v1/boxes) or let the default apply. The box receives, in order:

ItemWhenWhere it lands
Env varsfirst boot + live/etc/doppel/box-env.sh, sourced by every login shell
Reposfirst boot~/<dir> (default: the repo name), cloned as your box user, blocking repos first
Setup scriptfirst bootRuns once as your box user in your home, after the repos; log in /var/log/doppel-setup.log
Secret filesfirst boot + live~/<path>, owned by your box user, mode 0600 unless you set another

Env vars and secret files stay live: a change reaches the box within seconds, for new login shells. Secret files travel over the box's authenticated channel, never in the launch configuration, and the CLI shows only their path and size.

The default environment

There is none until you mark one: --default when creating, or prized environments default <name>. A box created from the CLI or API without naming an environment then takes it (environment: null on the API opts out). A box from the dashboard's New box page, the box your plan launches, a restore, and a fork never inherit one.

Versions and upgrade

Every save that changes what a box inherits mints a new immutable version (a rename or new description does not), and a box keeps its version until you upgrade it. Names are unique in the workspace regardless of case: prod and Prod are one name.

Versions
environment ml        v1 ──── v2 ──── v3 (latest)
                       │        │
box kiwi (created v1)  ●────────┼──── upgrade ──▶ v3
box mango (created v2)          ●──── stays on v2 until upgraded

prized environments upgrade <name> pins boxes to the latest version:

On upgradeWhat happens
Env vars and secret filesRe-apply within seconds; a dropped file or var is removed from the box.
Repos and the setup scriptDo not re-run.
A safe-for-third-parties versionMakes the box restricted, permanently: mounted secrets stop resolving, its phone password is revoked, device keys leave.
A box whose own vars would not fit the launch budgetSkipped (named in skipped); it keeps its version.

Up to 50 versions are kept per environment; older ones no live box pins are pruned.

Safe for third parties

A box for someone else (a contractor, a demo, an agent you do not fully trust) should hold none of your credentials: switch on safe for third parties on its environment (prized environments set <name> --safe-for-third-parties true), or tick Restricted when creating one box. Four channels close:

ChannelWhat is refused
Secret mountsPOST /api/v1/boxes/:id/secrets answers 409 box_restricted; no connector or secret can be mounted, and the box receives no AWS profile
Device keysNo member device SSH keys reach the box; desktop apps that rely on them cannot log in
Phone accessPOST /api/v1/boxes/:id/mobile-ssh answers 409 box_restricted
CLI credential handoffprized agents handoff and the agent, secrets and data steps of prized setup refuse with CHECK_FAILED (exit 5); prized setup also keeps .env files out of every sync session to the box

Env vars still apply. A safe environment cannot carry secret files (safe_environment_has_secret_files), and a restricted box never receives any, at create or on any upgrade, whatever environment it runs.

Restricted is one-way: set at create (restricted: true, or a safe environment), by an upgrade onto a safe version, or inherited by a restore, and never unset. The three channels can also be closed one at a time on an environment without restricting the box.

Repos

A repo is owner/name (GitHub) or an https:// clone URL, with an optional branch, directory under your home (default: the repo name), and setup script run inside the clone. A blocking repo clones before the others and before the environment's setup script.

Clones are plain https, so no credential lands in .git/config, and an existing directory is left alone. For a private repo, clone on the box once gh is signed in there (Credentials), or ship a deploy key as a secret file and clone in the setup script.

Vars and secret files

Env vars are not secret: shell-identifier names, single-line values, shown in the CLI. Put anything sensitive in a secret or a secret file: up to 64 KiB at a path relative to your home (.aws/credentials, .npmrc), encrypted at rest, decrypted only for its box, written 0600 or the mode you set, up to 16 per environment.

Per-box vars

Set a box's own vars with env at create (POST /api/v1/boxes with {"env": {"NAME": "value"}}) or Variables on the box page's Settings tab (PATCH /api/v1/boxes/:id with {"env": {...}}, which replaces the set). A per-box var wins over an environment var of the same name. Environment plus per-box vars must fit the launch budget of about 16 KiB compressed; a create or PATCH that would not fit is refused with environment_too_large.

Limits

Every cap, the launch budget included, is on Limits.

CLI

prized environments (alias prized envs); every command takes --json.

CommandWhat it does
prized environments lsOne row per environment. JSON: {"environments": [...]}
prized environments info <name>Channels, repos, vars, secret files (path, mode, size), versions with box counts. JSON: {"environment": {...}}
prized environments new <name> [--description] [--setup-script FILE] [--default]Create; --default marks it the default for new boxes
prized environments default <name>Make it the default for new boxes
prized environments rm <name>Delete (asks; -y skips); boxes keep their version
prized environments set <name> --safe-for-third-parties true|false --secret-mounts true|false --device-keys true|false --phone-access true|false [--description] [--setup-script FILE]Flip the switches or replace the description or script
prized environments set-var <name> K=V / rm-var <name> KSet or remove one env var
prized environments set-file <name> <path> --from FILE|- [--mode 0600] / rm-file <name> <path>Set a secret file from a local file or stdin, or remove it
prized environments add-repo <name> owner/repo [--branch] [--dir] [--setup-script FILE] [--blocking] / rm-repo <name> owner/repoAdd, replace, or remove a repo
prized environments upgrade <name> [--box B]...Pin every live box (or just --box ones) to the latest version. JSON: {"environment", "version", "upgraded": [ids], "skipped": [ids]}

The CLI's environment object carries the API row's fields in snake_case (safe_for_third_parties, secret_files, latest_version, versions with boxes counts).

Exit codes follow the CLI table: an unknown environment or a restricted-box refusal is CHECK_FAILED (5), a bad value USAGE (2), a taken name CONFLICT (6).

API

All routes take your session or a dcp_ CLI bearer, are scoped to your workspace, and take JSON bodies.

RouteBody / answer
GET /api/v1/environments{"environments": [row]}; a row carries isDefault, the four switches, latestVersionNo, repos, secretFiles as {path, mode, size}, versions as {versionNo, createdAt, boxCount}
POST /api/v1/environments{name, description?, baseTier?, setupScript?, envVars?, repos?, secretFiles?: [{path, content (base64), mode?}], safeForThirdParties?, passSecretMounts?, passDeviceKeys?, passPhoneAccess?, isDefault?} → 201 {environment}
PATCH /api/v1/environments/:idAny of the above; a config field mints a version → 200 {environment}
DELETE /api/v1/environments/:id204; boxes keep their version
POST /api/v1/environments/:id/defaultMake it the default → {environment}
POST /api/v1/environments/:id/toggles{safeForThirdParties?, passSecretMounts?, passDeviceKeys?, passPhoneAccess?} → {environment}
POST /api/v1/environments/:id/vars{name, value} → {environment}; DELETE /:id/vars/:name removes
PUT /api/v1/environments/:id/files{path, content (base64), mode?} → {environment}; DELETE /:id/files?path= removes
POST /api/v1/environments/:id/repos{repo, branch?, dir?, setupScript?, blocking?} → {environment}; DELETE /:id/repos?repo= removes
POST /api/v1/environments/:id/upgrade{boxIds?} → {upgraded: [ids], skipped: [ids], latestVersionNo}

On the box routes, POST /api/v1/boxes takes environment (id or name; null = none; absent = your default), env: {K: V} and restricted; PATCH /api/v1/boxes/:id with {env} replaces the per-box vars; GET /api/v1/boxes/:id carries environment: {id, name, versionNo, latestVersionNo}, envVars and restricted.

Errors: 400 invalid_repo, invalid_file, invalid_env_var, invalid_env, too_many_repos, too_many_files, environment_too_large (also from the box create and PATCH), safe_environment_has_secret_files; 404 not_found; 409 name_taken; 409 box_restricted from the mount and phone-access routes.