Commands Reference

Complete reference for all appenv commands.

Global Options

./appenv --help

update-lockfile

Update the dependency lockfile (uv.lock). See Locking Behavior for details on UV’s locking model.

./appenv update-lockfile           # Update lockfile
./appenv update-lockfile --diff    # Show changes without writing

Options

Option

Description

--diff

Show full diff without writing lockfile

Use APPENV_VERBOSE=1 for verbose output.

When to Use

  • After changing dependencies in pyproject.toml (add, remove, or update version constraints)

  • Before deploying — ensures the lockfile reflects current requirements

  • When onboarding — run once after cloning to generate uv.lock

See Common Workflows for detailed examples.

init

Create a new pyproject.toml project. Interactive by default; use flags for scripting.

Interactive Mode (default)

Run without flags — init asks five questions:

  1. Binary to expose — creates ./<name> symlink that runs the installed <name> binary (default: app)

  2. Dependencies (one per line, empty line to finish; default: <command name>)

  3. Project name (default: <directory name>)

  4. Description

  5. Minimum Python version (default: 3.13)

Non-Interactive Mode (scripting / CI)

Pass --binary to skip all prompts. --dep is required when creating a new project from scratch. When updating an existing project (Python 3.11+), --dep is optional — existing dependencies are preserved.

# New project  --dep required
appenv init --binary http --dep httpie --dep pytest --name myproject

# Existing project (Python 3.11+)  --binary alone suffices, deps kept as-is
appenv init --binary http

# Existing project  add deps on top of existing ones
appenv init --binary http --dep pytest --dep ruff

Without a TTY and missing required flags, init prints an error with a usage example and exits with code 64 (USAGE).

Options

Flag

Description

path

Target directory for the new project (default: current directory)

--binary NAME

Binary to expose as ./<name> symlink. Required for non-interactive.

--dep PACKAGE

Package dependency. Repeat for multiple: --dep httpie --dep pytest. Required for new projects; optional when updating existing projects (Python 3.11+).

--name NAME

Project name (default: directory name).

--python-version VER

Minimum Python version (default: 3.13).

Updating an Existing Project (Python 3.11+)

When pyproject.toml already has a [project] section and appenv runs on Python 3.11+, init reads the existing values and pre-fills its prompts. Leave fields empty to keep current values, type new ones to change. Dependencies are additive — new entries get appended.

Before — existing pyproject.toml:

[project]
name = "myapp"
version = "0.1.0"
description = "HTTP client"
requires-python = ">=3.11"
dependencies = [
    "httpie>=3.0",
]

Running init:

$ ./appenv init
pyproject.toml already exists — current values shown in [brackets].

Binary to expose (creates ./<name> symlink) [http]:
Enter dependencies (one per line, empty line to finish):
  Current: httpie>=3.0
  Dependency: pytest
  Dependency: ruff
  Dependency:
Project name [myapp]:
Description [HTTP client]: HTTP client with dev tooling
Minimum Python version [3.11]:

After — updated pyproject.toml:

[project]
name = "myapp"
version = "0.1.0"
description = "HTTP client with dev tooling"
requires-python = ">=3.11"
dependencies = [
    "httpie>=3.0",
    "pytest",
    "ruff",
]

Non-interactive mode works the same way: --dep appends to existing dependencies, other flags override.

Existing Project on Python 3.9–3.10

Without tomllib (Python < 3.11), init cannot parse TOML and exits with a suggestion to edit manually:

$ ./appenv init
pyproject.toml already has a [project] section
Nothing to do - edit it manually to make changes

If appenv Script Is Outdated

When the local ./appenv script has a different version than the running appenv, init prints a warning:

Warning: ./appenv is version 0.0.1, running appenv is 2026.3.19.
Run './appenv self-update' to update the script.

migrate

Convert an existing requirements.txt into pyproject.toml. For appenv projects that still use requirements.txt instead of pyproject.toml.

./appenv migrate

Options

  • path — Target directory (default: current directory)

What It Does

  • Reads requirements.txt from the current directory

  • Creates or updates pyproject.toml with those dependencies

  • Generates uv.lock automatically

  • Skips editable installs (-e) with a warning

  • Cleans up old .appenv/ artifacts

  • Updates the local ./appenv script if the running version differs from the one on disk

  • Creates or updates .gitignore with a .venv entry

Running via uvx

If appenv is not yet in your project, you can run migrate directly:

uvx appenv migrate

If appenv is not yet on stable PyPI:

uvx --prerelease allow appenv migrate

This downloads the latest appenv into your project and runs the migration. Run the command from the project directory that contains requirements.txt.

After Migrating

Test it (./http --help), then remove requirements.txt.

See Common Workflows for a full migration walkthrough.

