Agent SkillsAgent Skills
tylertitsworth

uv

@tylertitsworth/uv
tylertitsworth
0
0 forks
Updated 4/1/2026
View on GitHub

uv — fast Python package/project manager, lockfiles, Python versions, uvx tool runner, Docker/CI integration. Use for Python dependency management. NOT for package publishing.

Installation

$npx agent-skills-cli install @tylertitsworth/uv
Claude Code
Cursor
Copilot
Codex
Antigravity

Details

Pathskills/uv/SKILL.md
Branchmain
Scoped Name@tylertitsworth/uv

Usage

After installing, this skill will be available to your AI coding assistant.

Verify installation:

npx agent-skills-cli list

Skill Instructions


name: uv description: "uv — fast Python package/project manager, lockfiles, Python versions, uvx tool runner, Docker/CI integration. Use for Python dependency management. NOT for package publishing."

uv

Ultra-fast Python package and project manager. Replaces pip, pip-tools, virtualenv, pyenv, and pipx in a single binary.

Installation

curl -LsSf https://astral.sh/uv/install.sh | sh   # Standalone (recommended)
pip install uv                                       # Or via pip/pipx/brew

Project Initialization

uv init myproject                    # App (no build system)
uv init --lib mylib                  # Library (src/ layout + build system)
uv init --package myapp              # Packaged app (build system + entry point)
uv init --build-backend hatch mylib  # Specify backend (hatch, flit, pdm, maturin, scikit, uv)

Dependency Management

uv add requests                      # Add to [project.dependencies]
uv add 'httpx>=0.27'                 # With version constraint
uv add --dev pytest ruff             # Add to [dependency-groups] dev
uv add --group test pytest-cov       # Custom dependency group
uv add --optional ml torch           # Add to [project.optional-dependencies]
uv add 'jax; sys_platform == "linux"'  # Platform-specific with markers
uv remove requests                   # Remove dependency
uv add -r requirements.txt          # Import from requirements file

Dependency Sources ([tool.uv.sources])

Sources override where a dependency is fetched during development (ignored by other tools):

[tool.uv.sources]
# Git — supports branch, tag, rev, subdirectory
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.0" }
# Local path — editable by default
mylib = { path = "./libs/mylib", editable = true }
# URL — remote wheel or sdist
special = { url = "https://example.com/special-1.0.0-py3-none-any.whl" }
# Workspace member
shared = { workspace = true }
# Pinned to a specific index
torch = { index = "pytorch" }
# CLI equivalents
uv add git+https://github.com/encode/httpx --tag 0.27.0
uv add httpx --index pytorch=https://download.pytorch.org/whl/cpu

Extras, Markers, and Constraints

[project]
dependencies = [
    "transformers[torch]>=4.39",           # Extras
    "importlib_metadata>=7; python_version < '3.10'",  # Markers
]

[project.optional-dependencies]
gpu = ["torch>=2.0", "triton"]             # Install with: uv sync --extra gpu

[tool.uv]
# Force a version regardless of what dependents request
override-dependencies = ["numpy==1.26.4"]
# Narrow resolution (must be compatible with all requesters)
constraint-dependencies = ["scipy>=1.12"]

Lock and Sync

uv lock                              # Resolve → uv.lock (cross-platform universal)
uv lock --check                      # Exit 1 if lockfile would change (CI validation)
uv sync                              # Install from lockfile into .venv
uv sync --frozen                     # Install without checking/updating lockfile
uv sync --locked                     # Fail if lockfile is out of date
uv sync --no-dev                     # Skip dev dependencies
uv sync --group test --extra gpu     # Include specific groups/extras

Lockfile Internals

uv.lock is a universal lockfile — human-readable TOML, committed to VCS. Key properties:

  • Cross-platform: locks versions for all OS/arch/Python combos simultaneously
  • Resolution forks: when different platforms need different versions, the lockfile contains multiple entries with markers (e.g., numpy 1.26 for Python 3.8, numpy 2.0 for Python 3.12+)
  • Hash checking: each locked package includes hashes for integrity verification
  • Not interoperable: uv.lock is uv-specific; export to requirements.txt or pylock.toml for other tools
