CLI reference
axiom is the agent CLI from packages/sdk (src/cli.ts). It submits, tracks and resumes actions as an agent, downloads and verifies receipts, and runs the policy simulator.
It never runs in the background and makes no promise that a webhook can restart it. When an action waits on a person, submit returns the pending ID, saves the record and prints how to check it; the next invocation re-authenticates as the same agent (including after key rotation) and carries on.
Developer preview
Not yet published to a registry. From the repository root run it as node packages/sdk/bin/axiom.mjs … (the launcher runs the TypeScript sources through tsx), or alias it: alias axiom="node $PWD/packages/sdk/bin/axiom.mjs". Requires Node 22+.
Configuration
Files live in $AXIOM_CONFIG_DIR, else $XDG_CONFIG_HOME/axiom, else ~/.config/axiom:
| File | Contents | Mode |
|---|---|---|
config.json | Settings below | 0600 |
keys/{kid}.jwk | Private keys from axiom keygen | 0600, directory 0700 |
actions.json | Pending action records | 0600 |
Files are written to a temporary name and renamed, so a crash never leaves a half-written file.
| Key | Used by | Meaning |
|---|---|---|
api_url | all agent commands | API origin. Default https://api.sectigoaxiom.com. |
agent_id | all agent commands | Stable agent ID (agt_…). |
key_file | all agent commands | Path to the agent's private JWK. |
tenant | submit, simulate | Default tenant ID. |
service | submit, simulate | Default protected service ID. |
project_id | simulate | Project for the simulator. |
api_key | simulate | Project API key (axk_…); AXIOM_API_KEY also works. |
Global option: --api URL overrides api_url for one invocation.
Commands
axiom keygen
Generate an agent signing key. The private key stays on this machine.
| Option | Default | Meaning |
|---|---|---|
--alg ALG | ES256 | ES256 or EdDSA. |
--agent ID | Also set agent_id in config. |
Saves keys/{kid}.jwk, sets key_file, and prints the public JWK to enroll.
Bind the key to the agent next with axiom agent bind (or with axiom agent sign-challenge and the console).
axiom agent bind AGENT_ID
Enroll this CLI's key for an agent with proof of possession: fetch a single-use challenge (POST /v1/agents/{id}/credentials/challenge), sign it with the key, and submit the public key and proof (POST /v1/agents/{id}/credentials, kind: "jwk"). The private key never leaves the machine. Earlier active jwk and x509 credentials of the agent enter the rotation overlap window.
Binding is an administrator action (agent.write on the tenant), so the command uses a signed-in console session: pass the axiom_session cookie value from your browser. Prefer the AXIOM_SESSION_COOKIE environment variable to the flag, which can end up in shell history. This is a developer convenience; production enrollment belongs in the console or an automated registration flow.
| Option | Meaning |
|---|---|
--key FILE | Private JWK to enroll. Default: config key_file. |
--cookie VALUE | axiom_session cookie (or AXIOM_SESSION_COOKIE). |
--issue-certificate | Also issue an X.509 client certificate for the key from the CA. |
--validity SECONDS | Requested credential lifetime (the server and CA may shorten it). |
--json | Print the credential as JSON. |
export AXIOM_SESSION_COOKIE='…' # axiom_session cookie of a tenant admin
axiom keygen --agent agt_01kd0m6n3b4v5c6x7z8a9s0d1f
axiom agent bind agt_01kd0m6n3b4v5c6x7z8a9s0d1f
# Bound jwk credential crd_… (thumbprint …) to agt_…, valid until 2027-02-13T…Binding a key that is already bound returns 409 conflict ("this key is already bound to this agent; generate a new key to rotate", or "…to another agent"). To rotate, generate a new key and bind it.
axiom agent sign-challenge CHALLENGE
Sign a challenge copied from the console's "bind a key you hold" form and print the proof (a compact JWS) to paste back. CHALLENGE is the payload shown in the console, or the whole challenge response, as JSON or a file holding it.
| Option | Default | Meaning |
|---|---|---|
--key FILE | config key_file | Private JWK whose public key is being enrolled. |
--typ TYP | axiom-pop+jws | JWS header typ, if the console asks for another. |
--agent ID | Refuse a challenge issued for any other agent. |
axiom agent sign-challenge '{"agent_id":"agt_…","nonce":"…","aud":"https://api.sectigoaxiom.com"}' --agent agt_…axiom config show and axiom config set KEY VALUE
show prints the configuration (with api_key masked) and the directory. set accepts only the keys in the table above.
axiom token
Obtain a DPoP-bound access token (private_key_jwt) and print it with its scope and expiry. The token is bound to your key; every request also needs a DPoP proof, so this is for inspection.
axiom submit
Submit an action.
| Option | Meaning |
|---|---|
--operation NAME | Required. E.g. billing.refund.create. |
--resource TYPE:ID | Required. E.g. invoice:417. |
--service ID | Default: config service. |
--tenant ID | Default: config tenant. |
--param KEY=VALUE | Material parameter, repeatable. Values stay strings, so decimals stay exact. |
--params-json JSON | Parameters as a JSON object; --param values are merged over it. |
--key OPERATION_KEY | Operation key. Default: a new random key, printed so you can retry with it. |
--intent TEXT | Free-text intent shown to approvers. |
--wait SECONDS | Bounded warm wait; if approved in time, resume and track. Without it, no wait. |
--no-execute | Record only; an approved action stays approved until axiom resume. |
--json | Print JSON ({ kind, status }). |
axiom submit --operation billing.refund.create --resource invoice:417 \
--param amount=25000 --param currency=USD --param beneficiary=acct_acme_ops \
--intent "Refund the duplicate charge"Prints the operation key (unless --key or --json), the status line and a description, then what to do next: for a pending action axiom status ID and, once approved, axiom resume ID; for a dispatched one axiom status ID; for a completed one axiom receipt ID --out receipt-ID.json.
axiom status ACTION_ID
Authenticated status read. Prints the state, reason and description; for an approved action, the resume command, and a hint if there is no saved request for the ID. --json prints the status.
axiom wait ACTION_ID
Bounded warm wait for a decision, capped by the server's max_warm_wait_seconds (25 s). --budget SECONDS, --json. If still waiting, prints when to check again.
axiom resume ACTION_ID
Resume an approved action as the original agent, then track it.
| Option | Meaning |
|---|---|
--resource TYPE:ID | Default: the saved request. |
--key OPERATION_KEY | Default: the saved request. |
--param KEY=VALUE | Approved parameter, repeatable. Default: the saved request. |
--params-json JSON | Approved parameters as a JSON object. |
--wait SECONDS | Bounded wait for the outcome. |
--json | Print JSON. |
Without a saved record (for example on another machine), pass --key, --resource and the params. The parameters must be exactly the approved ones; a difference is 409 conflict.
axiom pending
List actions saved by earlier invocations: ID, last state, operation, resource and deadline.
axiom receipt ACTION_ID
Download the signed receipt bundle. --out FILE writes it to a file (and prints the verify command); --reveal FIELDS takes a comma-separated list for a redacted export (e.g. operation,params.amount).
axiom verify BUNDLE_FILE
Verify a receipt bundle, offline by default (using the keys embedded in it).
| Option | Meaning |
|---|---|
--issuer-jwks URL | Fetch Axiom's keys instead of trusting the bundle snapshot. |
--provider-jwks URL | Fetch the provider's outcome keys. |
--trusted-issuer ISS | Require this issuer; repeatable. |
--json | Print { valid, key_source, report }. |
Exits with status 1 when the receipt is not valid.
Receipt rcp_01kd0mf…: VALID
Action act_01kd0m7s2v8x9yz3abcdefghjk (billing.refund.create on invoice 417)
Issuer https://api.sectigoaxiom.com, issued 2026-11-14T18:20:06.000Z
Agent agt_01kd0m6n3b4v5c6x7z8a9s0d1f (credential jwk …)
Tenant ten_01kd0m4z9x8c7v6b5n4m3l2k1j
Outcome succeeded · re_01kd0mf…
Phases authorized yes · approved yes · dispatched yes · destination confirmed yes
Keys fetched
Signer observation key …: valid, key active
Signer provider outcome key …: valid
Checks
PASS Axiom observation signature - 1 signature(s) verified
PASS Issuer - https://api.sectigoaxiom.com
PASS Disclosed fields match commitments - all fields disclosed
PASS Request digest - sha-256:…
PASS Approval by Finance manager <finance@acme.example> (axiom) - approved, verified via axiom_session
PASS Provider outcome attestation - succeeded · re_01kd0mf…axiom simulate
Preview the policy decision for a hypothetical request with a project API key. Creates nothing.
| Option | Meaning |
|---|---|
--operation NAME | Required. |
--resource TYPE:ID | Required. |
--service ID | Default: config service. |
--tenant ID | Default: config tenant. |
--project ID | Default: config project_id. |
--api-key KEY | Default: config api_key, or AXIOM_API_KEY. |
--agent ID | Agent to simulate as. |
--grant ID | Grant whose rules to apply. |
--param KEY=VALUE, --params-json JSON | Parameters. |
Prints the simulator's JSON, including decision.effect, decision.reason_code and the rule trace. Pass --grant to apply a grant's rules (the sample's USD 500 threshold is a grant rule). Without it, grant-level rules are skipped and the response says so in note.
Exit codes and errors
0 on success, 1 on any error. Errors print the code and reason, for example error: idempotency_conflict (material_change): … followed by changed fields: params.amount, or field issues for validation_failed. A transport failure says nothing is known about whether the server acted and suggests re-running with the same --key or checking status.