Skip to content

Command Reference

This document provides a complete reference for all Zaojun command-line options and arguments.

Command Syntax

zaojun [PYPROJECT_TOML] [OPTIONS]

Arguments

PYPROJECT_TOML

Type: Path (optional) Default: ./pyproject.toml Description: Path to the pyproject.toml file to check

Examples:

# Check current directory
zaojun

# Check specific file
zaojun /path/to/project/pyproject.toml

# Check file with different name
zaojun dependencies.toml

Configuration File

Zaojun reads defaults from a [tool.zaojun] section in the same pyproject.toml it is checking. CLI flags always take priority over config values.

Supported keys

TOML key CLI equivalent Type Default
short --short boolean false
groups --groups boolean false
compat-ok --compat-ok boolean false
cache --cache boolean false
cache-stats --cache-stats boolean false
min-age --min-age integer 0
library --library boolean false
format --format string "text"
index-url --index-url string "https://pypi.org/pypi"
flag-major --flag-major boolean true
major-ok --major-ok boolean false
vuln-ignore (config only) list of strings []
check-licenses --check-licenses boolean false
allowed-licenses (config only) list of SPDX strings []
unknown-license --unknown-license string "warn"
license-ignore (config only) list of dicts []

--clear-cache is intentionally absent — it is a one-shot action that does not make sense as a persistent default.

Example

[tool.zaojun]
cache = true
groups = true
min-age = 7
vuln-ignore = [
    "requests",              # ignore all advisories for requests
    "pillow == 10.3.0",      # ignore only when PyPI latest is exactly 10.3.0
    "urllib3 < 2.0",         # ignore when latest is in this range
    "CVE-2024-35195",        # ignore this CVE across all packages
    "GHSA-gc5v-m9x4-r6x2",  # ignore by GHSA ID
    "PYSEC-2024-001",        # ignore by OSV ID
]

Running zaojun with this config is equivalent to zaojun --cache --groups --min-age 7 (plus the vulnerability ignore rules applied at runtime).

Precedence

CLI flags always override config values, including --no-X negations. Passing --no-cache on the command line disables caching even when cache = true is set in [tool.zaojun].

Warnings

Unknown keys or type mismatches in [tool.zaojun] emit a warning to stderr and are ignored. They do not cause a non-zero exit code.

Options

License Checking

zaojun can verify that every dependency's license is compatible with your project's own license. See the License Checking guide for the full reference.

--check-licenses, --no-check-licenses

Type: Boolean flag Default: --no-check-licenses Description: Enable license compliance checking. Also enabled automatically when allowed-licenses is non-empty.

--unknown-license

Type: String ("warn" / "fail" / "allow") Default: "warn" Description: Controls how zaojun handles dependencies whose license cannot be determined from PyPI metadata.

allowed-licenses (config only)

Type: List of SPDX identifier strings Default: [] (auto-derive from project.license) Description: Explicit allowed set. When empty and check-licenses is true, the allowed set is derived from project.license.

license-ignore (config only)

Type: List of dicts, each with package (PEP 508 specifier) and reason (string) Default: [] Description: Exempt specific packages from license checking. The reason field is required.

[[tool.zaojun.license-ignore]]
package = "some-pkg >= 3.0"
reason = "Re-licensed to MIT in v3.0"

Vulnerability Scanning

zaojun automatically checks for known security advisories using data that is already present in the PyPI JSON response — no additional HTTP requests are made.

Output

When a package has open (non-withdrawn) advisories, its dependency line gains a 🔒 indicator, and a Vulnerabilities section is appended after the main report:

⚠️  requests: ~=2.28.0 → Latest: 2.32.3  🔒 1 vuln
✅️ httpx~=0.28.1 is up to date

Vulnerabilities
───────────────
requests
  PYSEC-2024-xxx (CVE-2024-35195)
    Fixed in: 2.32.0
    Verify that cert verification is enforced for redirect targets using HTTPS.

The Vulnerabilities block is suppressed by --short; the 🔒 inline indicator is always shown when vulns are present (even in --short mode).

