Command line reference
Read this if you run
laidlinecommands and need the exact options, defaults and exit codes. You will find every command, grouped as the CLI groups them, with its options and one example. Skip if you want a first marked image (Quickstart) or a configuration key (Configuration). Time: 2 minutes to find a command. Needs:pip install laidline(theserver,ingest,kmsandevidenceextras for the commands that name them).
In short
laidline --helplists the eight commands and seven command groups below;laidline GROUP --helplists a group's commands.- Every command that reads a configuration takes
--config FILE, elseLAIDLINE_CONFIG, else./laidline.yaml, else/etc/laidline/config.yaml. laidline servebinds127.0.0.1:8080unless you pass--host.- A command that fails prints
error: <reason>on stderr and exits 1, unless its section names another code. laidline benchneeds the separatelaidline-benchpackage.
Check your install with laidline --version, which prints the version and exits. The other global options are
--install-completion and --show-completion, which install or print shell completion for your current shell.
laidline --version
1.0.1
Before you use a command
- Configuration.
laidline initwrites the file the other commands read. See Configuration for every key. - Model weights. Marking and detecting images, audio and video download their pinned weights on first use into
$LAIDLINE_HOME/models.laidline models fetchdoes it ahead of time. - Errors. A failed command writes one line,
error: <reason>: <detail>, to stderr. The exit code is 1 unless the command's section lists another.
Commands at a glance
| Command | What it does |
|---|---|
laidline init |
Write a starter configuration, a payload key and a development certificate chain |
laidline serve |
Run the HTTP sidecar |
laidline ingest |
Run the storage-hook worker |
laidline mark |
Mark one image, audio or video file |
laidline detect |
Grade a file |
laidline verify-result |
Check a signed detect result offline |
laidline bench |
Run a watermark robustness benchmark |
laidline register |
Register this deployment with the issuing service |
laidline keys |
Signing keys and certificates: dev-cert, csr, rotate, list |
laidline evidence |
Export and verify evidence: export, verify, check-slots, init-db |
laidline models |
Download model weights: fetch |
laidline payload-keys |
Watermark payload keys: generate, list, fingerprint, retire |
laidline licence |
Licences: fetch, install, status |
laidline issuer |
Issuer certificate and directory snapshot: install, refresh |
laidline usage |
Usage statement and the monthly usage report: usage, usage report |
The --config FILE option (environment variable LAIDLINE_CONFIG) is left out of the option tables below. Every
command that reads a configuration takes it.
init
laidline init [OPTIONS]
Writes a starter laidline.yaml, a payload key file payload-k1.key (mode 0600) and, unless you pass --no-certs, a
development certificate authority and signing certificate in ./certs/. It draws a random trial issuer number. It
refuses to overwrite an existing file.
| Option | Default | Meaning |
|---|---|---|
--path FILE |
laidline.yaml |
The configuration file to write |
--system-name TEXT |
my-ai-system |
Your AI system's name (system.name) |
--system-version TEXT |
1.0 |
Its version (system.version) |
--org TEXT |
Example Org |
Organisation for the development certificate and the evidence log |
--certs / --no-certs |
--certs |
Also write a development certificate chain |
Example:
laidline init --system-name my-image-model --org "Yourcompany Inc"
wrote laidline.yaml and ./certs/ (development only; use your KMS and a C2PA trust-list certificate in production) One usage report a month (counts only, no media) is sent to your issuer; set issuer.usage_report: false to turn it off issuer 35443 is a trial number, so marks are shared marks (grade D, provider not identified). laidline register --email <you@yourdomain> --display-name "<Your Company Inc>" --plan registered_free gets a registered number, a private key bound to your name and attributable marks (https://laidline.com/docs/licensing).
Your trial number differs: it is random. The development certificate is for trying Laidline out. Production uses your KMS and a certificate from the C2PA trust list (Certificates).
serve
laidline serve [OPTIONS]
Runs the sidecar: the native mark and detect routes, the OpenAI-compatible proxy, health checks and metrics. Every
route is in the HTTP API reference. It needs the server extra.
| Option | Default | Meaning |
|---|---|---|
--host TEXT |
127.0.0.1 |
The address to bind. 0.0.0.0 listens on all interfaces |
--port INTEGER |
8080 |
The port to bind |
The default bind is loopback only. To reach the sidecar from other hosts, pass --host 0.0.0.0 (the Docker entrypoint
does) and set server.mark_token_env so the mark routes need a bearer token (HTTP API reference).
The start-up log names the bind:
laidline serve
2026-10-26 08:55:52,623 INFO laidline.cli listening on 127.0.0.1:8080 (loopback only) ... INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
laidline serve exits 1 with error: <reason> when the configuration is invalid. curl localhost:8080/readyz
reports whether the start-up self-test mark succeeded.
ingest
laidline ingest [OPTIONS]
Runs the storage-hook worker against the configured S3 with SQS, R2 with Queues or local directory source. It needs the
ingest extra. See S3 and SQS for the setup.
| Option | Default | Meaning |
|---|---|---|
--max-batches INTEGER |
run forever | Stop after this many polls |
Example:
laidline ingest --max-batches 1
The command polls the source once and exits.
mark
laidline mark [OPTIONS] PATH
Marks one image, audio or video file: the watermark, the Content Credentials where the container carries them, and an
evidence entry. The bytes decide the kind of file; the extension only settles what they cannot. Audio keeps its
container unless you name another with --fmt. Raw PCM has no sample rate, so the command refuses it. Video (MP4 or
MOV) is written as MP4.
| Option | Default | Meaning |
|---|---|---|
--out FILE |
NAME.marked.EXT beside the input |
Where to write the marked file |
--fmt TEXT |
the input's format | The output format, for example png, jpeg or mp3 |
Example:
laidline mark photo.png
{
"out": "photo.marked.png",
"asset_id": "ast_01M5W4M2TAEKG2PCHJYP8XRGH6",
"manifest_id": "urn:c2pa:ee943d64-d701-4dba-ae20-3a1bae7430f4",
"entry_hash": "c58129c5820548902596507903dc23cd61f6a02a3ad5dac6d43b20691dce248e",
"warnings": []
}
If the timestamp server does not answer, the command exits 1 and the message says to set signing.tsa.required: false
or point signing.tsa.url at a server this host can reach (Production setup).
detect
laidline detect [OPTIONS] PATH
Prints evidence-graded detection for a file. It never asserts human origin: a result of none means no signal was
found, not that a person made the file. The grades are in Grading.
| Option | Default | Meaning |
|---|---|---|
--json |
off | Print the full laidline.detect/1 result as JSON |
--text |
off | Treat the file as UTF-8 text and check the text watermark |
--model TEXT |
none | The tokenizer id, or a local directory, for --text |
--confirm |
off | Ask the checker the signed directory lists for the file's issuer, and verify its signed reply |
--save-result FILE |
none | With --confirm: write the checker's signed reply to this file |
Example:
laidline detect photo.marked.png
verdict: marked_by_this_system grade: A
c2pa present=True grade=A status=valid_trusted
watermark present=True grade=D status=shared mark
issuer: shared mark, provider not identified
note: Absence of a signal is not evidence that content is human-made.
note: Revocation status was not checked (OCSP disabled in this deployment).
The command exits 0 whatever the grade. With --confirm it exits 0 only when the issuer's checker confirmed the mark
in this file. Keep the signed reply with --save-result reply.json and check it later with
verify-result.
verify-result
laidline verify-result [OPTIONS] RESULT.json --file FILE
Checks a signed detect result, a checker's reply, offline. The signing key must be one the signed directory binds to
the issuer the result names, the signature must verify, and the statement must be about FILE and name that issuer's
checker. It prints the issuer line and exits 0 when the signature verifies (confirmed or not), 1 otherwise.
| Option | Default | Meaning |
|---|---|---|
--file FILE |
required | The file the result is about; its SHA-256 must match the statement |
--directory FILE |
the configured snapshot, else the shipped one | A directory snapshot file to check against |
Example:
laidline verify-result reply.json --file photo.marked.png
verify-result: confirmed by issuer 1234 (Example Org, operator of example.org) at https://example.org/detect on 2026-10-26T09:12:44Z verify-result: verdict marked_by_this_system, grade B, tier public, issued 2026-10-26T09:12:44Z
The issuer number, name and times are those in your result. Other issuer lines are listed in
Grading. A result that carries no signature prints verify-result: unsigned result; it is not a confirmation and exits 1. Unreadable inputs exit 2.
bench
laidline bench [OPTIONS] [SUITE]
Runs a watermark robustness benchmark on your own media: embed, transform and decode for image, audio and video; generate,
transform and detect on a C4 shard for text. It needs the separate laidline-bench package (pip install laidline-bench). Without it the command prints laidline bench needs the laidline-bench package: pip install laidline-bench to stderr and exits 2. Benchmarks lists the suites and the figures each one
reproduces.
SUITE is image (TrustMark), audio (AudioSeal), video (VideoSeal and the keyframe scheme) or text (SynthID and
KGW). The default is image.
| Option | Default | Meaning |
|---|---|---|
--corpus DIR |
none | A directory of unmarked media; for text, a C4 shard or a JSON-lines file |
--n INTEGER |
50; 20 for video and text | Images, clips or prompts to sample (seeded) |
--workers INTEGER |
2 |
Worker processes, each with its own watermark models |
--modes TEXT |
both | Audio only: batch, streaming or batch,streaming |
--transforms TEXT |
the suite's set | Comma-separated transform names, or all |
--out FILE |
SUITE-robustness-DATE.json |
Where to write the JSON result |
--device TEXT |
the harness's own | cpu, cuda or auto (video also cuda:N); for text, where the generating model runs while detection stays on the CPU |
--schemes TEXT |
both | Video only: videoseal, trustmark_keyframes or both |
--model TEXT |
none | Text only: the generating model, a Hugging Face id or a local directory |
--music-bed FILE |
none | Audio only: the music file the music_bed_10db transform mixes in (the row is not run without one) |
--sweeps / --no-sweeps |
image off; video and text on; audio on the first --sweep-n clips |
Run the parameter sweeps |
--sweep-families TEXT |
all | Image and video only: comma-separated sweep families |
--sweep-n INTEGER |
the harness's own | How many items of the sample run the sweeps |
--resume |
off | Continue the interrupted run checkpointed next to --out (same arguments) |
--gen-batch INTEGER |
1 on CPU, 8 on CUDA | Text only: prompts per generate call |
Example:
laidline bench image --corpus ./photos --n 50 --out image-run.json
The command embeds, transforms and decodes 50 photos and writes the per-transform results to image-run.json.
register
laidline register --email ADDRESS --display-name NAME [OPTIONS]
Registers this deployment with the issuing service. Registration gets a registered issuer number, a licence and an issuer certificate bound to your signing key and the active payload key. A free plan issues once you follow the link in the email; Laidline verifies and installs the documents, then prints a summary. Plans and prices are at https://laidline.com/licensing.
You must accept the Laidline Customer Licence Agreement: pass --accept-terms, or answer y
at the prompt on a terminal. The acceptance is signed into the request.
| Option | Default | Meaning |
|---|---|---|
--email ADDRESS |
required | An address at your organisation's domain; it receives the link |
--plan TEXT |
registered_free |
registered_free, lite, starter, growth or scale |
--interval month|year |
month |
How a paid plan is billed. A free plan accepts it and ignores it (a free licence runs 12 months) |
--display TEXT |
public |
Always public: the directory shows your name and domain beside your number |
--display-name TEXT |
required | The public name; it must contain your verified domain's label, as Acme Inc does for you@acme.com. The command stops before sending anything when it is missing |
--country TEXT |
none | ISO 3166-1 alpha-2 country code |
--detect-url URL |
none | Your public /detect URL (https) |
--disclosure-url URL |
none | Your AI disclosure page (https) |
--name TEXT |
system.provider_legal_name |
Your legal name |
--usage TEXT |
none | A note on your intended use, sent in the request |
--accept-terms |
off | Accept the Laidline Customer Licence Agreement |
--wait / --no-wait |
--wait |
Wait for the email link to be followed |
--timeout TEXT |
30m |
How long to wait: 90s, 30m, 2h |
Example:
laidline register --email you@yourcompany.com --display-name "Yourcompany Inc" --accept-terms
check you@yourcompany.com for the link (registration reg_...) waiting for the link to be clicked ... installed /var/lib/laidline/licence/licence-....json licence ...: plan registered_free, valid until 2027-10-26 issuer 1234: display public as Yourcompany Inc issuer: registered 1234 as Yourcompany Inc reload: send SIGHUP to laidline serve or restart it
Your registration id, issuer number and dates differ.
If the command stops waiting before you follow the link, it prints resume with: laidline licence fetch REGISTRATION_ID; run it with laidline licence fetch. A running laidline serve picks up the new documents on SIGHUP or restart.
The issuing service hands out the documents only with a documents proof signed by the signing key the registration
binds (the documents proof): register, licence fetch and automatic renewal sign a new
one with the active signing key for each fetch. A rotated key must be bound, by running register again, before it
can fetch.
keys
Signing keys and certificates. dev-cert, csr and rotate take the same options to name the key they act on.
Key selection options
| Option | Default | Meaning |
|---|---|---|
--key-path FILE |
none | A local EC P-256 private key (PEM). Development only |
--kms-key-id TEXT |
none | An AWS KMS key (key spec ECC_NIST_P256) |
--region TEXT |
$AWS_DEFAULT_REGION |
The AWS region of the key |
--vault-key TEXT |
none | A Vault or OpenBao Transit key (type ecdsa-p256) |
--vault-addr TEXT |
$VAULT_ADDR |
The Vault or OpenBao address |
--vault-mount TEXT |
transit |
The Transit mount path |
--vault-key-version INTEGER |
the latest | The Transit key version (1 or higher) |
--vault-namespace TEXT |
none | The Vault Enterprise namespace (hvac ignores VAULT_NAMESPACE) |
--vault-ca-cert FILE |
none | A CA bundle (PEM) that Vault's TLS certificate chains to, for private CAs |
--vault-token-env TEXT |
VAULT_TOKEN |
The environment variable that holds the Vault token |
keys dev-cert
laidline keys dev-cert [OPTIONS]
Mints a development certificate authority and signing certificate. Validators report "valid, not trusted" unless you load the authority as an anchor. With a key selection option the certificate covers that key and no private key file is written.
| Option | Default | Meaning |
|---|---|---|
--out-dir DIR |
./certs |
Where to write dev-chain.pem, dev-ca.pem and, without a key option, dev-key.pem |
--org TEXT |
Example Org |
Organisation (O) of the certificate and the authority |
--cn TEXT |
laidline dev |
Common Name (CN) of the certificate |
Plus the key selection options.
laidline keys dev-cert --out-dir ./certs2 --org "Example Org"
wrote ./certs2/dev-key.pem, dev-chain.pem, dev-ca.pem
keys csr
laidline keys csr --out FILE --org TEXT --cn TEXT [OPTIONS]
Creates a certificate signing request (CSR) for a certificate authority on the C2PA trust list. The key itself signs the request (KMS, Vault Transit or a local key; the default is the configured signing key). Only the public key leaves the KMS or Vault. See Certificates for what to send the authority.
| Option | Default | Meaning |
|---|---|---|
--out FILE |
required | The CSR (PEM) to write |
--org TEXT |
required | Organisation (O); C2PA validators need it in the certificate subject |
--cn TEXT |
required | Common Name (CN) |
--country TEXT |
none | Country (C), a two-letter code |
--eku email|document-signing|both |
email |
The requested ExtendedKeyUsage: emailProtection, id-kp-documentSigning (1.3.6.1.5.5.7.3.36) or both |
--force |
off | Overwrite --out |
Plus the key selection options.
laidline keys csr --kms-key-id arn:aws:kms:<region>:<account>:key/<id> --out signing.csr \ --org "Example Org" --cn "Example Org image service"
The command writes signing.csr; the private key never leaves the KMS.
keys rotate
laidline keys rotate --id TEXT --backend BACKEND --cert-chain FILE [OPTIONS]
Adds a signing key to the file named by signing.keys_file and reloads the server. It checks the chain against the key
at --not-before, appends the entry under a lock with an atomic replace, prints the keyring, then reloads the server
with --pid or --admin-url. A new file is seeded with the current key as id default.
| Option | Default | Meaning |
|---|---|---|
--id TEXT |
required | The new key's id: letters, digits, ., _, - |
--backend local|aws-kms|vault-transit |
required | The key's backend |
--cert-chain FILE |
required | The new key's certificate chain (PEM, leaf first) |
--not-before ISO |
now | When the new key takes over |
--retire-previous-at ISO |
none | Set not_after on the key that is active now |
--pid INTEGER |
none | Send SIGHUP to this laidline serve process afterwards |
--admin-url URL |
none | POST URL/admin/reload afterwards, with the bearer token from admin.token_env |
--dry-run |
off | Validate and print the result; write nothing |
Plus the key selection options.
--admin-url must be an https URL, or http to localhost, 127.0.0.1 or ::1. The admin token travels in the
request, so the command refuses plain http to any other host and exits 2.
laidline keys rotate --id k2 --backend aws-kms --kms-key-id arn:aws:kms:<region>:<account>:key/<id> \ --cert-chain k2-chain.pem --pid 4242
keys list
laidline keys list [OPTIONS]
Lists the configured signing keys with their status now. It reads the configuration only and makes no KMS or Vault call.
| Option | Default | Meaning |
|---|---|---|
--json |
off | Print the rows as JSON |
laidline keys list
id backend ref not_before not_after status cert_sha256 default local local:./certs/dev-key.pem - - active c9ae231262dee584d865e87d688aab8a0b6fba06592b9df211cc5cd69b5f9b99
evidence
Evidence log export and verification. See Evidence for what a bundle holds.
evidence export
laidline evidence export --out FILE [OPTIONS]
Exports an evidence bundle (a zip). It holds the log, the checkpoints, the certificates, the compliance texts, a signed
manifest, a standalone verify.py and, unless you pass --without-records, every keyed audio entry's fingerprint
record (fp/). A date range extends to the checkpoint that anchors it. --tenant narrows the counts; the streams stay
whole.
| Option | Default | Meaning |
|---|---|---|
--out FILE |
required | The bundle zip to write |
--from TEXT |
no lower bound | The first day (YYYY-MM-DD, inclusive) or an ISO 8601 UTC timestamp |
--to TEXT |
no upper bound | The last day (YYYY-MM-DD, inclusive) or an ISO 8601 UTC timestamp |
--sink INTEGER |
0 |
The index into evidence.sinks to read; 0 is the authoritative first |
--without-records |
off | Leave the keyed audio fingerprint records (fp/) out |
--tenant TEXT |
none | Count only this tenant's entries in the summary (needs the tenant_reports licence feature) |
The export itself is never locked. A month over the free allowance that no licence unlocks exports with the compliance
paperwork withheld (Licensing). The one refusal is
--tenant without the tenant_reports feature: the command prints error: ... and exits 3.
laidline evidence export --out bundle.zip
{
"out": "bundle.zip",
"streams": 2,
"entries": 6,
"checkpoints": 1,
"unanchored": 4,
"signed": true,
"records": {
"included": true,
"count": 0,
"missing": 0
},
"warnings": []
}
evidence verify
laidline evidence verify [OPTIONS] BUNDLE
Verifies a bundle (a zip or its unpacked directory) with the same code as the bundle's own verify.py. Exit 0 means
verified, 1 an integrity failure (or a skipped check with --strict), 2 unreadable input.
| Option | Default | Meaning |
|---|---|---|
--json |
off | Print the laidline.verify/1 report as JSON |
--strict |
off | Fail when a check is skipped |
--tsa-roots FILE |
the built-in roots | Trusted timestamp root certificates (PEM) |
laidline evidence verify bundle.zip
Laidline evidence bundle: bundle.zip manifest: 11 files listed, signature ok stream host-0ca3df: seq 1..4 (4 entries) ok; no anchoring checkpoint, 4 unanchored stream host-242d81: seq 1..2 (2 entries) ok; anchored to seq 1, 0 unanchored checkpoint host-242d81 [1, 1]: head ok, signature ok, tsa ok licence: absent 2026-10: private 0, shared 2, self-test marks: 1, absent warnings: unanchored_tail:host-0ca3df:4 RESULT: OK
evidence check-slots
laidline evidence check-slots [OPTIONS]
Checks the keyed registry's stored slots and fingerprint records against the evidence chain. The slots (the S3
watermark pointers and the Postgres slot column) are not part of the hash chain: every one must match its entry,
every marked entry must have one and every decoy must be the canonical one. A file sink stores no slot. Every keyed
audio entry's fingerprint record must be stored with its committed length and hash, every decoy record must be
canonical, and every record no entry names is listed as an orphan.
Exit 0 when nothing is found, 1 when something is (one line per finding), 2 when the store cannot be read.
| Option | Default | Meaning |
|---|---|---|
--sink INTEGER |
0 |
The index into evidence.sinks to check |
--records-sample N |
0 (all) |
Check the fingerprint records of N keyed audio entries (seeded) instead of all; lists no orphans |
evidence init-db
laidline evidence init-db [OPTIONS]
Creates the Postgres evidence schema as the migrator and grants the app role SELECT and INSERT only. It is
idempotent. In one transaction it creates the schema, evidence_entries and evidence_checkpoints, their indexes and
the append-only triggers (UPDATE, DELETE and TRUNCATE raise for every role). The triggers bind the app role. The role
that owns the tables (the migrator) or a superuser can still disable or drop them, which the hash chain and the timestamped
checkpoints make evident.
Your database administrator creates the app role first, for example CREATE ROLE laidline_app LOGIN PASSWORD '...',
and gives the sink that role's DSN (evidence.sinks[].dsn_env). The migrator must be a different role. The command
refuses an app role that is a superuser or a member of the migrator role.
| Option | Default | Meaning |
|---|---|---|
--dsn-env TEXT |
LAIDLINE_PG_MIGRATOR_DSN |
The variable that holds the migrator DSN, the role that owns the schema |
--schema TEXT |
laidline |
The schema to create |
--app-role TEXT |
laidline_app |
The existing role the sink connects as |
laidline evidence init-db
The command creates the schema in the database the migrator DSN names and exits 0; running it again changes nothing.
models
models fetch
laidline models fetch [OPTIONS]
Downloads and verifies the pinned watermark weights into $LAIDLINE_HOME/models. Use it to prepare an air-gapped
host. Each file is checked against its pinned SHA-256 before it is kept. It does not yet fetch the TrustMark Q decoder's
ONNX graph (decoder_Q.fp32.onnx) of the keyframe video reader; the reader fetches that on first use unless
LAIDLINE_OFFLINE=1 (Install).
| Option | Default | Meaning |
|---|---|---|
--audio / --no-audio |
--audio |
The AudioSeal generator and detector (about 190 MB) |
--video / --no-video |
--video |
VideoSeal 1.0 (about 230 MB) |
--image / --no-image |
--image |
PixelSeal, the default image scheme (a 1.24 GB checkpoint, kept as its slimmed 309 MB weights) |
laidline models fetch --no-audio --no-video
/home/you/.cache/laidline/models/pixelseal/model.pth (308952624 bytes, from dl.fbaipublicfiles.com)
Each line is a file the command wrote, its size and the host it came from (already present when the file was
already in place). With LAIDLINE_MODELS_MIRROR set, the mirror is tried first and the upstream host is the fallback.
$LAIDLINE_HOME/models is ~/.cache/laidline/models when
LAIDLINE_HOME is unset. Set LAIDLINE_OFFLINE=1 on the host that serves to forbid any model download after this
step.
payload-keys
Watermark payload keys. See Keys for what a key does and does not do.
payload-keys generate
laidline payload-keys generate [OPTIONS]
Generates a payload secret: 64 hex characters from 32 random bytes. With --out the file is created with mode 0600
(and never replaced) and the command prints only the key fingerprints.
| Option | Default | Meaning |
|---|---|---|
--out FILE |
none | Write the secret here (mode 0600) |
--stdout |
off | Print the secret instead; it then reaches your terminal |
--id TEXT |
k1 |
The key id the fingerprints are computed for |
laidline payload-keys generate --out k2.key --id k2
wrote k2.key (mode 0600); key_fp for id k2: image=a0bc6fa1506cdc22 video=59f1ecefe488baaf audio=f493b030607d3144 warning: a new payload key is inert for marking until it is re-bound: run `laidline register` again (the issuer replaces the binding per medium on a renewal). The old key keeps marking while it is bound and live, and stays `verify` afterwards so earlier marks keep confirming.
payload-keys list
laidline payload-keys list [OPTIONS]
Lists the payload keys: id, state, media and the key fingerprint (key_fp) per medium. It resolves each secret and
prints none.
laidline payload-keys list
id state media key_fp k1 active image,video,audio image=79efa0982b664112,video=1cfebef6882886fc,audio=ca389ea92e9fd17e
payload-keys fingerprint
laidline payload-keys fingerprint ID [OPTIONS]
Prints the key_fp of one payload key per medium, as medium=key_fp. ID is the key's id in
watermark.payload_keys.
laidline payload-keys fingerprint k1
image=79efa0982b664112 video=1cfebef6882886fc audio=ca389ea92e9fd17e
payload-keys retire
laidline payload-keys retire ID [OPTIONS]
Acknowledges the retirement of a payload key. It does not retire the key. Marks made under a retired key stop
verifying (grade B or C falls to D), so the command refuses a key with marked entries in the local evidence chain
unless you pass --orphans-marks. It records a config_changed entry (retire_acknowledged, with the orphan count)
and does not edit the configuration: set state: retired for the key in watermark.payload_keys, then restart
laidline. A SIGHUP re-reads only the secrets, never the configuration. The restarted process records the retired
event.
| Option | Default | Meaning |
|---|---|---|
--orphans-marks |
off | Retire even though marks were made under the key; they stop verifying |
laidline payload-keys retire k1
recorded the retirement of payload key k1 (0 marked entries orphaned); the key is still live: set state: retired for k1 in watermark.payload_keys and restart laidline
licence
Licences from the issuing service. See Licensing.
licence fetch
laidline licence fetch REGISTRATION_ID [OPTIONS]
Resumes a registration: polls until the documents are issued, then verifies and installs them. REGISTRATION_ID is the
id register printed (also in its resume command).
| Option | Default | Meaning |
|---|---|---|
--timeout TEXT |
30m |
How long to wait: 90s, 30m, 2h |
The status polls carry no proof. Once the registration is issued, the command fetches the documents with a documents
proof signed by the active signing key (the documents proof), so it needs the
deployment's signing key (exit 1 when none can be built). When the issuing service does not accept that key as the
registration's, the command exits 1 with error: registration REGISTRATION_ID is issued, but the issuer did not accept this deployment's signing key as the registration's; bind it by running laidline register again (a host clock more than five minutes off, or an issuer.registration_url that is not the issuing service's address, also causes this).
licence install
laidline licence install FILE [OPTIONS]
Verifies a laidline.licence file under the pinned roots and copies it into the licence directory. Use it on an
air-gapped host. A licence that lapsed beyond its grace period is refused and nothing is installed.
laidline licence install licence.json
installed /var/lib/laidline/licence/licence-....json licence ...: plan lite, valid until 2027-10-26 reload: send SIGHUP to laidline serve or restart it
licence status
laidline licence status [OPTIONS]
Prints the licence state, plan, allowance, credits used this month, the issuer number and the directory snapshot.
| Option | Default | Meaning |
|---|---|---|
--json |
off | Print one JSON object |
laidline licence status
state: free_within_cap plan: none allowance: none credits this month: image 0, video 0, audio 0 (total 0) suggested band: registered_free marks this month: private 0, shared 0 self-test marks: 0 issuer: unregistered shared number 46958 directory: snapshot 2026-10-21 serial 10 licence: absent
issuer
Issuer certificate and the issuer directory snapshot.
issuer install
laidline issuer install FILE [OPTIONS]
Installs an issuer certificate or a directory snapshot, told apart by its type, after verifying it under the pinned
roots. FILE is the JSON document.
issuer refresh
laidline issuer refresh [OPTIONS]
Fetches the issuer directory snapshot, verifies it and its serial (never backwards) and writes it. A refusal keeps the installed file and exits 1.
| Option | Default | Meaning |
|---|---|---|
--url TEXT |
issuer.directory.refresh_url |
Where to fetch the snapshot |
laidline issuer refresh
The command prints the snapshot date and serial it installed, or error: <reason> and leaves the installed snapshot in
place.
usage
laidline usage [OPTIONS] laidline usage report [OPTIONS]
laidline usage prints the usage statement for a month as JSON: credits and marks by medium, the licence state and the
issuer numbers, counts only.
| Option | Default | Meaning |
|---|---|---|
--month YYYY-MM |
this month | The month to report |
--tenant TEXT |
none | Only this tenant (needs the tenant_reports licence feature; exits 3 without it) |
usage report
Sends the signed monthly usage report (counts only, no media) to the issuing service. The issuer keeps the first
report of each month. An empty usage-reported-MONTH file in the evidence directory records that it was sent.
| Option | Default | Meaning |
|---|---|---|
--month YYYY-MM |
the previous month | A completed month |
laidline usage --month 2026-10
{
"v": 1,
"type": "laidline.usage-statement",
"month": "2026-10",
"closed": false,
"licence_state": "free_within_cap",
...
}
Exit codes
| Code | Meaning |
|---|---|
| 0 | The command did what you asked |
| 1 | The command failed, or (for evidence verify, evidence check-slots and verify-result) found a problem |
| 2 | An unreadable input: a bundle, a result file or a store that cannot be read; or an option the command refuses, such as a plain http --admin-url; or bench without the laidline-bench package |
| 3 | The licence lacks a feature the command needs: --tenant on evidence export or usage without tenant_reports |
Troubleshooting
| Message | Cause | Fix |
|---|---|---|
error: laidline.yaml already exists; not overwriting |
init never replaces a file |
Pass --path for a new name, or delete the old file |
error: add signing.keys_file: ./keys.yaml to ...; rotate creates it and seeds it with the current key as id 'default' |
keys rotate needs the key file named in the configuration |
Add the line it shows to laidline.yaml, then run the command again |
error: --admin-url http://... is plain http to another host: the admin token would cross the network unencrypted; use https, or http only to localhost, 127.0.0.1 or ::1 |
The admin token travels in the request | Use an https URL |
error: network: [Errno 111] Connection refused |
issuer refresh or register cannot reach the service |
Check the network and issuer.registration_url, issuer.directory.refresh_url |
error: unknown_key: the signing key is not bound to a registered customer |
usage report runs for a deployment that has not registered |
Run laidline register first |
laidline bench needs the laidline-bench package: pip install laidline-bench |
The benchmark harness is a separate package; the command exits 2 | pip install laidline-bench |
the timestamp server did not answer: ... |
mark cannot reach signing.tsa.url |
Open egress to the timestamp server, or set signing.tsa.required: false and accept grade B at best |
Reference
- HTTP API reference: the routes
laidline serveexposes. - Configuration: every key the commands read.
- Grading: what
laidline detectreports and how it grades. - Evidence: what
laidline evidence exportbundles and howverifychecks it. - Keys: payload keys and the shared pool key.
- Licensing: plans, credits and what each licence state allows.