docs

A small CLI that bootstraps and manages Python projects. One binary, no Python prerequisite — pyr downloads a standalone CPython into ~/.pyr/python on first use and creates a project-local .venv from it.

pyr init myapp        # scaffold a project (downloads python on first run)
cd myapp
pyr run               # python app/main.py
pyr add httpx         # add a dep, resolve, lock, install
pyr remove httpx      # the obvious
pyr sync              # reconcile venv + lock with pyproject.toml
pyr upgrade           # update pyr itself
pyr upgrade --python  # update the managed cpython

Install

macOS / Linux

curl -fsSL https://pyrun.dev/install.sh | sh

The script drops pyr into ~/.pyr/bin/. Add that to your PATH — the installer prints the exact line for your shell.

Windows

In PowerShell:

irm https://pyrun.dev/install.ps1 | iex

This installs pyr.exe into %USERPROFILE%\.pyr\bin\. Add that directory to your user PATH if it isn't already — the installer prints the exact command.

Or, manually: download the latest pyr-windows-x86_64.zip from releases, unzip it, and put pyr.exe somewhere on your PATH.

PYR_HOME overrides where pyr keeps its state and binary; defaults to ~/.pyr (or %USERPROFILE%\.pyr on Windows).

How dependencies work

pyproject.toml [project].dependencies is the source of truth. You write what you want there — either by hand, or via pyr add/pyr remove. requirements.txt is a generated lock file (flat, alpha-sorted, fully pinned, with a # generated by pyr header), produced by pyr sync.

pyproject.toml         requirements.txt
[project]              # generated by pyr 0.1.0; do not edit
dependencies = [       anyio==4.3.0
    "httpx[http2]",    certifi==2024.2.2
]                      h11==0.14.0
                       h2==4.1.0
                       httpcore==1.0.5
                       httpx==0.27.0

pyr add httpx and pyr remove httpx both edit pyproject.toml then call pyr sync under the hood. pyr sync resolves the top-level deps via pip, prunes anything no longer needed, and rewrites the lock. pyr run auto-syncs if pyproject.toml is newer than the lock — so hand-edits to [project].dependencies followed by pyr run Just Work.

Commands

command what it does
pyr init [name] Scaffold a project in ./<name>/ (or cwd). Refuses to overwrite existing content.
pyr run [-- args] Run app/main.py in the venv with PYTHONPATH=.. Args after -- go to python.
pyr add <pkg>... Add packages to pyproject.toml [project].dependencies, then sync.
pyr remove <pkg>... Remove packages from pyproject.toml, then sync.
pyr sync Reconcile the venv and lock with pyproject.toml. Idempotent.
pyr upgrade Update the pyr binary from the latest GitHub release.
pyr upgrade --python Update the managed CPython in ~/.pyr/python.
pyr help [cmd] Top-level usage, or per-command details.

pyr <cmd> --help and pyr help <cmd> are equivalent. To pass a literal --help (or any flag starting with -) to python via pyr run, separate with --: pyr run -- --help.

Project layout

After pyr init myapp:

myapp/
  pyproject.toml         # [project] metadata; you edit dependencies here
  requirements.txt       # generated lock; pyr owns this file
  .gitignore             # python defaults
  app/
    __init__.py
    config.py            # ENV from os.getenv
    main.py              # the entrypoint pyr run executes
  .venv/                 # the project's python environment

How upgrades propagate

pyr upgrade --python swaps out ~/.pyr/python with the latest CPython release. The next time you run pyr run (or any command that touches the venv) in any project, pyr notices the version stamp in .venv/.pyr-python no longer matches and silently rebuilds the venv from the new managed python, reinstalling everything from requirements.txt.

pyr upgrade (no flags) updates the pyr binary itself. The downloaded zip is extracted to a temp dir, size-checked, exec'd to confirm it reports the expected version, then renamed over the running binary.

Requirements

  • macOS / Linux: any reasonably recent x86_64 or aarch64 system. tar and unzip must be on PATH (both are basically always present).
  • Windows 10 1803+: needed for the bundled tar.exe in System32 (used to extract release zips during self-upgrade).