Packages with open advisories set exit code 1, just like version updates.

vuln-ignore (config only)

Suppress specific advisories by adding a vuln-ignore list to [tool.zaojun]. Two entry shapes are supported:

Vuln-ID entries (prefix CVE-, GHSA-, PYSEC-): match a single advisory by its primary ID or any alias, across all packages:

vuln-ignore = [
    "CVE-2024-35195",
    "GHSA-gc5v-m9x4-r6x2",
    "PYSEC-2024-001",
]

Package entries (package name + optional version specifier): suppress all advisories for a package, optionally only when the PyPI-latest version satisfies the specifier:

vuln-ignore = [
    "requests",             # unconditional — suppress forever
    "pillow == 10.3.0",     # re-alert when PyPI ships 10.3.1+
    "urllib3 >= 1.0, < 2.0",
]

The version in package entries is matched against the latest version on PyPI (the same value shown in the report), not the installed version. This gives a natural "re-check on next release" behaviour: a == X.Y.Z rule stops suppressing as soon as a newer release appears.

Invalid entries (parse errors) emit a warning to stderr and are skipped — they do not hard-fail a run.

--short, --no-short

Type: Boolean flag Default: --no-short (show full output) Description: Show only the shortest possible output

When enabled (--short): - Only shows dependencies that need updates - Omits "up to date" messages - Omits section headers - Useful for scripts and CI/CD pipelines

Examples:

# Full output (default)
zaojun
# Output: Shows all dependencies with status

# Short output
zaojun --short
# Output: Only shows packages needing updates

--groups, --no-groups

Type: Boolean flag Default: --no-groups (check only main dependencies) Description: Check dependencies in all dependency groups

When enabled (--groups): - Checks [project.dependencies] section - Checks all [dependency-groups] sections - Shows each group separately in output - Useful for projects with development, test, or documentation dependencies

Examples:

# Check only main dependencies (default)
zaojun
# Output: Only checks [project.dependencies]

# Check all dependency groups
zaojun --groups
# Output: Checks [project.dependencies] and all [dependency-groups]

--compat-ok, --no-compat-ok

Type: Boolean flag Default: --no-compat-ok (compatible updates cause exit code 1) Description: Treat compatible version updates as acceptable

When enabled (--compat-ok): - Compatible updates (⚠️) don't cause exit code 1 - Only incompatible updates (❌) cause exit code 1 - Useful during development or in CI/CD where you want to allow compatible updates

Examples:

# Default: All updates cause exit code 1
zaojun
# Exit code: 1 if any ⚠️ or ❌ updates

# Compatible updates don't cause errors
zaojun --compat-ok
# Exit code: 1 only if ❌ updates, 0 if only ⚠️ updates

--cache, --no-cache

Type: Boolean flag Default: --no-cache (caching disabled) Description: Enable caching of PyPI API responses

When enabled (--cache): - PyPI API responses are cached locally for 24 hours - Subsequent runs use cached data for faster execution - Cache is stored in ~/.cache/zaojun/pypi_cache/ - Useful for repeated checks during development

Examples:

# Default: No caching (backward compatible)
zaojun
# Always fetches fresh data from PyPI

# Enable caching for faster repeated runs
zaojun --cache
# First run: Fetches from PyPI and caches results
# Subsequent runs: Uses cached data (much faster)

# Explicitly disable caching
zaojun --no-cache
# Always fetches fresh data from PyPI

--clear-cache, --no-clear-cache

Type: Boolean flag Default: --no-clear-cache (preserve cache) Description: Clear all cache entries before checking

When enabled (--clear-cache): - All cached PyPI API responses are deleted - Fresh data is fetched from PyPI - Cache statistics are reset - Useful when you want to force fresh data or troubleshoot cache issues

Examples:

# Clear cache and check dependencies
zaojun --clear-cache
# Output: "Cleared X cache entries" then normal output

# Clear cache with caching enabled
zaojun --cache --clear-cache
# Clears cache, then fetches fresh data and caches it

# Clear cache with groups
zaojun --groups --clear-cache
# Clears cache, then checks all dependency groups

