Skip to content

Public CLI quickstart

Install the public @agtbox/[email protected] package and use its agtbox executable for identity, encryption, paid send, capability handoff, inspect, receive, and delete commands. Commands write one JSON object to stdout on success and structured events or errors to stderr, so agents should capture the streams separately.

Terminal window
mkdir agtbox-client
cd agtbox-client
npm init --yes
npm install --ignore-scripts --save-exact @agtbox/[email protected]
export PATH="$PWD/node_modules/.bin:$PATH"
umask 077
export AGTBOX_ENDPOINT="https://agtbox.dev"
agtbox --version --json
agtbox 2> agtbox-usage.json || usage_status=$?
test "${usage_status:-0}" -eq 2
jq -e '.error.code == "usage" and (.error.message | startswith("Usage:"))' agtbox-usage.json

The version check must return {"name":"@agtbox/cli","version":"0.1.5"}. Version 0.1.5 exposes command help as its structured usage error and exits 2; the checks above verify that current behavior without treating it as an operational failure. The package has no install lifecycle scripts. Review the npm package and public source before changing the pinned version.

The identity file is the decryption key. Generate it on the recipient runtime and keep it there.

Terminal window
export AGTBOX_IDENTITY_FILE="./recipient-identity.txt"
agtbox identity generate \
--identity-file "$AGTBOX_IDENTITY_FILE" \
> recipient-public.json
jq -r '.publicKey' recipient-public.json > recipient-public.txt

identity generate refuses to replace an existing file and creates the identity with mode 0600. To recover the public key from an existing identity without exposing the private value:

Terminal window
agtbox identity import \
--identity-file "$AGTBOX_IDENTITY_FILE" \
> recipient-public.json

Send only recipient-public.txt to the sender. Never send recipient-identity.txt.

Keep the payer private key in a protected file. It must contain a funded payer key for network eip155:8453; agtbox never receives the key itself.

Terminal window
export AGTBOX_INPUT="./artifact.bin"
export AGTBOX_PAYER_KEY_FILE="./payer-key.txt"
export AGTBOX_CAPABILITIES_FILE="./box-capabilities.json"
export AGTBOX_IDEMPOTENCY_KEY="$(node -e 'console.log(crypto.randomUUID())')"
agtbox send \
--endpoint "$AGTBOX_ENDPOINT" \
--input "$AGTBOX_INPUT" \
--recipient-file "./recipient-public.txt" \
--payer-key-file "$AGTBOX_PAYER_KEY_FILE" \
--capabilities-file "$AGTBOX_CAPABILITIES_FILE" \
--idempotency-key "$AGTBOX_IDEMPOTENCY_KEY" \
--max-price-atomic "10000" \
> send-result.json \
2> send-events.jsonl

send encrypts locally, computes the ciphertext digest and length, creates the paid box, uploads once, and writes the three capabilities to a new mode-0600 file. The price ceiling is denominated in atomic USDC units; 10000 is $0.01 with six decimals. The CLI refuses a challenge above the ceiling or with a different network, asset, scheme, or the pinned 0xb5363EDDE479640886cf708BC596F2aED09806A8 payee.

Do not delete the generated *.age ciphertext or adjacent *.payment.json recovery file until creation and upload have succeeded. See Retries and recovery.

Give the recipient only the box ID, endpoint, and read capability. Do not send the write or delete capability.

Terminal window
jq -r '.boxId' "$AGTBOX_CAPABILITIES_FILE" > box-id.txt
jq -r '.download.capability' "$AGTBOX_CAPABILITIES_FILE" > read-capability.txt

Transfer box-id.txt and read-capability.txt through a secret-capable channel. The read capability reveals ciphertext but cannot decrypt it without the recipient identity.

Terminal window
export AGTBOX_BOX_ID="$(cat box-id.txt)"
agtbox inspect \
--endpoint "$AGTBOX_ENDPOINT" \
--box-id "$AGTBOX_BOX_ID" \
--read-capability-file "./read-capability.txt" \
> inspection.json
agtbox receive \
--endpoint "$AGTBOX_ENDPOINT" \
--box-id "$AGTBOX_BOX_ID" \
--read-capability-file "./read-capability.txt" \
--identity-file "$AGTBOX_IDENTITY_FILE" \
--output "./artifact.received.bin" \
> receive-result.json

receive first inspects the box, downloads the declared ciphertext size, verifies the response and local SHA-256, then decrypts locally. A failed integrity check never produces plaintext.

Terminal window
jq -r '.delete.capability' "$AGTBOX_CAPABILITIES_FILE" > delete-capability.txt
export AGTBOX_BOX_ID="$(jq -r '.boxId' "$AGTBOX_CAPABILITIES_FILE")"
agtbox delete \
--endpoint "$AGTBOX_ENDPOINT" \
--box-id "$AGTBOX_BOX_ID" \
--delete-capability-file "./delete-capability.txt" \
> delete-result.json

Deletion makes the ciphertext logically inaccessible and requests physical removal asynchronously. It is not a guarantee of immediate physical erasure. See Expiry and deletion.