uv export --format requirements-txt    # Export for pip/deployers
uv export -o pylock.toml              # PEP 751 format
uv export --no-dev --frozen           # Production export without re-resolving

Resolution

Strategies

[tool.uv]
resolution = "highest"         # Default: latest compatible versions
# resolution = "lowest-direct" # Lowest for direct deps, highest for transitive — good for CI
# resolution = "lowest"        # Lowest for everything — test against lower bounds

When to use each: highest for development. lowest-direct in CI to catch lower-bound incompatibilities in your direct deps without also downgrading transitive deps (which causes noise). lowest for thorough compatibility testing.

Universal Resolution and Platform Control

uv.lock resolves for all platforms by default. Constrain it if you only target specific ones:

[tool.uv]
# Only resolve for Linux and macOS (skip Windows)
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]

# Require wheels exist for specific platforms (fail if not)
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'",
]

Fork Strategy and Multi-Version Resolution

When requires-python spans a wide range (e.g., >=3.8), uv will fork the resolution — selecting the latest version for newer Pythons and older versions for older Pythons. Control this with fork-strategy:

UV_FORK_STRATEGY=fewest uv lock    # Minimize forks (prefer single version)

Upgrading and Pinning

uv lock --upgrade                  # Upgrade everything to latest
uv lock --upgrade-package httpx    # Upgrade just one package
uv add 'httpx>0.1' --upgrade-package httpx  # Change constraint + upgrade

Existing lockfile versions are preferred unless incompatible or --upgrade is specified.

uv run In Depth

uv run auto-syncs the project environment then runs a command. It's more than just activating a venv:

uv run pytest                        # Sync + run in project env
uv run --with rich python script.py  # Add ephemeral dep (not saved to project)
uv run --with 'httpx==0.25' python -c "import httpx"  # Override version ephemerally
uv run --no-project script.py        # Skip project install entirely
uv run --isolated script.py          # Fresh ephemeral env, no project context
uv run --package api-server flask run  # Run in specific workspace member

uv run ensures the env is up-to-date before every invocation. Use UV_NO_SYNC=1 to skip auto-sync. Supports --env-file .env.local for env file loading.

Python Version Management

uv python install 3.12               # Download CPython 3.12
uv python install pypy@3.10          # Install PyPy
uv python list                       # Show available/installed
uv python pin 3.12                   # Write .python-version — uv auto-downloads when needed

Virtual Environments

uv venv                              # Create .venv with project's Python
uv venv --python 3.11 /path/to/env   # Specific version + path

uv auto-manages .venv via uv run/uv sync. Manual activation is optional. Set UV_PROJECT_ENVIRONMENT to override location.

pip Interface / Tool Management

uv pip install -r requirements.txt   # Drop-in pip replacement (10-100x faster)
uv pip install -e '.[dev]'           # Editable install with extras
uv pip compile requirements.in -o requirements.txt  # Pin versions (like pip-tools)
uv pip compile --universal requirements.in           # Cross-platform pins
uv pip sync requirements.txt         # Exact install from lockfile
uvx ruff check .                     # Run CLI tool in ephemeral env (replaces pipx)
uv tool install ruff                 # Install tool persistently

Scripts with Inline Dependencies (PEP 723)

# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx", "rich"]
# ///
import httpx; from rich import print; print(httpx.get("https://httpbin.org/get").json())

uv run script.py auto-installs deps in an isolated env. uv add --script script.py requests injects metadata.

Workspaces (Monorepo)

A workspace shares a single uv.lock across multiple packages:

# Root pyproject.toml
[project]
name = "monorepo"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["shared-lib"]

[tool.uv.sources]
shared-lib = { workspace = true }

[tool.uv.workspace]
members = ["packages/*"]
exclude = ["packages/experimental"]

Virtual Workspace Roots

If the root exists only to aggregate members (no code of its own), omit [project]:

# Root pyproject.toml — virtual root (no [project] table)
[tool.uv.workspace]
members = ["services/*", "libs/*"]

