Reference
Every command, option, status and file format in Remixware 0.2. The README that ships with the program covers the same ground.
Commands
remixware index <folder>... [--out FILE] fingerprint third-party code into an index
remixware scan [project] --index FILE compare a project with indexes, list the matches
remixware check [project] --index FILE the same, as a pass/fail gate for CI
remixware notice [project] --index FILE write third-party notices for what you copied
remixware licenses list the licences Remixware knows
remixware version
scan, check and notice compare the project with --index files, with --from results files, with the SCANOSS service (--scanoss), or with any mix of them. The project defaults to the current folder. Flags can come before or after it, and remixware help <command> lists a command’s flags.
index
| Option | What it does |
|---|---|
--out FILE |
The index file to write. Default remixware.rmx |
--name NAME |
Component name for the folder, when you index one folder |
--version V |
Component version for the folder, when you index one folder |
--license EXPR |
Licence of the components, as an SPDX expression, instead of what Remixware finds. A file’s own header or SPDX tag still adds to it |
--exclude PATTERN |
Leave out paths that match. Repeatable |
--max-common N |
Drop fingerprints found in more than N components. 0 picks a value, -1 keeps all |
--quiet |
Print nothing but errors |
Components are found by go.mod, package.json, Cargo.toml, composer.json, pyproject.toml and .dist-info folders, and by folders with a licence file. A component’s licence comes from its manifest, its licence files and a REUSE LICENSES/ folder. A folder with no licence of its own takes the licence of the folder above it, except across node_modules, vendor, third_party and similar folders.
- Several licence files all apply, except files that each name one licence, such as
LICENSE-MITandLICENSE-APACHE, or a short file saying the project is dual licensed: those are a choice, as inApache-2.0 OR MIT. - A crate with
license.workspace = truetakes its workspace’s licence when the workspace is inside the indexed folder, and Python distributions that share a folder are told apart by theirRECORDfiles. - A file’s own header can say more. An
SPDX-License-Identifierline in the comments at its top is that file’s licence. A licence notice there that differs from the component’s is counted along with it, so a file headed MIT inside a GPL project counts as both. Licences a header offers as a choice (“BSD, or alternatively the GPL”, “either the GPL or the CDDL”, “at your option”) count as one; a GNU notice’s “version 2, or (at your option) any later version” is a choice of versions only. Where the component has no licence, a header that only names the licence of the code it came from gives the file none. Code never counts, only comments. - A licence text with a condition on top, such as the Commons Clause after the Apache License, counts as both.
- Symbolic links aren’t followed, only regular files are read, and nothing outside the indexed folders is read, even when a manifest names a licence file there through a link.
scan, check and notice
| Option | What it does |
|---|---|
--index FILE |
An index made by remixware index. Repeatable |
--from FILE |
A SCANOSS results file (scanoss-py scan -o FILE, or --scanoss-out) or a findings file from remixware scan --json. Repeatable |
--scanoss |
Also ask the SCANOSS service. Only fingerprints are sent, see SCANOSS |
--scanoss-key KEY |
A SCANOSS API key. Default: SCANOSS_API_KEY |
--scanoss-url URL |
The SCANOSS service to ask; Remixware asks /scan/direct on its host. Default: SCANOSS_SCAN_URL, else https://api.osskb.org, or https://api.scanoss.com with a key |
--scanoss-out FILE |
Save SCANOSS’s answers as a results file, which --from reads |
--license EXPR |
Your project’s licence, instead of its licence file or the policy |
--policy FILE |
The policy file. Default .remixware.json in the project, if there is one |
--exclude PATTERN |
Leave out project paths that match. Repeatable |
--include-deps |
Also scan vendor, node_modules, third_party and virtual environments |
--min-tokens N |
Smallest match from an index to report, in tokens. Default 50 |
--min-lines N |
Smallest match from an index to report, in lines. Default 5 |
--quiet |
Print only the findings and errors |
--json FILE |
(scan, check) Write the findings as JSON |
--html FILE |
(scan, check) Write a self-contained HTML report |
--spdx FILE |
(scan) Write an SPDX 2.3 document |
--fail-on LIST |
(check) Statuses that fail the check, comma separated |
--out FILE |
(notice) Notices file to add entries to. Default: print them |
--all |
(notice) Also write entries for copies that are already credited |
An index can hold code inside your project, such as your own vendor folder, or the whole project when you index a folder above it. Indexed code inside the project is third-party code when it sits in a folder such as vendor or third_party, has a licence of its own that differs from the project’s, or comes from an index of a folder inside the project: the rest of the project is checked for code copied from it, and no file is reported as a copy of the component it’s part of. Everything else inside the project is the project’s own code, scanned like the rest, and nothing is reported as copied from it. An index never makes a scan skip a file. Symbolic links in the project aren’t followed, and the scan says how many it passed over.
An index is data. One made elsewhere can’t show a scan a file on your machine that it doesn’t hold: an indexed file is read back only when its bytes match the checksum in the index. One that doesn’t hold together, unpacks to far more than its size or lists more files than it could hold is refused as damaged.
Results files, findings files and SCANOSS answers are data too. Characters a terminal acts on (escape sequences, line breaks inside a name, direction marks) are taken out of their text and of the text in indexes, which otherwise stays as it is so copyright lines still match, and everything Remixware prints goes through the same filter. A copyright line that would start a Markdown block in a notices file is escaped. An entry whose path points outside the project, or holds such characters, is left out with a warning, and check then exits with 2. A results file may give one file at most 100 SCANOSS matches, each listing at most 100 licences, copyright lines or package URLs, and a findings file at most 20,000 findings per file, each with at most 100 copyright lines.
SCANOSS
With --scanoss, Remixware fingerprints the files a scan reads, plus the minified files a scan skips (.min.js and .min.css files, and source files with very long lines), which SCANOSS can name as a whole, and sends the fingerprints to the SCANOSS service in batches of up to 32 files. It makes them the way SCANOSS’s own scanner does, with one difference: that scanner takes a few text files for binary by their first bytes, such as a source file starting with “BM”, and sends no hashes for them, while Remixware hashes them. For each file it sends a number with the file’s extension, the file’s MD5 checksum and size, a second checksum taken with the other kind of line endings, and hashes of short runs of the file’s letters and digits: no code and no file names. Each request also names Remixware’s version and carries a random request ID, and your API key if you set one. The answers come back about the numbers. An answer about anything Remixware didn’t send is dropped, and an answer has to cover every file sent: one that leaves files out is asked for again, and then the command exits with 2.
The free service at https://api.osskb.org is run by the Software Transparency Foundation, under its terms. When the service asks Remixware to slow down, Remixware waits as long as it asks, a minute at a time, and tries again, up to five times, with a line saying so. When it asks for a longer wait than that, as it does once a usage limit is used up, Remixware stops and says how long, and for a long wait until when. A SCANOSS API key avoids the free service’s limits. Remixware asks /scan/direct on the host of the URL it’s given, as SCANOSS’s scanner does, and doesn’t follow redirects, which could take the key and the fingerprints elsewhere. A user name, password or query in the URL never shows up in output or reports.
Exit codes
| Code | Meaning |
|---|---|
| 0 | All went well, and check found nothing that breaks the policy |
| 1 | check found findings that break the policy |
| 2 | Bad arguments, an unreadable or damaged file, a check that found no source files to scan or none to send to SCANOSS, a SCANOSS service that didn’t answer or turned the request away, a check with a results file it could only read in part, or another error |
Statuses
| Status | Meaning |
|---|---|
conflict |
The copied code’s licence can’t be combined with your project’s licence as it stands, for example GPL code in an MIT project |
no-license |
No licence was found for the source, so nobody has given permission to copy it |
review |
A person has to look: a file-level copyleft licence such as MPL-2.0 or LGPL, code that fits only if your project moves to another licence version (Apache-2.0 into GPL-2.0-or-later), a licence text Remixware doesn’t recognise, or the same code also found under stricter terms. A copy that also needs its notice shows as attribution-missing until your notices have it |
attribution-missing |
The licence allows the copy, but its copyright line and licence text have to ship with your code, and your notice files don’t have them |
attributed |
Allowed and credited: your notice files name the source, or the copied file kept its original copyright header |
allowed |
Accepted by a rule in your policy file |
ok |
Public domain or similar: nothing to do |
check fails on conflict, no-license and attribution-missing unless the policy or --fail-on says otherwise. Without any licence, your own project is treated as proprietary.
Each finding also says how the code was copied: verbatim (as is, perhaps reformatted or with comments changed), edited (some lines changed), renamed (names changed throughout), and for SCANOSS results file or snippet. Its ID, such as RW-5441d221, stays the same from scan to scan while the file and the source stay the same.
Notice Files
A source counts as credited when one of your notice files has its full component name (such as github.com/acme/tool or [email protected]), its repository address, its package URL, one of its full copyright lines, or the Source: line that remixware notice writes, as a whole word: github.com/acme/tool-extras doesn’t credit github.com/acme/tool. A bare name like errors doesn’t count, since it’s an everyday word, and neither does an entry remixware notice left for you to finish.
Without notice_files in the policy, Remixware reads files in your project’s top folder named like NOTICE, THIRD_PARTY_NOTICES.md, CREDITS, ATTRIBUTION or ACKNOWLEDGEMENTS, and every file in folders such as licenses/ and third_party_licenses/.
Policy File
Put .remixware.json in your project’s top folder, or pass --policy FILE. Every field is optional. Unknown fields are errors, so a typo can’t quietly switch a rule off.
{
"license": "MIT",
"fail_on": ["conflict", "no-license", "attribution-missing"],
"ignore": ["testdata/**", "docs/examples/**"],
"notice_files": ["THIRD_PARTY_NOTICES.md"],
"allow": [
{"component": "github.com/acme/*", "reason": "Acme gave us a commercial licence in 2025"},
{"license": "MPL-2.0", "file": "third_party/mpl/**", "reason": "MPL files are kept unchanged and published"}
],
"min_tokens": 50,
"min_lines": 5
}
| Field | What it does |
|---|---|
license |
Your project’s licence, as an SPDX expression |
fail_on |
The statuses that make check fail. An empty list is an error |
ignore |
Project paths not to scan. * stays inside a folder, ** crosses folders, and a bare name matches at any depth |
notice_files |
Where you credit third-party code, when the defaults don’t find it. Folders are read file by file |
allow |
Findings you accept on purpose. Each rule names a component (* works as a wildcard), a file pattern, a license, or several of them, and must give a reason |
min_tokens, min_lines |
The smallest match from an index to report |
Reports
- HTML (
--html): one self-contained page with every finding and the reason for each status, with your code next to the source for matches from an index, and a link to the source for SCANOSS matches. It works offline and in dark mode. - JSON (
--json):findings, each withid,file,lines,status,reason,sourceandmatch, pluscountsper status and what was scanned.inputslists what the project was compared with, each with akind:index,scanoss(a results file),remixware(a findings file) orscanoss-api(the SCANOSS service, with its URL and the number of files sent), and for a results or findings file the number of entriesdropped.--fromreads it back. - SPDX (
--spdx): an SPDX 2.3 document in JSON with each copied snippet’s byte and line ranges, its source, its licence and its copyright lines. - Notices (
remixware notice): Markdown entries with the copyright lines, the licence texts and the files that use the code. Each entry carries the component’s own licence files when the index has them, and the standard text of any other licence the copy is under, built in for MIT, BSD-2-Clause, BSD-3-Clause, ISC, Zlib, BSL-1.0, Apache-2.0 and MPL-2.0. Whatnoticecan’t find, it asks you to fill in.
How Matching Works
Remixware reads source as tokens: it drops comments and layout, keeps keywords, operators and literals, and numbers each name in the order it first appears. A copy with new spacing, comments or variable names gives the same tokens. It hashes every run of 17 tokens and keeps a sample of those hashes, chosen so that a shared run of 28 tokens or more always leaves a shared hash. Hashes shared with an indexed file are chained into stretches that move through both files together. A stretch becomes a finding when it covers at least 50 tokens and 5 lines; when only the shape matches and the names don’t, it has to cover more, with fewer gaps, and where a line matches exactly, names included, that place wins over look-alike lines. Code that everyone writes the same way, such as a run of near-identical lines or Go’s sort.Interface methods, isn’t matched, and neither are tables of numbers or strings with no names in them, such as a hash function’s constants.
Remixware reads Go, C and C++, Objective-C, Java, C#, Dart, Kotlin, Swift, Scala, JavaScript and TypeScript (with Vue and Svelte files), Rust, Python, Ruby, PHP, shell, Perl, SQL, Lua, CSS and SCSS, R, Julia, Elixir, Nim, PowerShell and Tcl. Generated, minified and binary files are skipped, and so are files over 2 MB. With --scanoss, minified files go to SCANOSS too.