CLI
The AGLedger CLI is a thin cover over the API. Every route the API exposes is reachable through one pass-through command, agledger api <METHOD> <path>, so the CLI never drifts behind the API and the API reference is also the CLI reference. A small set of CLI-local commands handle the things a pass-through cannot: storing credentials, cold-start discovery, and verifying an audit export offline.
Use this guide when you want to notarize from a shell, script a chain in CI, or hand an agent a terminal instead of an SDK. For request and response shapes, follow the API reference — this page covers which command maps to which job and how the offline path works.
The CLI is published as @agledger/cli v0.8.7 and requires Node 24 or later.
Install
npm install -g @agledger/cli
agledger --version
Air-gapped install. The CLI is a single npm package with two runtime dependencies (@oclif/core, cborg) and no network calls of its own beyond the API requests you make. On a connected machine, pack it and carry the tarball across:
npm pack @agledger/cli
# produces agledger-cli-0.8.7.tgz — copy it to the target host, then:
npm install -g ./agledger-cli-0.8.7.tgz
The agledger verify command runs entirely offline once installed and never contacts a registry, our website, or any AGLedger Server.
Point the CLI at your Server
Every command resolves its Server URL and key from, in order: explicit --api-url / --api-key flags, the AGLEDGER_API_URL / AGLEDGER_API_KEY environment variables, or a stored login profile. For a single shell session, environment variables are the simplest:
export AGLEDGER_API_URL=https://agledger.internal.example
export AGLEDGER_API_KEY=agl_agt_...
There is no default Server — point the CLI at your own instance. The CLI talks only to the URL you give it.
Authenticate
agledger login verifies a key against your Server (it calls GET /v1/auth/me) and, on success, stores it in ~/.agledger/config.json with 0600 permissions. Use named profiles to hold keys for more than one Server or environment on the same machine:
agledger login --api-key agl_agt_... --api-url https://agledger.internal.example --profile prod
Switch and inspect profiles with config:
agledger config list # all stored profiles, marking the active one
agledger config use prod # set prod as the active profile
agledger config get # show the active profile (URL only, never the key)
agledger config path # print the config file path
Check login state without failing — auth returns authenticated: false and exit code 0 when no key is configured, which is convenient for scripts that gate on it:
agledger auth
Remove a stored credential with agledger logout --profile prod, or agledger logout --all to clear every profile.
Keys are minted and rotated on the Server, not by the CLI. For how to obtain an agl_ key or an OIDC-bound certificate, see Authentication.
Confirm connectivity
agledger discover is the cold-start call. It checks Server health and your resolved identity, and returns the quickstart workflow. Partial results come back even if one call fails, so you can tell what is reachable:
agledger discover
Notarize a record
Creating a record is POST /v1/records through the pass-through command. For a notarize-only contract type the record terminalizes in this one signed call — this is the on-ramp.
agledger api POST /v1/records --data '{
"type": "invoice-processed-v1",
"criteria": { "invoiceId": "INV-4815", "amount": 2400 }
}'
You can build the body from typed -F fields instead of a JSON string. Dots nest, [] appends to an array, and values are typed (true / false / null, numbers, or bracketed JSON):
agledger api POST /v1/records \
-F type=invoice-processed-v1 \
-F criteria.invoiceId=INV-4815 \
-F criteria.amount=2400
For larger payloads, read the body from a file or stdin:
agledger api POST /v1/records --input record.json
cat record.json | agledger api POST /v1/records --input -
Body sources compose in this precedence (low to high): --data, then --input, then -F, then --query. Later sources override overlapping keys, so you can keep a base file and override one field with -F.
To see exactly what would be sent without calling the Server, add --dry-run:
agledger api POST /v1/records --input record.json --dry-run
Submit a completion (gated contract types)
A contract type that declares a completion schema runs the gated lifecycle: create, accept, completion, verdict. The performer submits evidence as a Completion against the record:
agledger api POST /v1/records/<record-id>/completions \
--data '{"evidence":{"itemsDelivered":"copper wire","quantityDelivered":500}}'
The principal then renders the verdict with POST /v1/records/<record-id>/verdict (body {"completionId":"<id>","verdict":"accept"}). The CLI carries these calls because it is a pass-through; the lifecycle, fields, and states are owned by the API reference.
List and stream records
For GET and DELETE, parameters go to the query string rather than the body:
agledger api GET /v1/records -F status=ACTIVE -F limit=50
To walk every page of a paginated route, add --paginate. The CLI follows the cursor and streams each item as newline-delimited JSON (NDJSON), one record per line, which pipes cleanly into jq or a file:
agledger api GET /v1/records --paginate > records.ndjson
Export a chain
A record's full audit chain is exported through the same pass-through command. Write it to a file so you can verify it later, on this host or an air-gapped one:
agledger api GET /v1/records/<record-id>/audit-export > audit-export.json
The export is format 2.0: each entry is a COSE_Sign1 envelope (RFC 9052) over an in-toto v1 Statement, hash-chained and Ed25519-signed. These are the Signed Statements that make the chain verifiable by anyone holding the public keys, with no access to the Server.
Verify an export offline
agledger verify checks an export with no network access and no API key. It recomputes the hash chain, decodes each COSE_Sign1 envelope, and verifies every Ed25519 signature against the public keys. This is the default verification path — it runs the same on an air-gapped host as on a connected one.
agledger verify audit-export.json
The export embeds the Server's signing public keys, so a self-contained export verifies on its own. To verify against keys you hold out-of-band instead of trusting the embedded set, supply them as a JSON map of signingKeyId to base64 SPKI-DER public key:
agledger verify audit-export.json --keys vault-keys.json
To reject any export signed by an unexpected or retired key, pin the expected key id — every entry must reference it or verification fails:
agledger verify audit-export.json --require-key-id <key-id>
Read the export from stdin with -, and emit a machine-readable result with --json:
cat audit-export.json | agledger verify - --json
A passing run reports the record id and that every entry verified; verify exits non-zero on any failure, so it gates a pipeline cleanly. When the chain is broken, the result names the first failing position and the failure class — for example a position gap, a payload_hash_mismatch, a chain_break, an unknown_key, or a signature_invalid — so you can tell tampering from a missing key.
Output, exit codes, and errors
Every command supports --json (the default when stdout is piped, so output is parseable in scripts automatically) and --quiet (suppress output, exit code only). Errors are written to stderr as a structured object — { "error": true, "code", "message", "suggestion", ... } — and API errors pass through verbatim, including the API's own suggestion and nextSteps.
Exit codes are semantic and stable across releases, which lets a script branch on the failure without parsing text:
| Exit code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Usage error (bad path, method, JSON, or field) |
| 3 | Auth error (401, or no key configured) |
| 4 | Forbidden (403, missing scope or role) |
| 5 | Not found (404) |
| 6 | Conflict (409) |
| 7 | Rate limited (429) |
| 8 | Server error (5xx) |
| 9 | Network error |
| 10 | Timeout |
Discover the rest
Because the CLI is a thin cover, the API reference is the command reference. To explore the surface from the terminal:
agledger list-commands # the nine CLI-local commands
agledger help-json api # arguments and flags for one command
agledger api GET /openapi.json # the full route catalog from your Server
Everything beyond the CLI-local commands — records, completions, schemas, webhooks, federation, admin — is reached with agledger api <METHOD> <path> using the exact path and body shape in the API reference.
Command surface, flags, and the offline-verify behavior on this page are drawn from @agledger/cli v0.8.7. The pass-through routes (/v1/records, /v1/records/{id}/completions, /v1/records/{id}/audit-export) and their request and response shapes are owned by the API reference; confirm field-level detail there against your own Server.