CLI reference
The ecmrhub command line for terminals, coding agents and CI. Sign-in, commands, JSON output, exit codes and approvals.
In build (CLI)
ecmrhub is part of phase 1 and not released yet; it is not on npm. ecmrhub --help and
ecmrhub <command> --help show the exact flags of your version.
ecmrhub works in one company's account. It is built from the same operation catalog as the MCP
server, so anything a chat assistant can do over MCP, a terminal agent can do here.
Sign-in and profiles
| Command | What it does |
|---|---|
ecmrhub login | Browser sign-in (OAuth 2.1 with PKCE, callback on http://127.0.0.1:<port>/callback). The client registers itself once per profile. Options: --no-browser (print the address), --timeout S, --new-client. |
ecmrhub login --api-key | Fallback: a company API key from stdin or ECMR_HUB_API_KEY. |
ecmrhub whoami | Company (tenantId), permissions and how the CLI is connected (auth: oauth, apikey, env-key, env-token). |
ecmrhub logout | Forget the tokens or key of the profile. |
- Tokens and the refresh token live in
~/.config/ecmr-hub/config.json, readable only by you (0600).--profile <name>keeps several companies apart. - Environment:
ECMR_HUB_API_KEYorECMR_HUB_ACCESS_TOKEN;ECMR_HUB_URL,ECMR_HUB_ANON_KEY,ECMR_HUB_PROFILE,ECMR_HUB_CONFIG,ECMR_HUB_APP_URL. A key in the environment wins over a browser sign-in. Never pass a key as an argument.
Output
--json, or any pipe, prints JSON on stdout.- Errors go to stderr as
{"error":{"status","code","message","retryable","approval"?}}. retryable: true(429, 5xx, transport errors) means: repeat the same command with the same ids and keys. Writes are idempotent by draft revision and idempotency key.
Exit codes
| Code | Meaning | What the agent does |
|---|---|---|
| 0 | Success | Continue |
| 1 | Error | Read error.code; retry only when retryable is true |
| 2 | Wrong usage | Check --help |
| 3 | Not signed in, session expired, key or connection revoked | Ask the user to run ecmrhub login; do not retry |
| 4 | Forbidden: a missing permission, or a person must do it | Tell the user which permission or step |
| 5 | Waiting for a person's approval | Show error.approval.url, wait, run error.approval.retry |
Commands
| Command | Operation | Notes |
|---|---|---|
fields | (local) | CMR fields: key, label, box, required, eFTI, codes |
drafts check --data FILE | (local) | Validation and eFTI gaps, no network |
drafts list | draft.list | Drafts and documents by stage |
drafts create --data FILE | draft.save | New draft; returns id and revision |
drafts update <id> --data FILE [--revision N] | draft.save | Without --revision only the given fields change; an empty string clears a field |
drafts delete <id> [--revision N] | draft.delete | Needs approval |
drafts issue <id> [--revision N] | draft.publish | Needs approval; issuing twice returns the same document |
documents list [--limit N] [--before ISO] | document.list | Issued documents |
documents get <id> | document.get | One document |
documents evidence <id> | document.evidence | Versions, events, consents |
documents pdf <id> --out FILE | document.pdf | Stored PDF, checked against its SHA-256 |
sign request <documentId> --role sender|carrier|consignee [--idempotency-key K] | signing.createLink | Needs approval; link valid 7 days |
sign revoke <documentId> --role sender|carrier|consignee | signing.revokeLink | Needs approval |
efti check <documentId> or efti check --data FILE | (local) | eFTI gaps; nothing is sent to any gateway |
approvals list [--status S] | Approvals this connection requested | |
approvals status <id> | One approval | |
approvals wait <id> [--timeout S] [--interval S] | Exit 0 approved, 4 rejected, 1 expired or used, 5 still pending | |
connections list | A person's session only; an agent gets exit 4 | |
connections revoke <id> | A person's session only; an agent gets exit 4 | |
operations list | The whole catalog; cli: "unavailable" marks what only a person or an app screen can run | |
operations describe <name> | Input schema of one operation | |
operation <name> --data FILE | any | Run any operation of the catalog by name |
skill | Print the agent skill (SKILL.md) |
Global options: --approval ID, --json, --profile NAME, --url URL, --help, --version.
There is no flag that approves an operation. --approval <id> only repeats a call a person has
already approved. Pass --data as a file rather than stdin, so the repeated call sends the same
input.
Approvals
When a command needs approval it exits with 5 and prints:
{
"error": {
"status": 428,
"code": "APPROVAL_REQUIRED",
"retryable": false,
"approval": {
"id": "6f1c2a9e-...",
"url": "https://ecmrhub-v2.lucaspiera.com/dashboard/approvals/6f1c2a9e-...",
"expiresAt": "2026-10-20T10:00:00.000Z",
"operation": "draft.publish",
"retry": "ecmrhub drafts issue 1b2c... --revision 3 --approval 6f1c2a9e-... --json"
}
}
}Give the user error.approval.url, wait with approvals wait, then run error.approval.retry exactly as
given. More: Human approvals.
Calling any operation
Every operation the company allows has a command, even without a dedicated subcommand:
ecmrhub operations describe vehicle.add --json # input schema
ecmrhub operation vehicle.add --data vehicle.json --json{ "name": "Truck 1", "values": { "registration": "WX12345", "country": "PL" } }The full list with permissions and approval rules: Operation catalog.
The agent skill
mkdir -p ~/.claude/skills/ecmr-hub-cli
ecmrhub skill > ~/.claude/skills/ecmr-hub-cli/SKILL.mdThe skill teaches a coding agent the same rules as this page: sign-in, JSON output, exit codes, approvals and the order of steps to issue a consignment note.