CLI Reference¶
Entry Point¶
Installed by pip install ud-resolver as the udr console script (entry point: backend.cli.main:main).
All commands support --help for inline usage and common flags --version, --offline.
Command Dispatch Flow¶
flowchart LR
subgraph INVOCATION["Invocation"]
ARGS["udr <command> [args]"]
PARSER["_build_parser()<br/>argparse with 26 subparsers"]
end
subgraph DISPATCH["Dispatch"]
MAIN["main()"]
DT["dispatch table<br/>cmd name → handler function"]
end
subgraph HANDLER["Command Handler"]
HAND["cmd_*() in commands/*.py"]
CORO["async def inner coroutine"]
RUN["asyncio.run(inner())"]
end
subgraph ORCH["Orchestrator"]
ORCH_LAYER["orchestrator/resolve.py<br/>create_solver() + BFS"]
AGG["core/data_aggregator.py"]
SOLVER["ConflictResolver / PubGrubSolver"]
SS["core/system_scanner.py"]
EXPORT["core/export_generator.py"]
end
ARGS -->|parse_args| PARSER
PARSER -->|args Namespace| MAIN
MAIN -->|args.command| DT
DT -->|function call| HAND
HAND -->|async workflow| CORO
CORO --> RUN
RUN --> ORCH_LAYER
ORCH_LAYER --> AGG
ORCH_LAYER --> SOLVER
ORCH_LAYER --> SS
HAND --> EXPORT
style INVOCATION fill:#1a237e,color:#fff
style DISPATCH fill:#004d40,color:#fff
style HANDLER fill:#e65100,color:#fff
style ORCH fill:#4a148c,color:#fff
classDef box fill:#1a237e,color:#fff
class ARGS,PARSER,MAIN,DT,HAND,CORO,RUN,ORCH_LAYER,AGG,SOLVER,SS,EXPORT box
Global Flags¶
| Flag | Description |
|---|---|
--version |
Print version and exit |
--offline |
Offline mode: use SQLite offline indexes + cached data; no network requests |
Exit Code Summary¶
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (resolution failure, file not found, invalid input, etc.) |
130 |
Cancelled by user (Ctrl+C) |
auth¶
Manage API keys for the UDR server in saas mode, and Ed25519 signing keys for lock file signing.
Requires: Running UDR server with ENABLE_AUTH=true for API-key subcommands.
auth create¶
Generate a new API key.
udr auth create --name my-key --role admin
udr auth create --name ci-token --role read-only --description "Used in GitHub Actions"
| Flag | Default | Description |
|---|---|---|
--name |
cli-generated |
Human-readable name for the key (3-100 chars) |
--role |
read-only |
read-only, read-write, or admin |
--description |
— | Optional description |
auth revoke¶
Revoke an API key by ID.
| Argument | Description |
|---|---|
key_id |
ID of the key to revoke (required, positional integer) |
auth list¶
List all API keys with ID, name, role, active status, last used, and usage count.
auth gen-key¶
Generate an Ed25519 signing key pair for lock file signing. Stored at ~/.config/udr/signing.key.
auth show-key¶
Display the current Ed25519 public signing key.
Exit codes: 0 on success, 1 on failure.
check¶
Scan the current system and display a compatibility report. Can also check lock files for CVEs, license compliance, deprecated packages, peer dependency issues, or policy compliance.
Usage:
udr check # basic system info table
udr check -v # verbose (CPU arch, all runtimes)
udr check --deps # also show project's core deps
udr check --json # raw JSON output, then exit
udr check --cuda 12.1 # simulate for specific CUDA version
udr check --device rocm # simulate for AMD ROCm device
udr check --cve # check lock file for known CVEs
udr check --license # check lock file for license compliance
udr check --deprecated # check lock file for deprecated/yanked packages
udr check --peer # check lock file for peer dependency issues
udr check --policy # check policy compliance (udr-policy.yaml)
udr check --cve --license --deprecated # run multiple checks in one invocation
Check flags are combinable — each selected check runs, its verdict is AND-ed into the exit code, and in --json mode each check's payload is grouped under its name ({"ok": true, "cve": {...}, "license": {...}}).
| Flag | Default | Description |
|---|---|---|
-v, --verbose |
False |
Show CPU architecture, runtime versions table |
--deps |
False |
Show project core dependencies (from pyproject.toml) |
--json |
False |
Output as JSON to stdout, then exit |
--cuda |
None |
Target CUDA version string (e.g. 12.1, 11.8) — selects +cu<ver> package variants when available, and restricts pytorch-family packages to base versions shipped on the matching pytorch index tag (e.g. cu121 → torch ≤ 2.5.1); otherwise the request is informational (CUDA encoded in nvidia dep names) |
--device |
None |
Target compute device: cpu, cuda, mps, rocm |
--cve |
False |
Check lock file packages against OSV vulnerability database |
--license |
False |
Check lock file for license compliance |
--deprecated |
False |
Check lock file for deprecated or yanked packages |
--peer |
False |
Check lock file for peer dependency issues |
--policy, -p |
None |
Path to policy YAML file (default: ./udr-policy.yaml) |
-d, --directory |
. |
Project directory with lock file |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path (overrides directory/workspace) |
Exit codes:
- 0 — all selected checks passed (system report; CVE findings are informational and do not fail the exit code)
- 1 — any selected check reported a violation (denied license, yanked package, error-severity policy violation), lock file missing, or fetch failure — also in --json mode
completion¶
Generate shell completion scripts for bash, zsh, or fish.
udr completion # auto-detect shell (requires shellingham)
udr completion bash # bash completions
udr completion zsh # zsh completions
udr completion fish # fish completions
Installing completions:
# bash — source in ~/.bashrc
udr completion bash > /etc/bash_completion.d/udr
# zsh — save to a directory in $fpath
udr completion zsh > /usr/local/share/zsh/site-functions/_udr
# fish
udr completion fish > ~/.config/fish/completions/udr.fish
| Argument | Default | Description |
|---|---|---|
shell |
auto |
Shell to target: bash, zsh, fish (auto-detected via shellingham if omitted) |
Exit codes: 0 on success, 1 on unsupported shell.
details¶
Show detailed package information — description, latest version, total version count, dependencies.
udr details numpy # PyPI (default ecosystem)
udr details react -e npm # npm ecosystem
udr details serde -e crates --json # JSON output
| Flag | Default | Description |
|---|---|---|
package |
(required) | Package name |
-e, --ecosystem |
pypi |
Ecosystem identifier |
--json |
False |
Output as JSON |
Exit codes: 0 on success, 1 on not found or fetch failure.
versions¶
List all available versions of a package, newest first.
| Flag | Default | Description |
|---|---|---|
package |
(required) | Package name |
-e, --ecosystem |
pypi |
Ecosystem identifier |
--json |
False |
Output as JSON {"package", "ecosystem", "versions": [...]} |
Exit codes: 0 on success, 1 on package not found ({"error": "No versions found"} in JSON mode).
dependencies¶
Show a package's dependencies and their constraints.
udr dependencies flask # PyPI (default ecosystem)
udr dependencies express -e npm --json # JSON output
| Flag | Default | Description |
|---|---|---|
package |
(required) | Package name |
-e, --ecosystem |
pypi |
Ecosystem identifier |
--json |
False |
Output as JSON {"package", "ecosystem", "dependencies": {name: constraint}} |
Exit codes: 0 on success, 1 on fetch failure. A package with no dependencies is a valid success.
diff¶
Compare two lock files and show version differences (added, removed, changed, unchanged).
udr diff old.lock new.lock # compare two explicit lock files
udr diff old.lock new.lock --json # JSON output
udr diff --workspace backend # compare udr.lock vs udr-backend.lock
| Argument/Flag | Default | Description |
|---|---|---|
lock_file_a |
None |
First lock file path (positional, optional with --workspace) |
lock_file_b |
None |
Second lock file path (positional, optional with --workspace) |
--json |
False |
Output as JSON |
-d, --directory |
. |
Project directory containing lock files |
--workspace |
None |
Compare base lock vs udr-{workspace}.lock |
Exit codes: 0 on success, 1 on read error or missing arguments. In --json mode errors are emitted as {"error": "..."} on stdout (exit 1) so JSON consumers always parse a valid document.
export¶
Export a lock file to a specific format.
udr export # default: requirements.txt
udr export --format requirements.txt # pip freeze style
udr export --format Dockerfile # Dockerfile with pip install
udr export --output /tmp/deps.txt # write to file
udr export --workspace backend # export from workspace lock
udr export -l /path/to/lock.json # explicit lock file
| Flag | Default | Description |
|---|---|---|
-d, --directory |
. |
Project directory with lock file |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path |
-f, --format |
requirements.txt |
Export format identifier |
-o, --output |
None |
Output file path (default: print to stdout) |
Exit codes: 0 on success, 1 on failure.
graph¶
Display a dependency tree for one or more packages, showing direct and transitive dependencies. With no package arguments (or with --from-lock), renders nested trees from an existing udr.lock — fully offline.
udr graph flask django # PyPI packages
udr graph numpy@pypi serde@crates # mixed ecosystems
udr graph react -e npm # npm packages
udr graph torch --cuda 12.1 # with CUDA variant selection (if published)
udr graph torch --json # JSON output
udr graph # nested trees from udr.lock in cwd (no network)
udr graph --from-lock -d /path/to/project # trees from a specific project's lock file
udr graph --from-lock --json # JSON trees
| Flag | Default | Description |
|---|---|---|
packages |
(optional) | One or more package names with optional @ecosystem suffix. Omitted → tree from existing lock file |
--from-lock |
False |
Build nested dependency trees from an existing lock file (no registry access). Roots are packages with direct: true; falls back to all packages when the lock predates that field |
-d, --directory |
. |
Project directory with lock file (used with --from-lock) |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path |
-e, --ecosystem |
pypi |
Default ecosystem for packages without @ecosystem suffix |
--json |
False |
Output as JSON. Live resolution: flat resolved_packages map. From lock: {"status": "success", "source": "<lock path>", "trees": [{name, version, ecosystem, children}]} |
--cuda |
None |
Target CUDA version (e.g. 12.1) — auto-detected if omitted. Selects a +cu<ver> variant when the package publishes one (e.g. pytorch's own index). For PyPI torch, the CUDA build is chosen by consulting the pytorch wheel index: the resolver caps torch to the version ceiling of the requested tag and rewrites it to its +cu<ver> local version (e.g. --cuda 12.1 → 2.5.1+cu121) |
--device |
None |
Target compute device: cpu, cuda, mps, rocm |
Exit codes: 0 on success, 1 on resolution failure or lock file error (missing/invalid lock, empty packages).
index¶
Manage offline SQLite indexes for local package resolution. Indexes stored at ~/.cache/udr/indexes/{ecosystem}.db.
index pull¶
Download pre-built SQLite indexes from a remote URL.
udr index pull https://indexes.udr.dev # pull all available indexes
udr index pull https://indexes.udr.dev -e pypi # single ecosystem
| Flag | Default | Description |
|---|---|---|
url |
(required) | Base URL for index download (expects index.json + {eco}.db files) |
-e, --ecosystem |
None |
Only pull index for this ecosystem |
index build¶
Build an offline SQLite index from resolved packages in udr.lock or a comma-separated package list.
udr index build # build from udr.lock in cwd
udr index build -d /path/to/project # build from lock file in project
udr index build --packages flask,requests # build index for specific packages
udr index build --packages react -e npm # build index for npm packages
| Flag | Default | Description |
|---|---|---|
--packages |
"" |
Comma-separated package names to index (uses --ecosystem) |
-e, --ecosystem |
pypi |
Ecosystem for --packages |
-d, --directory |
cwd | Directory containing udr.lock |
index status¶
Show which ecosystems have local indexes available, with package and version counts.
| Flag | Default | Description |
|---|---|---|
--json |
False |
Output as JSON |
index sync¶
Sync local indexes from remote registries.
| Flag | Default | Description |
|---|---|---|
-e, --ecosystem |
None |
Ecosystem to sync |
-a, --all |
False |
Sync all supported ecosystems |
Hosting your own pre-built index¶
index pull downloads {url}/index.json (manifest) plus {url}/{ecosystem}.db files. Both are produced by udr index build, so hosting is a two-step workflow:
- Build:
udr index build -d /path/to/projectwrites~/.cache/udr/indexes/{ecosystem}.dbplus anindex.jsonmanifest ({"ecosystems": [...]}). - Serve: copy the
.dbfiles +index.jsonto any static host (nginx, S3, GitHub Pages,python3 -m http.server). The manifest format is:
Consumers then run udr index pull https://your-host/indexes (all ecosystems listed in the manifest) or udr index pull https://your-host/indexes -e pypi (single ecosystem). The format/version fields are metadata for the manifest; the puller only uses the ecosystems list.
Exit codes: 0 on success, 1 on failure.
init¶
Initialize a new project with UDR configuration files.
udr init # auto-detect project type
udr init -t python-requirements # Python requirements project
udr init -t python-pyproject # Python pyproject.toml project
udr init -t node # Node.js project
udr init -t go # Go project
udr init -t rust # Rust project
udr init --with-config # also create udr.json config
udr init --gitignore # also create .gitignore
udr init --lock # run initial lock after init
| Flag | Default | Description |
|---|---|---|
-t, --template |
auto |
Project template: python-requirements, python-pyproject, node, go, rust |
-n, --name |
None |
Project name (defaults to directory name) |
-d, --directory |
. |
Project directory |
-f, --force |
False |
Overwrite existing files |
--with-config |
False |
Create udr.json configuration file |
--gitignore |
False |
Create .gitignore with UDR entries |
--lock |
False |
Run initial resolution after initialization |
Exit codes: 0 on success, 1 on failure.
install¶
Install direct dependencies from the lock file using their native package managers.
udr install # install all direct deps
udr install -d /path/to/project # specific project directory
udr install --lock-file path/to/lock.json # custom lock file path
udr install --workspace backend # install from udr-backend.lock
udr install -e npm # only install npm packages
udr install --dry-run # show install commands without executing
udr install -y # skip confirmation prompt
udr install --production # skip dev dependencies
udr install --restore # restore mode (all direct + transitive deps)
| Flag | Default | Description |
|---|---|---|
-d, --directory |
. |
Project directory containing lock file |
-l, --lock-file |
None |
Path to lock file |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-e, --ecosystem |
None |
Only install packages from this ecosystem; all ecosystems if omitted |
-n, --dry-run |
False |
Show install commands without executing them |
-y, --yes |
False |
Skip confirmation prompt |
--restore |
False |
Restore mode — install all packages (direct + transitive) |
--production |
False |
Skip dev dependencies |
--cuda |
None |
CUDA version to target (e.g. 12.1) |
--target |
None |
Target OS: linux, windows, darwin |
--platform |
None |
Target CPU arch: x86_64, aarch64, arm64, i386, amd64 |
Ecosystem installers used:
| Ecosystem | Command |
|---|---|
pypi |
pip install pkg==ver |
npm |
npm install pkg@ver |
crates |
cargo add pkg@ver |
gomodules |
go get pkg@ver |
conda |
conda install pkg==ver |
rubygems |
gem install pkg==ver |
packagist |
composer require pkg==ver |
pub |
dart pub add pkg:ver |
nuget |
dotnet add package pkg --version ver |
cocoapods |
pod install (uses Podfile) |
maven |
mvn dependency:copy-dependencies |
homebrew |
brew install pkg |
hex |
mix deps.update pkg |
swift |
swift package resolve |
Exit codes: 0 on success, 1 on failure.
list-ecosystems¶
List all supported package ecosystems with display names and capabilities.
| Flag | Default | Description |
|---|---|---|
--json |
False |
Output as JSON array |
Exit codes: 0 always.
lock¶
Auto-detect dependency manifests in a project directory, fetch metadata for all packages, scan the system, run SAT resolution, and write a udr.lock file.
Usage:
udr lock # current directory
udr lock -d /path/to/project # specific project
udr lock -m requirements.txt # only process one manifest
udr lock --dry-run # preview without writing
udr lock -y # skip confirmation prompts
udr lock -i # interactive manifest selection
udr lock --json # output lock data as JSON to stdout
udr lock -r # write readable report file
udr lock --cuda 12.1 # target CUDA 12.1 (variant-aware)
udr lock --target linux --platform x86_64 # cross-compilation for linux/amd64
udr lock --sign # sign lock file with Ed25519 key
udr lock --provenance # add SLSA provenance section
udr lock --check # CI drift detection (exit 1 if out of date)
udr lock --auto-sync # auto-sync stale local indexes
udr lock --export Dockerfile # also export resolved deps
Flags:
| Flag | Default | Description |
|---|---|---|
-d, --directory |
. |
Project root directory to scan |
-m, --manifest |
None |
Only process a specific manifest file; all manifests if omitted |
--export |
None |
Export resolved deps to a format (e.g. Dockerfile, requirements.txt) |
-y, --yes |
False |
Update manifests in-place without prompting |
--dry-run |
False |
Run resolution and show results but don't write any files |
-i, --interactive |
False |
Select manifests manually + resolve conflicts interactively |
--cuda |
None |
Target CUDA version (e.g. 12.1, 11.8) — selects +cu<ver> package variants when the registry publishes them, and caps pytorch-family packages (torch/torchvision/torchaudio/triton) to the base versions shipped on the matching pytorch index tag |
--device |
None |
Target compute device: cpu, cuda, mps, rocm. Note: --device cpu requests a CPU-only graph — but PyPI torch (2.x+) ships a single combined wheel whose metadata hard-requires nvidia-*-cuXX deps, so those still appear unless a CPU-only index is configured (e.g. download.pytorch.org/whl/cpu) |
--json |
False |
Output lock data as JSON to stdout instead of writing file |
-r, --report |
False |
Write readable report file (udr.report.txt) alongside lock file |
--include-dev |
False |
Include manifests from examples, test, docs directories |
--timeout |
None |
Resolution timeout in seconds (default: 120 from SOLVER_TIMEOUT) |
--extras |
None |
Comma-separated extras groups to activate (e.g. dotenv,speedups) |
--pin |
None |
Pin a package to an exact version (name==version). Repeatable. |
--pin-mode |
none |
Global pinning strategy: none, patch, minor, exact |
--block |
None |
Block a package from resolution. Repeatable. |
--freeze |
False |
Freeze all packages at their lock-file versions |
--workspace |
None |
Workspace name for monorepo support — lock file becomes udr-{workspace}.lock |
--prefix |
None |
Prefix package names in lock file (e.g. backend/ for monorepo scoping) |
--force, -f |
False |
Force full re-resolution, ignoring existing lock file cache |
--target |
None |
Target OS for cross-compilation: linux, windows, darwin |
--platform |
None |
Target CPU architecture: x86_64, aarch64, arm64, i386, amd64 |
--auto-sync |
False |
Auto-sync stale local indexes before resolution |
--sign |
False |
Sign the lock file with Ed25519 key |
--provenance |
False |
Add SLSA provenance section to lock file |
--check, -c |
False |
CI mode: run resolution and diff against existing lock; exit 1 on drift |
--with-dev |
False |
Include dev/optional dependency manifests |
--without-optional |
False |
Exclude optional dependencies (default: optional deps excluded, use --with-dev) |
Pipeline steps:
- Detect manifests — scan directory for recognized dependency files
- Parse packages — extract name, ecosystem, constraint from each manifest
- Fetch metadata — query registry APIs for versions, dependencies, system requirements
- Scan system — detect OS, CPU, GPU, CUDA, Python, runtimes
- Resolve — SAT solver finds compatible versions across all packages and ecosystems
- Lock — write
udr.lock - Report/export — optional report file and export generation
- Sign/provenance — optional Ed25519 signing and SLSA metadata
- Update manifests — optionally pin resolved versions in original manifest files
Lock file structure (udr.lock):
{
"version": "2.1",
"generated_at": "2026-07-05T12:00:00",
"resolver": "sat",
"system": {
"os": "Linux 6.2.0",
"python": "3.11.5",
"cpu": "Intel(R) Xeon(R)",
"gpu": "NVIDIA A100",
"cuda": "12.1"
},
"manifests": ["requirements.txt"],
"packages": {
"torch": {
"name": "torch",
"ecosystem": "pypi",
"resolved_version": "2.1.2+cu121",
"direct": true,
"cuda_variant": true,
"cuda_version": "121",
"original_constraint": ">=2.0",
"source": "requirements.txt",
"resolution_hash": "abc123def456",
"deprecated": false,
"yanked": false,
"integrity": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"depends_on": {
"pypi": {
"sympy": ">=1.0",
"jinja2": ">=2.0"
}
}
}
},
"warnings": []
}
Recognized manifests and lock files:
| File | Ecosystem | Type |
|---|---|---|
requirements.txt, requirements.in, *-requirements.txt |
pypi | Manifest |
Pipfile |
pypi | Manifest |
pyproject.toml |
pypi | Manifest |
setup.py |
pypi | Manifest |
setup.cfg |
pypi | Manifest |
Pipfile.lock |
pypi | Lock |
poetry.lock |
pypi | Lock |
uv.lock |
pypi | Lock |
package.json |
npm | Manifest |
package-lock.json |
npm | Lock |
yarn.lock |
npm | Lock |
pnpm-lock.yaml |
npm | Lock |
Cargo.toml |
crates | Manifest |
Cargo.lock |
crates | Lock |
go.mod |
gomodules | Manifest |
go.sum |
gomodules | Lock (version source) |
environment.yml, environment.yaml |
conda | Manifest |
Gemfile |
rubygems | Manifest |
Gemfile.lock |
rubygems | Lock |
composer.json |
packagist | Manifest |
composer.lock |
packagist | Lock |
pubspec.yaml |
pub | Manifest |
build.gradle, build.gradle.kts |
gradle | Manifest |
Package.swift |
swift | Manifest |
Package.resolved |
swift | Lock |
mix.exs |
hex | Manifest |
mix.lock |
hex | Lock |
*.cabal, cabal.project, stack.yaml |
haskell | Manifest |
pom.xml |
maven | Manifest |
Podfile, Podfile.lock |
cocoapods | Manifest |
packages.config |
nuget | Manifest |
Brewfile, Brewfile.lock.json |
homebrew | Manifest |
apt-packages.txt |
apt | Manifest |
apk-packages.txt |
apk | Manifest |
default.nix, shell.nix, flake.nix, flake.lock |
nix | Manifest |
guix.scm, manifest.scm |
guix | Manifest |
udr.lock |
— | Self (UDR lock file) |
Exit codes: 0 on success, 1 on failure, 130 on user cancel.
migrate¶
Migrate existing lock files to udr.lock. Supports 25 source lock file formats.
Supported source formats: package-lock.json, Cargo.lock, poetry.lock, uv.lock, go.sum, Gemfile.lock, composer.lock, mix.lock, Package.resolved, yarn.lock, pnpm-lock.yaml, Brewfile.lock.json, Podfile.lock, Pipfile.lock.
udr migrate # auto-detect and migrate
udr migrate --display # preview only (no write)
udr migrate --force # overwrite existing udr.lock
udr migrate -d /path/to/project # specific project
udr migrate -e pypi # override detected ecosystem
| Flag | Default | Description |
|---|---|---|
-d, --directory |
. |
Project directory |
-e, --ecosystem |
None |
Override detected ecosystem for all packages |
-f, --force |
False |
Overwrite existing udr.lock |
-y, --yes |
False |
Skip confirmation prompt |
--display |
False |
Preview only — don't write lock file |
Exit codes: 0 on success, 1 on failure.
outdated¶
List packages with newer versions available in their respective registries.
udr outdated # check all packages in current project
udr outdated -d /path/to/project # specific project
udr outdated --json # JSON output
udr outdated -e npm # only check npm packages
udr outdated --workspace backend # check udr-backend.lock
udr outdated -l /path/to/lock.json # explicit lock file
| Flag | Default | Description |
|---|---|---|
-d, --directory |
. |
Project directory with lock file |
--json |
False |
Output as JSON: {"status": "success", "outdated_count": N, "packages": [{name, ecosystem, current, latest, type}]} — same shape as POST /outdated |
-e, --ecosystem |
None |
Only check packages from this ecosystem; all ecosystems if omitted |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path |
Exit codes: 0 when all packages are up to date, 1 when outdated packages were found (both table and --json modes) or on error.
resolve¶
Resolve compatible versions for one or more packages from any ecosystem.
udr resolve numpy pandas scikit-learn # PyPI (default ecosystem)
udr resolve react vue -e npm # npm ecosystem
udr resolve serde tokio -e crates # Cargo ecosystem
udr resolve flask django --format json # JSON output
udr resolve torch --interactive # manual conflict resolution
udr resolve numpy@pypi express@npm # mixed ecosystems
| Flag | Default | Description |
|---|---|---|
packages |
(required) | One or more package names. Use pkg@eco syntax for non-default ecosystems |
-e, --ecosystem |
pypi |
Default ecosystem for packages without @ecosystem suffix |
-f, --format |
text |
Output format: text (rich table) or json |
--json |
False |
Output as JSON (shorthand for --format json) |
-i, --interactive |
False |
If SAT solver reports unsatisfiable, enter manual resolution mode |
--cuda |
None |
Target CUDA version (e.g. 12.1, 11.8) |
--device |
None |
Target compute device: cpu, cuda, mps, rocm |
--timeout |
None |
Resolution timeout in seconds (default: 120 from SOLVER_TIMEOUT) |
--extras |
None |
Comma-separated extras groups to activate (e.g. dotenv,speedups) |
--pin |
None |
Pin a package to an exact version (name==version). Repeatable. |
--pin-mode |
none |
Global pinning strategy: none, patch, minor, exact |
--block |
None |
Block a package from resolution. Repeatable. |
--freeze |
False |
Freeze all packages at their lock-file versions |
--target |
None |
Target OS for cross-compilation: linux, windows, darwin |
--platform |
None |
Target CPU architecture: x86_64, aarch64, arm64, i386, amd64 |
--auto-sync |
False |
Auto-sync stale local indexes before resolution |
--with-dev |
False |
Include dev/optional dependency manifests |
--without-optional |
False |
Exclude optional dependencies (default: optional deps excluded, use --with-dev) |
Exit codes: 0 on success, 1 on resolution failure, 130 on user cancel.
sbom¶
Generate a Software Bill of Materials from the lock file in SPDX 2.3 or CycloneDX 1.5 format.
udr sbom # SPDX 2.3 JSON to stdout
udr sbom --format cyclonedx # CycloneDX 1.5 format
udr sbom --output sbom.json # write to file
udr sbom --workspace backend # lock file from workspace
udr sbom --lock-file /path/to/udr.lock # explicit lock file
| Flag | Default | Description |
|---|---|---|
-d, --directory |
. |
Project directory with lock file |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path |
-f, --format |
spdx |
SBOM format: spdx (SPDX 2.3) or cyclonedx (CycloneDX 1.5) |
-o, --output |
None |
Output file path (default: print to stdout) |
Exit codes: 0 on success, 1 on failure.
scan¶
Scan a remote GitHub repository or a local directory — same pipeline as lock without needing to clone manually or change directories.
udr scan --github https://github.com/user/repo # scan remote repo
udr scan --github https://github.com/user/repo --branch develop
udr scan --directory /path/to/project # scan local path
udr scan --github https://github.com/user/repo --cuda 12.1
udr scan --github https://github.com/user/repo -y --export Dockerfile
| Flag | Default | Description |
|---|---|---|
--github |
None |
GitHub repository URL (e.g. https://github.com/user/repo) |
--branch |
main |
Git branch to scan (only with --github) |
--directory |
None |
Local project directory path |
-m, --manifest |
None |
Only process a specific manifest file |
-y, --yes |
False |
Update manifests without prompting |
--export |
None |
Export resolved deps to a format (e.g. Dockerfile) |
--json |
False |
Output lock data as JSON |
--cuda |
None |
Target CUDA version — auto-detected if omitted |
--device |
None |
Target compute device: cpu, cuda, mps, rocm |
--dry-run |
False |
Preview without writing files |
-i, --interactive |
False |
Interactive manifest selection + conflict resolution |
Exit codes: 0 on success, 1 on failure, 130 on user cancel.
search¶
Search for packages across ecosystems in registries.
udr search numpy # search all ecosystems
udr search numpy --ecosystems pypi # search only pypi
udr search numpy --json # JSON output
udr search numpy --limit 50 # max results per ecosystem
| Flag | Default | Description |
|---|---|---|
query |
(required) | Search query string |
--ecosystems |
None |
Comma-separated ecosystems to search (e.g. pypi,npm); all if omitted |
--limit |
20 |
Max results per ecosystem (1–100) |
--json |
False |
Output as JSON |
Exit codes: 0 on success, 1 on no results or error.
serve¶
Start the REST API server (FastAPI + uvicorn). Also serves the web frontend (vanilla JS SPA with 8 pages) at the root URL (/), with API under /api/v1.
udr serve # http://127.0.0.1:8000, local mode
udr serve --host 0.0.0.0 # bind all network interfaces
udr serve --port 9000 # custom port
udr serve --reload # auto-reload on file changes (dev only)
udr serve --mode saas # enable full auth stack (JWT, rate limiting)
udr serve --log-level debug # verbose logging
udr serve --workers 4 # multiple worker processes
udr serve --ssl-keyfile key.pem --ssl-certfile cert.pem # HTTPS
| Flag | Default | Description |
|---|---|---|
--host |
127.0.0.1 |
Bind address |
--port |
8000 |
Bind port |
--reload |
False |
Enable hot-reload for development |
--mode |
local |
local (no auth) or saas (JWT auth, rate limiting) |
--log-level |
info |
Uvicorn log level: debug, info, warning, error, critical |
--workers |
None |
Number of worker processes (auto-detected if omitted) |
--ssl-keyfile |
None |
SSL key file path for HTTPS |
--ssl-certfile |
None |
SSL certificate file path for HTTPS |
Environment variables for run-time tuning:
| Variable | Default | Description |
|---|---|---|
SOLVER_TIMEOUT |
120 |
Total seconds for BFS+SAT resolution |
SOLVER_API_TIMEOUT |
60 |
Resolution timeout for API endpoints (seconds) |
CACHE_TTL |
3600 |
Default cache TTL in seconds |
CACHE_TTL_SHORT |
300 |
Cache TTL for rate-limited endpoints |
CACHE_TTL_VERSIONS |
600 |
Cache TTL for version listings |
SCANNER_MAX_WORKERS |
10 |
Thread pool workers for system scanning |
NPM_CONCURRENCY |
10 |
Concurrent npm API requests |
GOMODULES_CONCURRENCY |
20 |
Concurrent Go module proxy requests |
BFS_BATCH_SIZE |
20 |
Batch size for BFS dependency discovery |
USE_PUBGRUB_SOLVER |
false |
Use PubGrub solver instead of Z3 |
USE_Z3_OPTIMIZE |
false |
Enable Z3 optimization (prefers latest versions) |
PIN_INTEGRITY |
false |
Verify integrity hashes during lock operations |
SOLVER_REJECT_DEPRECATED |
false |
Reject deprecated/yanked packages in resolution |
SOLVER_MAX_VARIABLES |
50000 |
Maximum SAT variables before solver gives up |
Exit codes: 0 on clean shutdown, 1 on server error.
system-info¶
Show detailed system information — OS, CPU, GPU, Python, runtimes, accelerators.
| Flag | Default | Description |
|---|---|---|
--json |
False |
Output as JSON |
Exit codes: 0 on success, 1 on scan failure.
tools¶
Manage plugins and extensions.
tools register-plugin¶
Register a local plugin directory.
udr tools register-plugin --path ./my-plugin
udr tools register-plugin --path ./my-plugin --name my-plugin
| Flag | Required | Default | Description |
|---|---|---|---|
--path |
Yes | — | Directory path containing plugin Python files |
--name |
No | None |
Optional name tag for the plugin group |
Exit codes: 0 on success, 1 on failure.
update¶
Re-resolve a single package and update its entry in the lock file. Can also auto-fix vulnerable packages.
udr update flask # re-resolve flask in current project
udr update flask -d /path/to/project # specific project
udr update flask -i # interactive conflict resolution
udr update torch --cuda 12.1 # update with CUDA override
udr update flask --dry-run # preview changes without writing
udr update flask --workspace backend # update in udr-backend.lock
udr update flask -l /path/to/lock.json # update in explicit lock file
udr update --all # bulk-update every direct package
udr update --all --dry-run # preview bulk-update without writing
udr update --fix-cve # auto-fix all vulnerable packages
udr update flask --fix-cve # auto-fix specific vulnerable package
| Flag | Default | Description |
|---|---|---|
package |
None |
Package name to re-resolve (optional with --all/--fix-cve) |
--all |
False |
Bulk-update every direct package in the lock file to the newest version within its constraints. Recomputes each package's resolution hash. Conflicts with a package name. Transitive deps update implicitly when their parents change |
-d, --directory |
. |
Project directory with lock file |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path |
-i, --interactive |
False |
Interactive conflict resolution |
--dry-run |
False |
Show what would be updated without modifying the lock file |
--cuda |
None |
Target CUDA version — auto-detected if omitted |
--device |
None |
Target compute device: cpu, cuda, mps, rocm |
--target |
None |
Target OS for cross-compilation: linux, windows, darwin |
--platform |
None |
Target CPU architecture: x86_64, aarch64, arm64, i386, amd64 |
--timeout |
None |
Resolution timeout in seconds |
--fix-cve |
False |
Update vulnerable packages to versions that fix known CVEs |
--with-dev |
False |
Include dev/optional dependency manifests |
--without-optional |
False |
Exclude optional dependencies (default: optional deps excluded, use --with-dev) |
Exit codes: 0 on success, 1 on package not found or resolution failure, 130 on user cancel.
verify¶
Validate a lock file — checks that every pinned version still exists in its respective package registry.
udr verify # auto-detects lock file in current dir
udr verify --workspace backend # verify udr-backend.lock
udr verify path/to/custom-lock.json # specific lock file
udr verify --signature # verify Ed25519 signature on lock file
| Argument/Flag | Default | Description |
|---|---|---|
lock_file |
None |
Path to lock file (positional, optional) |
--json |
False |
Output as JSON |
-d, --directory |
. |
Project directory with lock file |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
--signature, --sig |
False |
Verify Ed25519 signature on the lock file |
Exit codes: 0 on success (all versions verified), 1 on issues found.
why¶
Explain why a package version was selected — show dependency chain from the lock file.
udr why flask # explain flask version in current project
udr why flask -d /path/to/project # specific project
udr why flask --json # JSON output
udr why --all # explain all packages
udr why --all --json # all packages as JSON array
udr why --workspace backend # use udr-backend.lock
udr why flask -l /path/to/lock.json # explicit lock file
| Flag | Default | Description |
|---|---|---|
package |
None |
Package name to explain (optional with --all) |
-a, --all |
False |
Show info for all packages |
-d, --directory |
. |
Project directory with lock file |
--json |
False |
Output as JSON |
--workspace |
None |
Workspace name — lock file becomes udr-{workspace}.lock |
-l, --lock-file |
None |
Explicit lock file path |
Exit codes: 0 on success, 1 on package not found.
Package Spec Syntax¶
Use name@ecosystem to specify which ecosystem a package belongs to:
| Spec | Package | Ecosystem |
|---|---|---|
numpy |
numpy | pypi (default) |
numpy@pypi |
numpy | pypi |
@angular/core@npm |
@angular/core | npm |
express@npm |
express | npm |
serde@crates |
serde | crates |
torch@pypi |
torch | pypi |
The @ delimiter splits on the last @ so scoped npm packages (@angular/core) work correctly.
CUDA / GPU Handling¶
The resolver is GPU-aware for PyPI packages. When a package has CUDA-tagged variants (e.g. torch 2.1.2+cu121), the tool selects the best match based on the system's CUDA version.
For pytorch-family packages (torch, torchvision, torchaudio, triton, etc.) the PyPI release has no +cu labels — its CUDA is baked into nvidia-*-cu<ver> dependency names. The actual per-CUDA builds live on the pytorch wheel index. When a CUDA version is requested, the resolver consults that index for the matching tag (e.g. cu121) and:
1. Caps the package to the highest base version that ships a wheel for that tag (the cu121 tag carries torch only up to 2.5.1, while cu128 goes to 2.11.0), and
2. Rewrites the resolved version to its +cu<ver> form (e.g. 2.5.1+cu121).
This is what makes --cuda 12.1 produce a genuinely CUDA-12.1 torch rather than the newest PyPI build.
Auto-detection¶
The system scanner detects CUDA via:
1. pynvml (NVIDIA Management Library) — most reliable
2. nvcc --version — compiler version
3. nvidia-smi — driver-reported CUDA version
If none work, CUDA is reported as unavailable.
Resolution behavior¶
| System CUDA | Behavior |
|---|---|
Detected (e.g. 12.1) |
Best-matching CUDA variant selected (exact match preferred, closest lower version as fallback); pytorch-family packages capped + rewritten to the matching pytorch index tag |
| Detected but no variants available | CPU-only version used |
| Not detected | CPU-only versions used. No CUDA variants selected. |
--cuda flag provided |
Overrides auto-detection — forces CUDA-aware resolution |
--cuda flag¶
On CPU-only machines (CI runners, cloud VMs), use --cuda to produce a lock file with GPU variants:
udr lock --cuda 12.1 # resolve as if CUDA 12.1 is available
udr lock --cuda 11.8 --export Dockerfile # CUDA 11.8 with Docker export
udr scan --github <url> --cuda 12.1 # scan remote repo with GPU resolution
Lock file portability¶
The lock file stores the detected (or overridden) system info:
Running udr lock on a GPU machine records GPU info. Running the lock file on a different machine does not trigger re-resolution — use udr update to re-resolve on a new machine.
CLI ↔ API Mapping¶
Every non-interactive CLI operation has a corresponding REST API endpoint when udr serve is running.
Exact matches (same logic, same data)¶
| CLI Command | API Endpoint | Method |
|---|---|---|
udr resolve |
/api/v1/packages/resolve |
POST |
udr graph |
/api/v1/graph |
POST |
udr verify |
/api/v1/verify |
POST |
udr list-ecosystems |
/api/v1/packages/ecosystems |
GET |
udr update |
/api/v1/update |
POST |
udr why |
/api/v1/why |
POST |
udr outdated |
/api/v1/outdated |
POST |
udr diff |
/api/v1/diff |
POST |
udr search |
/api/v1/packages/search |
GET |
udr details |
/api/v1/packages/{eco}/{name}/details |
GET |
udr versions |
/api/v1/packages/{eco}/{name}/versions |
GET |
udr dependencies |
/api/v1/packages/{eco}/{name}/dependencies |
GET |
udr sbom |
/api/v1/sbom |
POST |
udr completion {shell} |
/api/v1/completion/{shell} |
GET |
udr scan --github <url> |
/api/v1/scan/github |
POST |
udr scan --directory <path> |
/api/v1/scan/local |
POST |
udr scan --upload <file> |
/api/v1/scan/upload |
POST |
udr check --cve |
/api/v1/check/cve |
POST |
udr check --license |
/api/v1/check/license |
POST |
udr check --deprecated |
/api/v1/check/deprecated |
POST |
udr check --policy |
/api/v1/check/policy |
POST |
udr lock --check |
/api/v1/lock/check |
POST |
udr lock --sign |
/api/v1/lock/sign |
POST |
udr lock --report |
/api/v1/lock/report |
POST |
udr lock --pin/--block/--freeze |
/api/v1/lock/apply-pinning |
POST |
udr update --fix-cve |
/api/v1/lock/update-with-fix |
POST |
udr auth gen-key |
/api/v1/auth/gen-key |
POST |
udr auth show-key |
/api/v1/auth/signing-key |
GET |
udr index pull <url> |
/api/v1/index/pull |
POST |
udr index build |
/api/v1/index/build |
POST |
udr index status |
/api/v1/index/status |
GET |
udr index sync --all |
/api/v1/index/sync-all |
POST |
Similar functionality, different I/O¶
| CLI Command | API Endpoint | Method | Difference |
|---|---|---|---|
udr check (no flags) |
GET /api/v1/system/info |
GET | CLI shows compatibility table; API returns raw system dict |
udr lock (full workflow) |
POST /api/v1/generate-lock |
POST | CLI auto-detects manifests from filesystem and writes lock file; API accepts pre-parsed packages or raw manifest content and returns lock data as JSON |
udr lock --export <fmt> |
POST /api/v1/packages/export |
POST | CLI works from scanned data; API works from supplied resolved_packages dict |
udr install |
POST /api/v1/install-commands |
POST | CLI runs native package manager commands; API returns command strings |
udr install --restore |
POST /api/v1/restore-commands |
POST | Same as above but for all packages |
No API equivalent (local filesystem / TTY only)¶
| CLI Feature | Reason |
|---|---|
udr serve |
Starts the API server itself |
udr export |
Local filesystem read/write |
udr init |
Creates files on local filesystem |
udr migrate |
Reads/writes local lock files |
udr system-info |
Local system scan — no network endpoint |
udr tools |
Local plugin filesystem registration |
udr lock -m/--manifest |
Filesystem manifest filtering |
udr lock --dry-run |
Preview without writing |
udr lock -i/--interactive |
Interactive TUI — requires terminal |
udr lock -y/--yes |
Manifest overwrite confirmation |
udr install (execution) |
Runs pip/npm/cargo — requires local package manager |
udr verify --signature |
Verifies against local files |
udr graph --from-lock |
Reads local lock file — no registry access |
udr update --all |
Bulk re-resolution of the local lock file — no single API call |
API-only (no CLI equivalent)¶
| Endpoint | Method | Purpose |
|---|---|---|
GET /api/v1/health |
GET | Health check (DB + Redis connectivity) |
POST /api/v1/system/check-compatibility |
POST | Structured system-requirement evaluation |
GET /api/v1/packages/{eco}/{name}/compatibility |
GET | Compatibility matrix from community reports |
GET /api/v1/packages/export-formats |
GET | List available export formats |
POST /api/v1/lock/update-manifests |
POST | Suggest version bumps from lock data (analysis only) |
POST /api/v1/auth/register, /login, /token, /refresh |
various | User auth (registration, login, token management) |
POST /api/v1/check/all |
POST | Combined CVE + license + deprecated + policy check |
Error Handling¶
All commands display errors in a formatted red panel:
╭──────────────────────── Error ────────────────────────╮
│ Resolution failed: <message> │
╰───────────────────────────────────────────────────────╯
Common error messages and causes:
| Error | Likely Cause |
|---|---|
No manifests found |
No recognized dependency files in the target directory |
No packages found in manifests |
Manifest files exist but are empty or unparseable |
Lock file not found |
Run udr lock first to generate udr.lock |
Package '{name}' not found in lock file |
Package doesn't exist in the lock file |
PackageLoader could not find a 'templates' directory |
Package installed without template data files — run pip install --upgrade ud-resolver |