config.json, input/ and output/ live. Each one first runs scripts/build.sh, an incremental Rust and TypeScript build that takes about a second when nothing changed, then runs the TypeScript CLI (cli/dist/index.js). Flags go after --, otherwise npm swallows them.
npm commands
init
config.json, records version 1 of every allowlist source it finds, checks the environment, and prints the operator public key. Without flags and with a terminal attached it prompts for the four issuer values. Nothing is destructive: an existing config.json or key file is kept and reported unless --force is given.
Exit 0 when the tree is ready, 1 when a blocking check failed or a required value was missing. An empty
input/ is reported and does not block.
start, hash
npm run hash is the same command. Reads input/, validates every row, proves every valid subject, writes bundles and the index file to output/. Needs both keys loaded, except under --dry-run.
Exit 0 when every row produced a bundle, 2 when some did and some failed, 1 when none did or the run aborted before proving.
--dry-run exits 0 when clean and 2 when it found problems. An empty input/ prints a message and exits 0. Input records has the outputs.
verify
output/<wallet>, or one subject of an archive. <wallet> is the checksummed address printed by npm start, which is the bundle directory name. At least one anchor is required.
The registry directory from
config.json is passed to the binary automatically, so as-of block queries resolve against config/registry without a flag. Exit codes: 0 verified and entitled, 2 failed, 3 verified but not entitled, 64 usage error from the binary, 66 unreadable, and 1 when no anchor was given. Verification explains each.
show
- the hashed fields and their circuits, and the passthrough columns,
- the tier map,
- each list’s root, depth and size,
- the key environment variable names, the epoch source and the config hash,
- the operator public key, when the signing key is loaded,
- every leaf’s claim descriptor,
- the registry summary. It works with an unpinned epoch and without keys, in which case it says the key is unavailable.
--jsonemits the same as one object, includingconfigHash,epochDays,asOfDateandunpinnedEpoch.
list-version
config/registry/lists/<id>.json, signed with the signing key. --effective-date defaults to today and also accepts a days-since-1970 integer. --allow-duplicates dedupes repeated entries instead of failing. Refuses unchanged values and a start date on or before the current version’s. Exit 0 recorded, 1 refused, 64 usage. Details on Registries and archives.
anchor
kycHash was published at that block, in config/registry/root_history.json. Recording the same publication twice is a no-op; a different root at the same height is refused. Exit 0, 1 or 64.
revoke
lapsed requires --effective-date; void_ab_initio rejects it. --leaf names one leaf, otherwise every leaf. --reason is a short machine-readable code of your choosing, recorded verbatim. Exit 0, 1 or 64.
archive
--all takes every bundle directory under <dir>; --bundle names them. --include-secrets embeds each secrets.enc, off by default. Exit 0, 1 or 64.
decrypt
prover/tests/end_to_end.rs, and exits 70. The suggested alternative is to re-run npm start over the original records with the same pinned date and master key, and compare byte for byte.
build
scripts/build.sh on its own: cargo build --release --workspace, the WASM verifier when the wasm32-unknown-unknown target is installed, and tsc for the CLI. npm install runs the same script as its postinstall step.
--json is accepted by init, hash, verify and show only. The registry and archive commands pass their output straight through from the native binary.
Native binaries
The npm commands wrap five binaries undertarget/release/. They can be called directly, which is how a counterparty verifies on a machine without the repository. Each prints usage with --help.
trusset-prover
The proving engine. It reads one JSON job from stdin, emits newline-delimited JSON events on stdout, and writes bundles.npm start builds the job from config.json and the input records; the job schema is in docs/ARCHITECTURE.md and prover/src/job.rs.
Events: start, subject_start, leaf_proved (with proof_bytes and ms), leaf_failed (dry run only), subject_done, subject_failed (with error_code and message), done. Stderr carries unstructured logs, which the CLI prefixes with [prover].
At startup it checks that the pinned proof parameters meet the published security floor and exits 1 with E_WEAK_PROOF_OPTIONS otherwise. It refuses utc_today unless the job carries the development flag. Exit 0 all subjects done, 2 some failed, 1 batch-aborting.
One flag exists:
--rekey-subject <dir> unwraps the bundle’s per-subject key under the old master key and re-wraps it under the new one, rewriting secrets.enc in place. The manifest, its signature, kycHash.hex and every proof are untouched, so the signature stays valid and the published root still matches. Only bundles with secretsKdfVersion: 2 support it; a version 2.0 bundle must be re-proved to move to a new master key.
trusset-verifier-cli
--subject selects one subject of an archive; without it every subject is verified. --registry names the signed registry root for as-of resolution, default config/registry relative to the working directory, and is ignored when reading an archive. Dates accept YYYY-MM-DD or a days-since-1970 integer. Exit codes 0, 2, 3, 64 and 66 as on Verification.
trusset-registry
--registry <DIR>, default config/registry. Every write needs TRUSSET_KYC_SIGNING_KEY in the environment. show, which has no npm wrapper, prints every list version with its window, every anchor and every revocation. Exit 0 recorded, 1 failed, 64 usage.
trusset-archive
trusset-list-commit
list-version runs the same code and records the result in the registry instead, which is what a version 3.0.0 run requires. Exit 0, 64 usage, 65 bad data, 66 unreadable source, 73 cannot write.
Environment variables
Binary discovery
The CLI looks for each binary intarget/release/ then target/debug/, walking up to five directories from the working directory, and falls back to the name on PATH. An environment variable overrides the search:
The last two names are derived mechanically from the binary name (
TRUSSET_ plus the upper-cased name), which is why TRUSSET appears twice. They are what the current code reads and may change in a later version.Test and build scripts
In the repository
- README.md, the commands section
- cli/src/index.ts, the command definitions