Workspace Behavior

  • Single lockfile: uv lock resolves all members together; uv.lock lives at the root
  • Shared sources: [tool.uv.sources] in root applies to all members (members can override)
  • Editable by default: workspace member deps are installed as editables
  • Single requires-python: the intersection of all members' ranges is enforced
  • Per-package commands: uv run --package api-server flask run

When NOT to Use Workspaces

If members have conflicting requirements (e.g., one needs numpy 1.x, another needs 2.x), use independent projects with path dependencies instead — each gets its own lockfile and venv:

[tool.uv.sources]
shared = { path = "../libs/shared" }   # Not workspace = true

Build System Integration

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

uv supports any PEP 517 backend: hatchling, setuptools, flit-core, pdm-backend, maturin (Rust), scikit-build-core (C++), and its own uv_build.

Build Isolation

By default, uv builds source distributions in isolated environments. Disable when needed:

uv pip install --no-build-isolation -e .    # Uses current env's build deps
UV_NO_BUILD_ISOLATION=1 uv sync            # Useful for editable installs with custom build deps

Build Constraints (Reproducible Builds)

# Pin build dependencies with hash checking
uv build --build-constraint constraints.txt --require-hashes

Cache System

Default location: ~/.cache/uv (Linux), ~/Library/Caches/uv (macOS). Caches registry packages (HTTP headers), git deps (commit hash), built wheels, and local directories (mtime-based).

uv cache dir                         # Show location
uv cache clean                       # Clear everything
uv cache clean numpy                 # Clear just one package
uv cache prune                       # Remove unused/old entries
uv sync --refresh                    # Revalidate all cached data
uv sync --refresh-package numpy      # Revalidate one package

In CI, use astral-sh/setup-uv@v5 with enable-cache: true (GitHub Actions) or cache ~/.cache/uv keyed on uv.lock. For Docker, use --mount=type=cache (see Docker section). The cache is thread-safe.

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true } }]  # Custom invalidation

Docker Integration

Production Multi-Stage Build

FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:0.10.4 /uv /uvx /bin/
ENV UV_COMPILE_BYTECODE=1 UV_NO_INSTALLER_METADATA=1 UV_LINK_MODE=copy
WORKDIR /app

# Layer 1: deps only (cached when pyproject.toml/uv.lock unchanged)
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --locked --no-dev --no-install-project --no-editable

# Layer 2: project code
COPY . .
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked --no-dev --no-editable

# Runtime stage — no uv, no source code
FROM python:3.12-slim
COPY --from=builder /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
CMD ["myapp"]

System Python (Skip Venv)

Set UV_PROJECT_ENVIRONMENT=/usr/local to install directly into system Python, skipping venv creation entirely. Useful for single-app containers where a venv adds no value.

