> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scanoss.com/llms.txt
> Use this file to discover all available pages before exploring further.

# From scanoss-py to scanoss-cli

> Move scans and CI pipelines from scanoss-py and the v2 API to scanoss-cli and the v3 API: install, endpoint, commands, flags, output, settings, behaviour changes, and what has no equivalent.

This page is for anyone who runs `scanoss-py` today, by hand or in a pipeline, and wants to move
to `scanoss-cli` and the v3 API. It maps what you use now to what you use in v3, and lists the
changes that can alter your results.

`scanoss-py` keeps working on v2 for now, so you can move one pipeline at a time. For an overview
of who is affected, see [Migrating to v3](https://docs.scanoss.com/en/latest/developer-tools/migrating/overview.md).

## Install scanoss-cli

`scanoss-cli` is a single binary with no runtime to install. Pick one:

* **Prebuilt binary** for Linux, macOS, or Windows, from the releases page. See
  [Installation](https://docs.scanoss.com/en/latest/cli/scanoss-go/installation.md#prebuilt-binary).

* **Go**, if you have Go 1.26 or later:

  ```bash theme={null}
  go install github.com/scanoss/scanoss.go/cmd/scanoss-cli@latest
  ```

* **Docker**, with the `ghcr.io/scanoss/scanoss` image. It replaces `ghcr.io/scanoss/scanoss-py`.
  Its entrypoint is `scanoss-cli`, so you pass the command and flags directly:

  ```bash theme={null}
  docker run --rm -v "$PWD:/src" ghcr.io/scanoss/scanoss:latest \
    scan /src --api-key "$SCANOSS_API_KEY" > results.json
  ```

  See [Using Docker](https://docs.scanoss.com/en/latest/cli/scanoss-go/using-docker.md) for writing output into the mounted
  folder.

Check the install with `scanoss-cli --version`.

## Point it at the API

`scanoss-cli` sends every request to `https://api.scanoss.com` unless you set another URL, and
that endpoint requires an API key. A self-hosted v3 deployment may run without a key.

> [!WARNING]
>
> `scanoss-py` used the free OSSKB.org service when you gave it no API key. `scanoss-cli` has no
> such fallback, and it can't talk to OSSKB.org or to a v2 server. Without a key, a scan against
> the default endpoint stops before it sends anything.

| scanoss-py | scanoss-cli | Notes |
| - | - | - |
| `SCANOSS_SCAN_URL` | `SCANOSS_API_URL` | Set only the base URL, for example `https://scanoss.example.com`. `scanoss-cli` adds the `/v3/...` paths itself. Don't add `/scan/direct`. |
| `SCANOSS_API_KEY` | `SCANOSS_API_KEY` | Same name. |
| `--apiurl` | `--api-url` | |
| `--key`, `-k` | `--api-key` | There is no short form. |
| `--proxy`, `HTTPS_PROXY` | `--proxy`, `SCANOSS_PROXY`, `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` | |
| `--pac` | Not supported | Read the proxy address from your PAC file and pass it with `--proxy`. |
| `--ca-cert`, `REQUESTS_CA_BUNDLE` | `--ca-cert`, `SCANOSS_CA_CERT` | The certificate is added to the system trust store, so the public API keeps working. |
| `--ignore-cert-errors` | `--ignore-cert-errors` | Same. It turns off certificate checks, so use it only for testing. |

Each setting resolves in this order: the flag, then the environment variable, then
`~/.scanoss/settings.json`, then the built-in default. To store a value once on a workstation,
use `scanoss-cli config set`:

```bash theme={null}
scanoss-cli config set api-key "<your-key>"
scanoss-cli config set api-url https://scanoss.example.com   # a self-hosted v3 deployment
scanoss-cli config list                                       # shows each value and where it came from
```

In CI, use environment variables instead. See [Configuration](https://docs.scanoss.com/en/latest/cli/scanoss-go/configuration.md)
and [API keys and authentication](https://docs.scanoss.com/en/latest/developer-tools/authentication.md).

## Commands

| scanoss-py | scanoss-cli | Notes |
| - | - | - |
| `scan <dir>` | `scan <dir>` | |
| `scan --wfp <file>` | `scan wfp <file>` | Scans a fingerprint file you generated earlier. |
| `fingerprint` / `wfp` | `wfp` | |
| `scan --dependencies` | `scan --include deps` | Reads your manifest and lock files locally. |
| `dependencies` | `dependencies <dir> --extract-local` | Parses manifest and lock files locally. See [Dependencies](https://docs.scanoss.com/en/latest/cli/scanoss-go/decoration-and-enrichment.md#dependencies). |
| `convert` | `sbom` | Converts a raw result, CycloneDX, or SPDX into CycloneDX or SPDX, offline. |
| `component vulns` | `vulnerabilities` | |
| `component licenses` | `licenses` | |
| `component provenance` | `geoprovenance` | |
| `component search` | `components search` | |
| `component versions` | `components versions` | `components releases` also lists release notes. |
| `component status` | `components status` | |
| `crypto algorithms` | `cryptography algorithms` | |
| `crypto hints` | `cryptography hints` | |
| `crypto versions-in-range` | `cryptography versions-range` | |
| — | `enrich` | New. Adds vulnerabilities, licences, cryptography, or geoprovenance to an existing result or SBOM without scanning again. |
| `results` | — | `results` in `scanoss-cli` means something else: it resumes or polls a scan by its scan ID. |

## Flags

| scanoss-py | scanoss-cli | Notes |
| - | - | - |
| `--threads` (default 5) | `--threads`, `-t` (default 10) | |
| `--skip-size` | `--min-size`, `--max-size` | `--min-size` is the smallest file to fingerprint, in bytes. `--max-size 0` means no limit. |
| `--skip-extension`, `--skip-folder` | `settings.skip.patterns` in `scanoss.json` | Use gitignore-style patterns, for example `"dist/**"` or `"**/*.min.js"`. |
| `--all-extensions`, `--all-folders`, `--all-hidden` | Same names | |
| `--skip-headers` (off unless set) | `--skip-headers` (on by default) | See [Behaviour changes](#behaviour-changes-that-alter-results). |
| `--skip-headers-limit` | `--skip-headers-limit` | |
| `--identify`, `--ignore` | `--identify`, `-i` and `--ignore`, `-n` | `scanoss-cli` also accepts CycloneDX, SPDX, or its own raw output here, and lets you combine them with `--settings`. |
| `--settings` | `--settings` | `scanoss.json` is still picked up from the scanned folder by default. |
| `--ranking-threshold` | `--ranking-threshold` | Applied by the client to the result. |
| `--format` | `--format`, `-f` | See [Output formats](#output-formats). |
| `--output`, `-o` | `--output`, `-o` | |
| `--wfp-output` | `--save-wfp` | |
| — | `--max-components N\|all` | New. How many candidate components the server reports for each match. Unset, the server default applies. Use `all` to get every candidate. |
| — | `--chunk-size`, `--poll-interval` | New. Upload block size (default 1 MiB) and how often to check for the result (default 2 s). |
| — | `--gitignore` (default on) | New. Files your `.gitignore` excludes are not scanned. Pass `--gitignore=false` to scan them. |

For every flag and default, see [Scanning your project](https://docs.scanoss.com/en/latest/cli/scanoss-go/scanning-your-project.md)
or run `scanoss-cli scan --help`.

## Output formats

| scanoss-py `--format` | scanoss-cli `--format` |
| - | - |
| `plain` (default) | `raw` (default), a different format. See below. |
| `cyclonedx` | `cyclonedx` (CycloneDX 1.7) |
| `spdxlite` | `spdx` (SPDX 2.3) |
| `csv` | No equivalent |

> [!WARNING]
>
> **The default JSON output is a new format.** `scanoss-py` wrote one entry per scanned file,
> each with a list of matches. `scanoss-cli` writes one entry per component, with the files it
> matched listed as evidence. Any script that reads `scanoss-py` results needs rewriting: `jq`
> filters, report generators, dashboards, and uploads to other tools.

`scanoss-py` (`plain`), keyed by file:

```json theme={null}
{
  "src/zlib/inflate.c": [
    { "id": "file", "purl": ["pkg:github/madler/zlib"], "version": "1.2.11", "licenses": [] }
  ]
}
```

`scanoss-cli` (`raw`), grouped by component:

```json theme={null}
{
  "schema_version": "2.1",
  "metadata": { "tool": "scanoss", "tool_version": "v0.17.0" },
  "components": [
    {
      "purl": "pkg:github/madler/zlib",
      "scope": "detected",
      "version": "1.2.11",
      "evidence": [
        { "path": "src/zlib/inflate.c", "match_type": "file", "match_index": 0 }
      ]
    }
  ]
}
```

Both examples are shortened. The `raw` format also has a top-level `vulnerabilities` list when you
add `--include vulns`, and a `dependencies` list when you add `--include deps`. `scanoss-cli`
builds CycloneDX and SPDX documents itself, on your machine. See
[Output formats](https://docs.scanoss.com/en/latest/cli/scanoss-go/output-formats.md) for every field.

For example, to list the detected components:

```bash theme={null}
# scanoss-py
jq -r '[.[][] | select(.id != "none") | .purl[0]] | unique[]' results.json

# scanoss-cli
jq -r '.components[] | select(.scope == "detected") | .purl' results.json
```

## Settings file (scanoss.json)

`scanoss-cli` reads the `scanoss.json` in the folder you scan, or the file you pass with
`--settings`. It reads these keys:

| Key | What it does |
| - | - |
| `bom.include` (also `bom.identify`) | Marks the components you name as identified. |
| `bom.ignore` (also `bom.exclude`) | Drops the components you name from the matches. |
| `bom.remove` | Removes matches from whole files. |
| `bom.replace` | Points a match at a different component. |
| `settings.skip.patterns`, `settings.skip.sizes` | Skips files by pattern or size, for scanning, fingerprinting, or dependencies. |
| `settings.file_snippet.skip_headers`, `skip_headers_limit` | Leaves file headers, comments, and imports out of the fingerprint. |
| `settings.file_snippet.ranking_threshold` | Drops matches to components that rank worse than this. |

`scanoss-cli` applies the `bom` rules on your machine, after the result comes back. A component you
identify is never dropped by `bom.ignore`, `bom.remove`, or the ranking threshold. For worked
examples, see [Approve components with scanoss.json](https://docs.scanoss.com/en/latest/developer-tools/recipes/approve-components-bom-rules.md).

## Behaviour changes that alter results

> [!WARNING]
>
> Run a new scan and compare it with a `scanoss-py` result before you rely on it. These changes
> can make the same code give different matches.

* **Header skipping is on by default.** `scanoss-cli` leaves each file's licence header, leading
  comments, and imports out of its fingerprint. `scanoss-py` did this only with `--skip-headers`.
  Fingerprints differ, so matches can differ too. To fingerprint whole files as `scanoss-py`
  did, pass `--skip-headers=false`, or set `"skip_headers": false` under
  `settings.file_snippet` in `scanoss.json`. If `scanoss.json` sets `skip_headers`, it wins
  over the flag.
* **`.gitignore` is honoured.** Files your `.gitignore` excludes are not scanned. Pass
  `--gitignore=false` to scan them.
* **Model weight files are skipped**, for example `.safetensors`, `.gguf`, `.onnx`, `.pt`, and
  `.bin` files. `--all-extensions` turns off the built-in file rules.
* **Candidates per match.** The v3 server decides how many candidate components it reports for
  each match. If you need every candidate, pass `--max-components all`, or a number with
  `--max-components N`.
* **Dependencies come from your files.** `--include deps` reads your manifest and lock files on
  your machine. Where a lock file covers a manifest, it lists the resolved versions without dev
  dependencies.
* **More threads.** Fingerprinting uses 10 workers by default instead of 5.
* **Exit codes.** `scanoss-cli` exits with `1` on any error. It has no policy exit codes. To fail a
  build on a finding, use a [gate script](https://docs.scanoss.com/en/latest/developer-tools/recipes/licence-and-vulnerability-gate.md).

## What has no equivalent

These `scanoss-py` features are not in `scanoss-cli`:

| scanoss-py | Where to go instead |
| - | - |
| `inspect` (copyleft, undeclared components, licence and component summaries, policy exit codes) | Earnie policies and merge gate, or a [gate script](https://docs.scanoss.com/en/latest/developer-tools/recipes/licence-and-vulnerability-gate.md) over the `scanoss-cli` result |
| `inspect gitlab` code-quality report | Earnie, or keep this step on `scanoss-py` |
| `export dt` (Dependency-Track upload) | Earnie, which keeps components, licences, and vulnerabilities per project. Or upload a CycloneDX file from `scanoss-cli` yourself. |
| `--format csv` and `convert --format csv` | Earnie reports and exports |
| `container-scan` | Keep this step on `scanoss-py` |
| `folder-scan`, `folder-hash` | Keep this step on `scanoss-py` |
| `delta`, `file-count`, `utils`, `component semgrep` | Keep this step on `scanoss-py` |
| `scan --stdin`, `--files`, `--files-from` | Scan a folder or a single file. The [pull request Recipe](https://docs.scanoss.com/en/latest/developer-tools/recipes/scan-pull-requests.md) shows how to scan only changed files. |
| `--skip-snippets`, `--hpsm`, engine `--flags` | No equivalent |
| `--timeout`, `--retry` | No equivalent |
| Scancode options (`--sc-command`, `--sc-timeout`) | No equivalent. Dependencies are read from your files instead. |

If you rely on policy checks, reports, or exports, look at [Earnie](https://docs.scanoss.com/en/latest/earnie/introduction.md).
It does these for every repository you connect. See
[Migrating from SCANOSS Tools](https://docs.scanoss.com/en/latest/earnie/migrating/from-scanoss-tools.md). Anything you keep on
`scanoss-py` keeps working on v2.

## Migrate a CI pipeline

**1. Swap the image or the install step**

If your job runs in `ghcr.io/scanoss/scanoss-py`, switch to `ghcr.io/scanoss/scanoss`.
That image has no shell, so it suits a job that runs one `scanoss-cli` command. If your job
runs a shell script, install the binary in the job instead. The
[pull request Recipe](https://docs.scanoss.com/en/latest/developer-tools/recipes/scan-pull-requests.md) shows how, with a
checksum check.

**2. Rename the environment variables**

Keep `SCANOSS_API_KEY` as a secret. Replace `SCANOSS_SCAN_URL` with `SCANOSS_API_URL`, set
to the base URL only. If you use the hosted API, you don't need to set a URL at all.

**3. Change the commands**

Use the [command](#commands) and [flag](#flags) tables. Move `--skip-extension` and
`--skip-folder` into `settings.skip.patterns` in `scanoss.json`. Decide whether you want
header skipping on (see [Behaviour changes](#behaviour-changes-that-alter-results)).

**4. Rewrite anything that reads the output**

Move every `jq` filter and script to the [raw format](#output-formats). If a step only
needs an SBOM, ask for CycloneDX or SPDX directly with `--format`.

**5. Rebuild your gates**

Replace `scanoss-py inspect` checks with a Recipe:
[Scan every pull request](https://docs.scanoss.com/en/latest/developer-tools/recipes/scan-pull-requests.md) for
undeclared components,
[Licence and vulnerability gate](https://docs.scanoss.com/en/latest/developer-tools/recipes/licence-and-vulnerability-gate.md)
for licences and vulnerabilities, and
[Generate an SBOM for each release](https://docs.scanoss.com/en/latest/developer-tools/recipes/release-sbom.md) to
publish SBOMs.

**6. Run both for a while**

Keep the old `scanoss-py` job, set not to block, next to the new one until the results
agree. Then remove it.

## Verify the migration

Scan the same commit with both tools and compare the components each one found:

```bash theme={null}
# Before: scanoss-py
scanoss-py scan . --key "$SCANOSS_API_KEY" --output before.json
jq -r '[.[][] | select(.id != "none") | .purl[0]] | unique[]' before.json > before.txt

# After: scanoss-cli
scanoss-cli scan . --output after.json
jq -r '[.components[] | select(.scope == "detected") | .purl] | unique[]' after.json > after.txt

diff before.txt after.txt
```

Some differences are expected, mostly from header skipping, `.gitignore`, and skipped model
files. To see how much header skipping accounts for, scan again with `--skip-headers=false`. If a
component you expected is missing, try `--max-components all` to see every candidate the server
found.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.