Environments (env)¶
The pyve env namespace manages named environments end to end — creation from the declared recipe, dependency install, execution, inventory, and removal — plus env sync, which reconciles a planned env spec into pyve.toml.
env <subcommand>¶
Manage named environments — dev/test runner envs for tools like ruff, mypy, black, and pytest, plus any other declared [env.<name>]. The default test env lives at .pyve/envs/testenv/venv/. Declare additional named envs in pyve.toml (see Named Environments and Testing → Named test environments). All named envs are preserved across pyve init --force and pyve purge --keep-testenv.
Usage:
pyve env init [<name>] [--force] # Create an env from its declared recipe (default: testenv)
pyve env install [<name>] [-r <file>] [--no-wait] # Install dependencies
pyve env purge [<name>|--all] [--yes] # Remove the default env, one env, or every env
pyve env run [<name> --] <command> [args...] # Run a command in an env
pyve env list # Tabulate every known env
pyve env prune [--unused-since <YYYY-MM-DD>|--all] [--yes] # Remove unused envs
pyve env sync [--yes] [--force] # Reconcile the env spec into pyve.toml
Subcommands:
init [<name>] [--force]: Creates.pyve/envs/<name>/{venv,conda}/and materializes the env's full declared setup recipe in one shot — condamanifestfirst, theneditable,requirements,extra, in that fixed order. No directives declared → an empty env ("init installs what you declared, nothing you didn't").--forceis the one-shot rebuild verb: purge + re-create + re-materialize, with the recorded operational state restored. (rootis rejected here — rebuild the root env withpyve init --force.)install [<name>] [-r <file>] [--no-wait]: No<name>iterates every declared non-lazy env. With<name>installs into one env.-r <file>overrides the declared pip-layer recipe; without any declared recipe, falls back to auto-detectedrequirements-dev.txtor barepytest.--no-waitfast-fails if another pyve process holds the install lock.purge [<name>|--all] [--yes]: Barepyve env purgeremoves the default env — matching its siblings, which assume the default when unnamed.<name>removes one env;--allsweeps every declared env (TTY-prompted;--yesskips the prompt; non-TTY stdin also skips).run [<name> --] <command> [args...]: Executes a command inside an env. With<name>, the--separator disambiguates env name from command. Venv-only — conda-backed envs hard-error with amicromamba run -p <env> <cmd>workaround hint.list: Tabulates the union of declared envs and on-disk envs withNAME / BACKEND / SIZE / LAST-USED / STATEcolumns. STATE is one ofready(recipe installed),realized(on-disk but never installed),lazy,not provisioned,orphaned.prune: Disk-walking removal. Default mode removes orphans (on-disk but not declared);--unused-since <ISO-date>removes envs whose.state.last_used_atis strictly older (envs never used are preserved);--allremoves every on-disk env. Distinct frompurge(which is declaration-driven, walkingpyve.toml).sync [--yes] [--force]: Reconciles the planned environment spec (docs/specs/env-dependencies.md§4, authored byproject-guide mode plan_envs) intopyve.toml: discover → diff →[Y/n]-apply. Writespyve.tomlonly, never materializes. Non-destructive changes default to apply (--yesassents); destructive drops and backend flips default to No —--forceescalates to apply them too. Exit6= spec invalid under the closed vocabulary. See Planning environments with project-guide.
Examples:
# Set up the default testenv
pyve env init
pyve env install -r requirements-dev.txt
# Set up a named env (requires an [env.smoke] declaration in pyve.toml)
pyve env init smoke # materializes smoke's full declared recipe
# Rebuild an env from its declaration (purge + create + install, state restored)
pyve env init smoke --force
# Install every declared non-lazy env in one shot
pyve env install
# Run dev tools from the default testenv
pyve env run ruff check .
pyve env run mypy src/
pyve env run black --check .
# Run a tool in a named env (note the `--` separator)
pyve env run smoke -- pytest -v
# See what's on disk
pyve env list
# Remove envs nobody has used since 2026-01-01
pyve env prune --unused-since 2026-01-01
# Tear down the default env / one env / every declared env
pyve env purge
pyve env purge smoke
pyve env purge --all --yes
# Reconcile the planned env spec into pyve.toml
pyve env sync
Notes:
- Every named env survives
pyve init --forceandpyve purge --keep-testenv; plainpyve purgeremoves them. pyve testis a convenience shortcut that runs pytest inside the resolved env with auto-install support and the silent-skip advisory.- Exit code matches the executed command's exit code (single env) or the worst-case aggregate (
installno-arg iteration /purge --all). - Concurrent
pyve env install <same-env>from two shells serialize via amkdir-based lock in the env's state directory; the holder's PID is inlock/pid.--no-waitfast-fails with a "(pid N)" message instead of queuing.
Legacy flag forms (removed in v2.3.0).
pyve testenv --init, pyve testenv --install, and pyve testenv --purge were delegated-with-warning through v2.2.x and hard-removed in v2.3.0. They now fall through to the dispatcher's unknown-flag path. See the Migration guide for the mapping.
pyve testenv → pyve env
The pyve testenv <sub> namespace is a deprecated alias for pyve env <sub>; it re-dispatches with a one-shot warning and is removed in v4.0. Every example above uses the canonical pyve env form.
See also¶
- Named Environments — the concept guide: purposes, backends, lifecycle policies
- Testing — how
pyve testselects and provisions envs - Project Lifecycle —
init --force --all,upgrade,purge --keep-testenv - Usage Guide — command overview and universal flags