For workspace Dockerfiles, use --frozen for the deps-only layer (can't validate without all member pyproject.toml files), then --locked after full COPY. Use --no-install-workspace instead of --no-install-project.

Private Index Authentication

uv authenticates to private indexes via environment variables derived from the index name:

[[tool.uv.index]]
name = "my-registry"
url = "https://example.com/simple/"
# UV_INDEX_{NAME}_USERNAME / UV_INDEX_{NAME}_PASSWORD
# Name is uppercased, non-alphanumeric → underscore
export UV_INDEX_MY_REGISTRY_USERNAME="user"
export UV_INDEX_MY_REGISTRY_PASSWORD="token"

Also supports .netrc (~/.netrc) and keyring (UV_KEYRING_PROVIDER=subprocess). Pin internal packages to explicit indexes to prevent dependency confusion:

[tool.uv.sources]
my-internal-lib = { index = "my-registry" }

[[tool.uv.index]]
name = "my-registry"
url = "https://example.com/simple/"
explicit = true  # Only pinned packages use this index

Provider Quick Reference

ProviderIndex URLUsernameToken Command
AWS CodeArtifacthttps://<DOMAIN>-<ACCT>.d.codeartifact.<REGION>.amazonaws.com/pypi/<REPO>/simple/awsaws codeartifact get-authorization-token --domain <D> --domain-owner <A> --query authorizationToken --output text
Google Artifact Registryhttps://<REGION>-python.pkg.dev/<PROJECT>/<REPO>/simple/oauth2accesstokengcloud auth print-access-token
JFrog Artifactoryhttps://<ORG>.jfrog.io/artifactory/api/pypi/<REPO>/simple<username> or "" (JWT)API key, identity token, or access token
GitHub Packageshttps://pypi.pkg.github.com/<OWNER>/simple/x-access-tokenPAT with read:packages or GITHUB_TOKEN

Docker Build-Time Auth (Secret Mounts)

Never bake credentials into layers. Use BuildKit secret mounts:

RUN --mount=type=secret,id=uv_env,target=/run/secrets/uv_env \
    --mount=type=cache,target=/root/.cache/uv \
    set -a && . /run/secrets/uv_env && set +a && \
    uv sync --frozen --no-dev --no-install-project
# .uv-secrets (not committed): UV_INDEX_MY_REGISTRY_USERNAME=... UV_INDEX_MY_REGISTRY_PASSWORD=...
docker build --secret id=uv_env,src=.uv-secrets -t myapp .

CI Auth (GitHub Actions)

env:
  UV_INDEX_MY_REGISTRY_USERNAME: ${{ secrets.INDEX_USERNAME }}
  UV_INDEX_MY_REGISTRY_PASSWORD: ${{ secrets.INDEX_PASSWORD }}
steps:
  - uses: astral-sh/setup-uv@v5
    with:
      version: "0.10.4"
      enable-cache: true
  - run: uv sync --locked

For OIDC (AWS, GCP), generate short-lived tokens in a step and export to $GITHUB_ENV. See private index authentication for complete provider configs, keyring setup, Docker .netrc patterns, and OIDC workflows.

CI Patterns

Lockfile Validation

uv lock --check    # Exit 1 if lockfile would change
uv sync --locked   # Exit 1 if lockfile is stale, then install

GitHub Actions

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5
        with:
          version: "0.10.4"
          enable-cache: true
          python-version: ${{ matrix.python-version }}
      - run: uv sync --locked
      - run: uv run pytest

CI Best Practices

  • Pin uv version — exact version, not latest, for reproducibility
  • Cache ~/.cache/uv — keyed on uv.lock checksum
  • Use --locked — fail if lockfile is stale rather than silently re-resolving
  • Run uv lock --check on PRs — catches pyproject.toml changes without lockfile update

Tool Integrations

pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/uv-pre-commit
    rev: 0.10.4
    hooks:
      - id: uv-lock        # Keep lockfile in sync with pyproject.toml
      - id: uv-export      # Keep requirements.txt in sync with uv.lock

tox / nox

Use tox-uv plugin (requires = tox-uv in tox.ini) or venv_backend="uv" in nox sessions for uv-powered environment creation.

Migration from pip/Poetry

From pip + requirements.txt

uv init                              # Creates pyproject.toml
uv add -r requirements.txt          # Import all deps
uv add --dev -r requirements-dev.txt # Import dev deps
# Delete requirements.txt, commit pyproject.toml + uv.lock

From pip-tools (drop-in speedup, no restructuring)

uv pip compile requirements.in -o requirements.txt   # Replaces pip-compile (10-100x faster)
uv pip sync requirements.txt                          # Replaces pip-sync

From Poetry

  1. Rewrite [tool.poetry] → standard [project] (PEP 621)
  2. Convert version constraints: ^1.2>=1.2,<2, ~1.2>=1.2,<1.3
  3. Replace [tool.poetry.group.dev.dependencies][dependency-groups]
  4. Replace [tool.poetry.extras][project.optional-dependencies]
  5. Swap build backend from poetry.core.masonry.api to hatchling/setuptools
  6. Run uv lock (poetry.lock is not importable)

From pipx

uvx ruff check .                     # Ephemeral run (replaces pipx run)
uv tool install ruff                 # Persistent install (replaces pipx install)

See full migration guide for command mappings, version constraint translation, and gotchas. See migration gotchas and environment variables for environment variable reference.

Cross-References

  • docker-buildx — Use uv in Dockerfiles for fast dependency installation
  • github-actions — Install Python dependencies with uv in CI workflows
  • flyte-sdk — Flyte ImageSpec can use uv for faster container builds

References

uv by tylertitsworth | Agent Skills