--cache-stats, --no-cache-stats

Type: Boolean flag Default: --no-cache-stats (don't show statistics) Description: Show cache statistics after checking

When enabled (--cache-stats): - Shows cache hit/miss statistics - Displays cache configuration and status - Useful for monitoring cache effectiveness - When combined with --short, a warning is emitted to stderr and stats are suppressed

Examples:

# Show cache statistics
zaojun --cache-stats
# Output: Normal output followed by cache statistics

# Enable caching and show statistics
zaojun --cache --cache-stats
# Output: Normal output with cache hits/misses

# Clear cache and show statistics
zaojun --clear-cache --cache-stats
# Output: Shows cleared entries, normal output, then statistics

--library, --no-library

Type: Boolean flag Default: --no-library (application mode) Description: Enable library mode: check constraint hygiene and flag only incompatible updates

Library mode is designed for Python packages that are consumed by other packages. It runs two checks per dependency:

  1. Constraint hygiene (local, no PyPI needed): flags version specifiers that are too restrictive for a library:
  2. Exact pins (==X.Y.Z) — blocks all other versions for downstream consumers
  3. Patch-level compatible releases (~=X.Y.Z) — too tight; minor-level (~=X.Y) is fine
  4. Tight upper bounds (<X.Y where Y ≠ 0) — use <X (major boundary) instead
  5. No specifier at all — warns that consumers get no minimum guarantee

  6. Incompatible staleness (PyPI): flags dependencies where the latest version falls outside the allowed range (e.g. ~=1.0 when 2.x is out). Compatible updates — where the latest version already satisfies the spec — are always silent in library mode regardless of --compat-ok.

--min-age works normally in library mode and applies to incompatible updates.

Examples:

# Check a library's pyproject.toml
zaojun --library

# Library check with supply-chain quarantine
zaojun --library --min-age 7

# Library check covering all dependency groups
zaojun --library --groups

# Output examples:
# ❌ pydantic: exact pin (==2.5.0) blocks consumers
# ❌ httpx: patch-level compatible release (~=0.27.2) is too tight for a library
# ❌ packaging: tight upper bound (<25.0) — use <26 instead
# ⚠️  requests: no version constraint — consumers get no minimum guarantee
# ❌ typer: ~=0.9.0 → Latest: 1.2.0   (incompatible staleness)
# ✅️ cyclopts>=2.0 is up to date

--flag-major, --no-flag-major

Type: Boolean flag Default: --flag-major (major-bump detection enabled) Description: Flag compatible updates that cross a major version boundary with 💥

When the latest version satisfies your spec but has a higher major version than the one your spec implies (e.g. spec >=2.0, latest 3.0.0), zaojun emits 💥 instead of ⚠️. This only fires for compatible updates; incompatible updates remain ❌ regardless.

CalVer note: Packages that use full-year versioning (YYYY.x, e.g. black, pip, certifi) are automatically excluded — a year increment is not a breaking-change signal. Short-year schemes (24.x, 25.x) are indistinguishable from numeric major versions and are not auto-detected; use --no-flag-major or flag-major = false in [tool.zaojun] to suppress false positives for those packages.

Use --major-ok if you want to see 💥 without failing CI.

Examples:

# Disable major-version detection (major bumps appear as ⚠️)
zaojun --no-flag-major

# Persistent default in config
# [tool.zaojun]
# flag-major = false

--major-ok, --no-major-ok

Type: Boolean flag Default: --no-major-ok (💥 triggers exit code 1) Description: Show 💥 for major-version bumps but do not exit with code 1

Mirrors --compat-ok for compatible updates: the 💥 signal is still displayed so nothing is silently hidden, but the exit code stays 0.

Interaction table:

Flags 💥 displayed Exit code
default yes 1
--major-ok yes 0
--no-flag-major no (shown as ⚠️) n/a
--compat-ok alone yes 1 (compat-ok does not affect major_update)

When to use:

  1. Deliberate deferral — your team has triaged a major bump (e.g. Django 4→5 requires a migration sprint) and doesn't want CI failing every day for something already on the backlog. --major-ok keeps 💥 visible in output without blocking.

  2. Routine major-bump tracking — projects that actively follow major releases and handle them via a dedicated process. The 💥 signal is informative but should never gate a deploy.

Contrast with --no-flag-major: that suppresses the signal entirely (major bumps become ⚠️). Use --major-ok when you want visibility without blocking; use --no-flag-major when you've consciously decided not to track major bumps at all.

Examples:

# See major bumps without blocking CI
zaojun --major-ok --cache

# Persistent default in config
# [tool.zaojun]
# major-ok = true

--min-age, --min-age N

Type: Integer Default: 0 (age check disabled) Description: Ignore updates younger than N days (supply-chain quarantine)

When set to a positive integer: - Updates released fewer than N days ago show ⏳ instead of ⚠️/❌ - If the release date is unavailable (old cache entry), the age check is skipped gracefully

Aged-version fallback: when the latest version is quarantined, zaojun searches the release history for the newest version that has already aged past the threshold and is genuinely newer than your spec's lower bound. If one is found, it is shown on the same ⏳ line with a compatibility icon and does trigger exit code 1 (it is actionable):

# latest is too new, but 2.32.3 has cleared the quarantine window
⏳ requests: ⚠️ 2.32.3 available (45 days old) — latest 2.33.0 is only 2 day(s) old (min-age: 7)

# no aged candidate — nothing actionable yet
⏳ requests: 2.33.0 is only 2 day(s) old (min-age: 7)

The compatibility icon follows the same rules as normal updates: ⚠️ compatible, ❌ incompatible, 💥 major-version bump.

Pre-release filtering: pre-release versions (alpha, beta, RC) are never surfaced as updates unless your spec's lower bound is itself a pre-release (e.g. >=1.0.0b1). This applies to both the quarantined latest version and aged candidates.

Examples:

# Ignore updates less than 7 days old
zaojun --min-age 7

# Stricter quarantine: wait 30 days
zaojun --min-age 30 --groups

--format

Type: String Default: text Allowed values: text, json Description: Select output format

When set to json, all results are printed as a single JSON object to stdout instead of human-readable text. The JSON format is stable and suitable for scripting and CI pipelines.

JSON output shape:

{
  "dependencies": [
    {"name": "requests", "spec": "==2.28.0", "latest": "2.28.0", "status": "up_to_date",
     "vulnerabilities": [
       {"id": "PYSEC-2024-xxx", "aliases": ["CVE-2024-35195"],
        "fixed_in": ["2.32.0"], "details": "...", "link": "https://osv.dev/..."}
     ]},
    {"name": "flask", "spec": "~=2.3.0", "latest": "3.0.0", "status": "incompatible_update"}
  ],
  "groups": {"dev": [...]},
  "needs_update": false
}

groups is only present when --groups is used. --short has no effect in JSON mode. vulnerabilities is only present on records that have open (non-ignored) advisories.

Status values:

Status Meaning
up_to_date On the latest version (or compatible update in library/compat-ok mode)
incompatible_update Newer version available that breaks the version spec
compatible_update Newer version available that satisfies the spec
major_update Latest is a major-version bump relative to the spec's lower bound; satisfies the spec but signals a potentially breaking upgrade. Includes needs_update: true unless --major-ok
too_new Update quarantined by --min-age; also includes age_days and min_age fields. When an aged candidate is found: also includes aged_version, aged_age_days, and aged_status fields
error Parse or network error; also includes an error field with the message

Examples:

# Machine-readable output
zaojun --format json

# Parse with jq
zaojun --format json | jq '.needs_update'

# Filter to only outdated packages
zaojun --format json | jq '[.dependencies[] | select(.status != "up_to_date")]'

# Set as persistent default in config
# [tool.zaojun]
# format = "json"

--index-url

Type: String Default: https://pypi.org/pypi Description: Base URL of a PyPI-compatible JSON API index

Use this option to point zaojun at a private package index such as Artifactory, devpi, or a corporate PyPI mirror. The index must implement the PyPI JSON API at {index-url}/{package}/json.

Cache note: The cache key is based on package name only and does not include the index URL. If you switch between indexes for the same package name, run --clear-cache between runs to avoid stale results.

Examples:

# Private Artifactory repository
zaojun --index-url https://artifactory.example.com/artifactory/api/pypi/pypi-local/pypi

# devpi server
zaojun --index-url https://devpi.example.com/root/pypi

# Set as persistent default in config
# [tool.zaojun]
# index-url = "https://my.private.index/pypi"

--help, -h

Type: Boolean flag Description: Show help message and exit

Displays usage information, available options, and examples.

Example:

zaojun --help

Cache Management

Zaojun includes a powerful caching system to improve performance for repeated dependency checks.

Cache Location

Cache files are stored in a platform-appropriate location: - Linux/Unix: ~/.cache/zaojun/pypi_cache/ (respects XDG_CACHE_HOME) - macOS: ~/Library/Caches/zaojun/pypi_cache/ - Windows: %LOCALAPPDATA%\zaojun\pypi_cache\

Cache Expiration

  • Cache entries expire after 24 hours (configurable)
  • Expired entries are automatically removed on access
  • Manual clearing via --clear-cache option

Cache Contents

Each cached package includes: - Package metadata (name, version, release info) - Upload timestamp (used by --min-age) - Timestamp for TTL calculation - Full PyPI response data

Cache Performance

  • First run with --cache: Cache misses (fetches from PyPI)
  • Subsequent runs: Cache hits (uses local data)
  • Performance improvement: 10-100x faster for repeated checks

--version

Type: Boolean flag Description: Show version information and exit

Displays the current Zaojun version.

Example:

zaojun --version
# Output: zaojun 1.0.3

Exit Codes

Zaojun uses the following exit codes to indicate results:

Code Meaning Description
0 Success All dependencies are up to date (or only compatible/quarantined updates) with no open advisories
1 Updates needed Incompatible updates available; compatible updates without --compat-ok; open security advisories; in library mode, also hygiene errors
2 Error Invalid arguments, file not found, or other errors

Hygiene warnings (bare dep with no specifier) do not affect the exit code. Advisories suppressed via vuln-ignore do not affect the exit code.

Environment Variables

Zaojun respects the following environment variables:

HTTP_PROXY, HTTPS_PROXY

Type: URL Description: Proxy server for HTTP/HTTPS requests

Use these variables if you need to access PyPI through a proxy server.

Example:

export HTTPS_PROXY="http://proxy.example.com:8080"
zaojun

NO_PROXY

Type: Comma-separated list Description: Hosts that should not use the proxy

Example:

export NO_PROXY="localhost,127.0.0.1,.internal"
zaojun

Common Option Combinations

CI/CD Pipeline Check

zaojun --short --groups
- Minimal output for clean logs - Checks all dependency groups - Exit code 1 if any updates needed

Development with Caching

zaojun --cache --cache-stats --groups
- Enables caching for faster repeated checks - Shows cache statistics to monitor effectiveness - Checks all dependency groups - Ideal for development workflows

Cache Management

zaojun --clear-cache --cache --cache-stats
- Clears existing cache entries - Enables caching for future runs - Shows cache statistics - Useful for forcing fresh data

Development Environment

zaojun --groups --compat-ok --cache
- Checks all dependencies - Allows compatible updates - Enables caching for faster repeated checks - Warns about incompatible updates

Supply-Chain Quarantine

zaojun --min-age 7 --groups
- Suppresses updates released in the last 7 days - ⏳ shown for quarantined packages (exit code stays 0) - Combine with --cache for fast repeated checks

Library Hygiene Check

zaojun --library
- Flags exact pins, patch-level compatible releases, and tight upper bounds - Compatible updates are silent (no PyPI noise for open-range specs) - Exit code 1 on any hygiene error or incompatible update

Private Index Check

zaojun --index-url https://my.private.index/pypi --groups
- Queries the private index for all dependency groups - Combine with --cache for faster repeated checks - If switching between indexes, use --clear-cache to avoid stale results

Aware of Major Bumps but Not Blocked

zaojun --major-ok --cache
- 💥 shown for major-version bumps, but exit code stays 0 - Useful when a major bump is already on the backlog

Suppress Major-Bump Detection Entirely

zaojun --no-flag-major
- Major-version bumps are treated as ordinary compatible updates (⚠️) - Use when you've deliberately decided not to track major bumps at all

Library Check with Quarantine

zaojun --library --min-age 7 --cache
- Full library hygiene + staleness check - Recent incompatible releases are quarantined (⏳) - Cached for fast CI runs

Quick Status Check

zaojun --short --cache
- Fast, minimal output - Quick overview of update status - Enables caching for repeated checks - Easy to parse in scripts

Comprehensive Check

zaojun --groups --cache --cache-stats
- Full detailed output - Checks everything - Enables caching for performance - Shows cache statistics - Complete dependency status

Option Precedence

When multiple options conflict or interact:

  1. File path is always processed first
  2. Output format (--short) affects all output
  3. Scope (--groups) determines what to check
  4. Tolerance (--compat-ok) affects exit code

Examples with Multiple Options

Complete Project Check

zaojun /path/to/project/pyproject.toml --groups --compat-ok --cache
- Checks specific file - Includes all dependency groups - Compatible updates don't cause errors - Enables caching for faster future checks

Script-Friendly Output

zaojun --short --groups --cache
- Minimal, parseable output - Includes all groups - Enables caching for performance - Clear exit code for automation

Development Workflow with Caching

# Initial check with caching
zaojun --groups --cache --cache-stats

# If updates needed, check with compat-ok
zaojun --groups --compat-ok --cache

# Update if only compatible updates
zaojun --short --compat-ok --cache
if [ $? -eq 0 ]; then
    uv sync -U --all-groups
fi

# Clear cache periodically
zaojun --clear-cache --cache-stats
```

Cache Option Interactions

Cache options interact with other options in specific ways:

  1. --cache with --clear-cache: Cache is cleared, then new data is fetched and cached
  2. --cache-stats with --short: A warning is emitted to stderr; statistics are suppressed
  3. --no-cache with --clear-cache: Cache is cleared, but no new data is cached
  4. --cache with network errors: Falls back gracefully, doesn't affect cached data

Deprecated Options

No options are currently deprecated. All options shown here are supported in the current version.

Version Compatibility

  • Cache options: Available in Zaojun 1.0.0 and later
  • Other options: Available in Zaojun 0.9.0 and later
  • Earlier versions: May not support cache options

Version History

  • 1.6.x: Aged-version fallback for --min-age: when the latest is quarantined, zaojun surfaces the newest version that has cleared the window (shown with compat icon on ⏳ line; exits 1)
  • 1.6.x: Pre-release filtering: alpha/beta/RC versions are not surfaced as updates unless the spec already pins to a pre-release
  • 1.5.0: CVE/vulnerability scanning — 🔒 inline indicator + Vulnerabilities detail block; vuln-ignore config list to suppress by ID or package/version
  • 1.5.0: --flag-major (default on) flags compatible major-version bumps with 💥; --major-ok opts out of exit code 1
  • 1.5.0: --index-url for querying private PyPI-compatible indexes (Artifactory, devpi, etc.)
  • 1.3.0: --library mode for library constraint hygiene and incompatible-only staleness checks
  • 1.2.0: --min-age flag for supply-chain quarantine; upload time stored in cache
  • 1.0.0: Initial cache implementation with TTL-based expiration

zaojun vs pip list --outdated

  • Zaojun: Checks against version constraints in pyproject.toml
  • pip: Shows all installed packages with newer versions available

zaojun vs uv pip compile --upgrade

  • Zaojun: Reports what updates are available, supports caching
  • uv pip compile: Generates updated lock files

zaojun Cache vs Other Tools

  • Zaojun cache: Project-specific, respects version constraints
  • pip cache: Package installation cache
  • HTTP cache: General HTTP response caching

Getting Help

For more information or to report issues:

See Also