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 []

--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

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 ⚠️/❌ - These packages do not trigger exit code 1 - Useful for reducing exposure to compromised packages in the window before the community reacts - If the release date is unavailable (old cache entry), the age check is skipped gracefully

Examples:

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

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

# Example output when a package is too new:
# ⏳ requests: 2.32.0 is only 2 day(s) old (min-age: 7)

--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
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.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