What 1.0 freezes¶
From 1.0.0, the things on this page are covered by semantic versioning: they do not change in a patch or minor release, and changing any of them means a new major version. Everything under Not covered may change in any release.
This page is the contract. It is deliberately a list of names and shapes, not a second copy of the reference — what each flag does is in the command-line reference, what each document field means is in the output format reference. What is frozen is that the name exists, takes the same kind of value, and means the same thing.
Every list here is checked against the code by tests/stability.rs. A flag added without a line on
this page fails the build, and so does a line on this page for something that does not exist.
Command-line flags¶
All 75. Their meanings are in cli.md; what this page promises is that none of them disappears or changes shape before 2.0.
| --against | --all-environments | --all-platforms | --allow-license |
| --assume-used | --ca-bundle | --color | --concurrency |
| --conda-index-kind | --config | --deny-license | --depth |
| --doctor | --embedded-sboms | --environment | --epss |
| --exclude | --exclude-kind | --explain | --fail-on-diff |
| --fail-on-epss | --fail-on-kev | --fail-on-phantom | --fail-on-scorecard |
| --fail-on-severity | --fail-on-yanked | --fetch-licenses | --format |
| --from-sbom | --group-by | --help | --ignore-license |
| --ignore-vuln | --include | --infer-extras | --keep-orphans |
| --kev | --license-texts | --lockfile | --log-format |
| --merge | --min-quality | --no-cache | --no-config |
| --outdated-min | --output | --platform | --prefix |
| --primary-purl | --pypi-mapping | --pypi-mapping-file | --quiet |
| --refresh | --report | --report-format | --require-license |
| --root-name | --root-version | --scan | --scan-depth |
| --scorecard | --scorecard-min | --skip-input | --source |
| --spec-version | --timings | --tree | --verbose |
| --verify-files | --version | --version-details | --vex |
| --vex-in | --vex-open | --vulnerabilities | |
Spellings that answer to an older name¶
Accepted permanently, hidden from --help so there is one name to learn. Removing any of these
would be a major version with its own notice.
| Accepted | Canonical | Since |
|---|---|---|
--name |
--root-name |
renamed in 1.0.0 |
--outdated-only |
--outdated-min |
renamed in 1.0.0 |
--pypi-licenses |
--fetch-licenses |
renamed in 0.4.0 |
--build-info |
--version-details |
a visible alias, both shown |
Values with a structure¶
--ignore-vuln (and the ignore-vuln config key and action input) takes ID, ID:TEXT or
ID:STATE[:JUSTIFICATION][:RESPONSE,...][:TEXT]. STATE is a CycloneDX impact-analysis state,
JUSTIFICATION a CycloneDX impact-analysis justification (only after not_affected) and RESPONSE a
comma-separated list of CycloneDX impact-analysis responses; each segment is read as one only when every word in
it names a known value, otherwise it is text. Every form keeps its meaning through 1.x; a new segment may be added only in
the same way, recognised by a fixed vocabulary, so an existing entry never changes meaning.
Exit codes¶
| Code | Meaning |
|---|---|
| 0 | The document or report was written. |
| 1 | A runtime error, or --doctor found a problem. A diagnostic goes to stderr. |
| 2 | A command-line usage error: an unknown flag, conflicting flags, or a value the flag does not accept. |
| 3 | --allow-license / --deny-license / --require-license was violated. |
| 4 | --fail-on-severity, --fail-on-kev or --fail-on-epss matched. |
| 6 | --fail-on-diff found a change it was asked to gate on. |
| 7 | --fail-on-yanked found a yanked release. |
| 8 | --fail-on-phantom found an undeclared import. |
| 9 | --fail-on-scorecard found a repository below the threshold. |
| 10 | --min-quality found the document's quality score below the threshold. |
| 11 | --verify-files or --report files found an installed file modified or missing against its conda-meta record. |
Every gate above 2 writes its document or report first and lists what tripped it on stderr, so a failing gate still leaves you the artifact.
5 is deliberately unused. It has never been assigned — not in any release — and it stays free
rather than being filled by the next gate, so that a script testing for a specific code is never
surprised by a number that used to mean nothing. Gates take 10 and upward: --min-quality is 10, --verify-files is 11, and the next one takes 12.
Configuration keys¶
A key is the flag's own name without the leading --, so --fetch-licenses is fetch-licenses.
The command line always wins over the files.
Three layers are read, least specific first, and merged per key — a layer overrides what a less specific one said and inherits what it did not mention:
| Layer | Where |
|---|---|
| system | /etc/pixi/pixi-sbom-config.toml, or %PROGRAMDATA%\pixi\pixi-sbom-config.toml on Windows |
| user | $PIXI_HOME/pixi-sbom-config.toml, else ~/.pixi/pixi-sbom-config.toml |
| project | <workspace>/.pixi/pixi-sbom-config.toml, else [tool.pixi-sbom] in pyproject.toml, else pixi-sbom.toml |
--config <PATH> replaces the search with one file; --no-config reads none. Both keep the
meanings they have always had: ours differ from pixi's flags of similar name, which still read
project-local files, and they are frozen as the broader meaning.
pixi-sbom.toml at the workspace root is deprecated. It is read, and named as deprecated by
--doctor and in the logs, until 2.0. [tool.pixi-sbom] in pyproject.toml is not deprecated and
stays supported.
format |
spec-version |
pypi-mapping |
pypi-mapping-file |
primary-purl |
fetch-licenses |
license-texts |
embedded-sboms |
exclude |
include |
exclude-kind |
keep-orphans |
allow-license |
deny-license |
require-license |
fail-on-yanked |
vulnerabilities |
kev |
fail-on-kev |
fail-on-severity |
ignore-vuln |
ignore-license |
scorecard |
scorecard-min |
fail-on-scorecard |
fail-on-diff |
source |
assume-used |
fail-on-phantom |
conda-index-kind |
concurrency |
infer-extras |
min-quality |
epss |
fail-on-epss |
vex-in |
skip-input |
An unknown key is an error, not a warning, and the diagnostic lists every key that is accepted — so a typo cannot pass silently and you are never left guessing at the spelling.
Environment variables¶
RATTLER_AUTH_FILE and NETRC are read for credentials. They are not this project's to define,
so they are not frozen here; they are honoured with the meanings rattler and curl give them.
| Variable | |
|---|---|
PIXI_SBOM_CACHE_DIR |
Where the caches live. |
PIXI_SBOM_CONCURRENCY |
How many requests at once; --concurrency and the concurrency key say the same thing, and the command line beats the variable, which beats the file. Requests only: threads for local work follow the core count. Above 100 is honoured with a warning; above 1000 is clamped, and the run is never sized past the number of packages. |
PIXI_SBOM_OFFLINE |
Make no network requests. |
PIXI_SBOM_NO_PROGRESS |
No progress bars. |
PIXI_SBOM_LOG_FORMAT |
text or json. |
PIXI_SBOM_COMPLETE |
bash, zsh, fish, powershell or elvish: print that shell's completion registration instead of an SBOM. Any other value is ignored. |
PIXI_SBOM_CA_BUNDLE |
A PEM bundle to trust. |
PIXI_SBOM_OSV_URL |
Where to query OSV. |
PIXI_SBOM_KEV_URL |
Where to fetch the CISA catalog. |
PIXI_SBOM_EPSS_URL |
Where to ask FIRST for EPSS scores. |
PIXI_SBOM_PYPI_URL |
Where to read PyPI metadata. |
PIXI_SBOM_ANACONDA_URL |
Where to read anaconda.org metadata. |
PIXI_SBOM_CONDA_FALLBACK_CHANNEL |
The channel a mirrored package is checked against, by hash. |
PIXI_SBOM_PREFIX_INDEX_URL |
Where to reach prefix.dev's GraphQL API. |
PIXI_SBOM_MAPPING_URL |
Where to download the conda-to-PyPI name mapping. |
PIXI_SBOM_CONDA_ARCHIVE_URL |
Base that conda package archives are read from, in place of each package's own host. |
PIXI_SBOM_WHEEL_ARCHIVE_URL |
Base that PyPI wheel archives are read from, in place of each wheel's own host. |
PIXI_SBOM_SCORECARD_URL |
Where to query OpenSSF Scorecard. |
Also read, and owned by other tools: SSL_CERT_FILE, PIXI_CACHE_DIR, RATTLER_CACHE_DIR,
HTTPS_PROXY / HTTP_PROXY / NO_PROXY, NO_COLOR, CLICOLOR_FORCE, RUST_LOG.
pixi:* names in a document¶
Property names in CycloneDX and comment / annotation names in SPDX. What is frozen is the name and
what it holds; whether a given run emits a particular one depends on the flags. output-format.md
says which flag produces which.
pixi:build |
pixi:build-number |
pixi:cargo-source |
pixi:channel |
pixi:channel-url |
pixi:cran-source |
pixi:declared-in |
pixi:direct |
pixi:direct-url |
pixi:editable |
pixi:embedded-sbom |
pixi:environment |
pixi:epss |
pixi:epss-cve |
pixi:epss-date |
pixi:epss-percentile |
pixi:excluded |
pixi:extracted-package-dir |
pixi:file-name |
pixi:identifier-hash |
pixi:incomplete |
pixi:incomplete-detail |
pixi:index-url |
pixi:installer |
pixi:interpreter |
pixi:kev |
pixi:kev-cve |
pixi:kev-date-added |
pixi:kev-due-date |
pixi:kev-ransomware |
pixi:kind |
pixi:license-exempt |
pixi:license-family |
pixi:license-file |
pixi:license-files-source |
pixi:license-raw |
pixi:license-source |
pixi:lockfile |
pixi:marker |
pixi:merge-conflict |
pixi:missing-files |
pixi:modified-files |
pixi:noarch |
pixi:platform |
pixi:prefix |
pixi:purl |
pixi:pypi-dist-info |
pixi:pypi-mapping |
pixi:python-extras |
pixi:python-extras-evidence |
pixi:python-extras-inferred |
pixi:python-version |
pixi:regenerated-bytecode |
pixi:repository-source |
pixi:requires-python |
pixi:resolution-markers |
pixi:scorecard |
pixi:scorecard-date |
pixi:size |
pixi:source |
pixi:source-branch |
pixi:source-document |
pixi:source-git |
pixi:source-path |
pixi:source-rev |
pixi:source-subdirectory |
pixi:source-tag |
pixi:source-url |
pixi:stale-cache |
pixi:subdir |
pixi:verified-files |
pixi:vex-for |
pixi:vex-source |
pixi:via-extra |
pixi:yanked |
pixi:yanked-reason |
pixi:scorecard-check-<name> is a family rather than one name: the suffix is the OpenSSF check,
so the set grows when OpenSSF adds a check. The prefix is frozen; the suffixes are theirs.
Report JSON¶
--report <kind> --report-format json writes an object with one key named after the report —
packages, licenses, vulnerabilities, diff, outdated, python, phantom, scorecard,
quality, files —
holding an array of rows. Row field names are frozen; row order is not, except where the
report documents an order (worst-first for vulnerabilities).
CSV columns and their order are frozen. A flag that adds data adds columns only after them and only
when given: --epss appends epss,epss_percentile to the vulnerabilities CSV. The Markdown and
table renderings are not frozen — see below.
The GitHub Action¶
Inputs and outputs of action.yml. An input maps to the flag of the same name; extra-args
passes anything through.
Inputs: all-environments, all-platforms, allow-license, artifact-name, attest,
attest-subject, config, dependency-submission, deny-license, diff-against, embedded-sboms, environment,
extra-args, fail-on-diff, fail-on-kev, fail-on-policy, fail-on-scorecard,
fail-on-severity, fail-on-vulnerabilities, fail-on-yanked, fetch-licenses, format,
from-sbom, ignore-license, ignore-vuln, kev, license-texts, lockfile, output,
platform, prefix, primary-purl, pypi-mapping, require-license, sarif-category, scan,
scorecard, scorecard-min, spec-version, upload-artifact, upload-sarif, version, vex,
vex-open, vulnerabilities.
Outputs: attestation-url, diff-changed, document, output, policy-violated, sarif,
version, vulnerabilities-found.
Document formats¶
CycloneDX 1.6 and 1.7, SPDX 2.3 and 3.0.1 stay writable, and --spec-version keeps accepting
1.6, 1.7, 2.3 and 3.0. Which is the default for each --format is frozen too: CycloneDX
1.6 and SPDX 2.3.
--from-sbom keeps reading CycloneDX 1.4–1.7 and SPDX 2.x / 3.0 JSON.
Lockfile format versions 1 through 7 stay readable. A newer one is refused by name rather than half-read, and that refusal is exit code 1.
The CPE table¶
The format of data/cpe.toml and of the CPEs written from it (a CPE 2.3 formatted string in CycloneDX's cpe,
SPDX 2.3's cpe23Type reference and SPDX 3.0.1's cpe23 identifier) is covered. Its entries are not: which conda
packages have a CPE, and with which vendor and product, change in any release, patch releases included, as entries
are added and corrected.
Not covered¶
These change without a major version, and nothing should be parsed out of them:
- Log lines. Every
INFO/WARN/DEBUGline, its wording, its fields and whether it appears at all.--log-format jsongives stable shape — a JSON object per line — but the messages and fields inside it are not a contract. Gate on exit codes, not on log text. - Table and Markdown report layout. Column widths, ordering of unordered reports, box drawing,
colour, the tree glyphs. Use
--report-format jsonorcsvif something reads it. - Recommendation and diagnostic wording.
recommendationtext in a document, the phrasing of a miette diagnostic, the help text of a flag. - Which lockfiles are read without
--lockfile. A directory's lockfiles are read one per ecosystem, and the ecosystems found and read this way may grow in a minor release, as may what--scanfinds besides lockfiles (installed environments since 1.13.0).--skip-input(or theskip-inputkey) pins it to the ones you want. - Progress output. Bars, spinners, what they count.
--timingsoutput. The phases, their names, the table.--doctoroutput. What it checks and how it says so; only the exit code is frozen.--explainoutput. A human-facing explanation, free to improve.- The published Rust library. Every module is
#[doc(hidden)]and none of it is an API; see the crate documentation. The command line is the interface. - Element ids and ordering inside a document.
bom-ref,SPDXIDand JSON-LDspdxIdvalues are derived and may change shape; so may the order ofcomponents/packages/@graphentries. Match onpurl,nameandversion. - Cache layout. Directory names and file formats under the cache directory.
- Completion scripts and candidates. What
PIXI_SBOM_COMPLETE=<shell> pixi-sbomprints, how the shell and the binary talk to each other (clap's dynamic completion, which clap itself marks unstable), and which candidates are offered. Source the registration at shell start rather than saving it, so it always matches the binary.
Changing something that is frozen¶
A rename keeps the old spelling as a permanent alias, the way --root-name and --outdated-min
did. That is additive and ships in a minor release. Removing a spelling, changing what a flag
means, or changing an exit code waits for a major version, and gets a deprecation warning in a
release before it.