Failure Cases

  • No requirements.txt found — exits normally with a suggestion to use init

  • pyproject.toml already has [project] section — exits normally without changes

self-update

Update the local ./appenv script to match the currently running version.

./appenv self-update

Options

Option

Description

--check

Check for version drift without updating (exit 0 if up-to-date, exit 1 if drift detected)

path

Target directory containing the appenv script (default: project directory)

What It Does

  • Compares the __version__ in the local ./appenv script with the currently running version

  • If versions differ: replaces the script with the running version

  • If versions match: reports that the script is already up-to-date

  • With --check: only reports drift status, does not modify any files

Running via uvx

When running via uvx, appenv runs from an externally managed environment and cannot update itself in place. Specify the target directory:

uvx appenv self-update .
uvx appenv self-update /path/to/project

If appenv is not yet on stable PyPI:

uvx --prerelease allow appenv self-update .

–check Mode

Use --check in CI or scripts to detect version drift:

./appenv self-update --check

Exit codes:

  • 0 — script is up-to-date

  • 1 — version drift detected

Failure Cases

  • No ./appenv script found — prints error, exits with code 67 (NOINPUT)

prepare

Create the virtual environment with production dependencies. Requires an existing uv.lock — run update-lockfile first.

./appenv prepare

What It Does

  • Validates that pyproject.toml and uv.lock exist

  • Creates .appenv/venv with uv venv

  • Installs production dependencies with uv sync --no-dev --frozen

  • Updates .venv symlink to point to .appenv/venv

When to Use

  • CI/CD pipelines that need the venv before running commands

  • Debugging: recreate the venv without removing and rebuilding from scratch

  • Deployment scripts that prepare the environment explicitly

reset

Remove the virtual environment and clean up legacy artifacts.

./appenv reset

What It Removes

  • .venv symlink

  • .appenv/venv directory

  • Old hash-based venvs in .appenv/

What It Preserves

  • Logs in .appenv/logs/

  • Cached uv binary in .appenv/.uv/

  • Profiling data in .appenv/profiling/

  • Version tracking in .appenv/current/

  • pyproject.toml and uv.lock

  • Source code and other project files

Example Usage

# After experiencing issues with the virtual environment
$ ./appenv reset
Removing .venv symlink ...
Removing .appenv/venv ...

# Then recreate it
$ ./appenv prepare

version

Show appenv version.

./appenv version
./appenv --version

python

Start a Python REPL in the virtual environment.

./appenv python                           # Start REPL
./appenv python -c "print('hello')"       # Execute code
./appenv python script.py --verbose       # Run script with args

Details

  • Automatically ensures the virtual environment is prepared (equivalent to running prepare first)

  • Production dependencies only — dev dependencies are excluded

  • For python -m pytest or other dev tool usage, use uv run instead: uv run python -m pytest

Example

$ ./appenv python
Python 3.x.x ...
Type "help", "copyright", "credits" or "license" for more information.
>>>

run

Run a command in the project virtual environment. Equivalent to uv run with appenv’s configured paths.

./appenv run pytest -xvs
./appenv run ruff check .
./appenv run python -c "print('hello')"

All arguments are passed through to uv run unchanged. This is useful for CI or deployment scripts that need to run arbitrary commands in the venv.

Tip: For commands you use frequently, create a symlink instead of typing appenv run every time:

ln -s appenv pytest
ln -s appenv ruff
./pytest -xvs          # equivalent to: appenv run pytest -xvs

See the init command for details on symlink setup.

uv

Pass-through to the uv binary with appenv’s configured environment (Python interpreter, venv paths). Use this when you need uv functionality not covered by dedicated appenv commands.

./appenv uv add requests           # Add production dependency
./appenv uv add --group dev pytest  # Add dev dependency
./appenv uv sync                    # Re-sync dependencies
./appenv uv lock --upgrade          # Upgrade all packages

All arguments are passed through to uv unchanged. See Common Workflows for dependency management examples.

Environment Variables

Variable

Description

APPENV_VERBOSE

Show verbose output (uv commands, Python selection)

APPENV_EXTRAS

Extras to install (comma-separated)

APPENV_BASEDIR

Base directory of the project (auto-set)

APPENV_BEST_PYTHON

Selected Python interpreter (auto-set)

See Common Workflows for verbose mode example.

Exit Codes

appenv uses BSD sysexits.h exit codes:

Code

Name

Description

64

USAGE

Incorrect command usage — unrecognized arguments or self-update from externally managed environment

65

DATAERR

Input data issue (e.g., invalid pyproject.toml)

67

NOINPUT

Missing input file (e.g., no pyproject.toml found)

68

UNAVAILABLE

Resource unavailable (e.g., required tool not found)