The generated CLI
From the same Glotto IR as your SDKs, docs site, and MCP server, Glotto
generates a command-line client for your API: a zero-dependency, executable Node.js script
(Node ≥ 20, node: builtins and global fetch only), plus a package.json with a bin entry
and shell-completion scripts. What you ship isn’t a one-time scaffold — every regeneration
re-derives the command tree, flags, and auth wiring from your spec, and the
drift gate proves the committed artifact never lags it.
Enable it in glotto.yml:
targets:
cli:
binary_name: acme # optional; defaults from your API name
glotto generate then writes <out>/cli/ — cli.js, package.json, README.md, and
completions/ — installable with npm install -g . or runnable directly with
node cli.js <command>.
One command per operation
Every operation becomes a command named by its resource path plus method — subresources nest
(acme events batches list), and client-level methods surface at the root. Parameters map to
flags by wire name: path parameters interpolate into the URL, query parameters land on the query
string (array parameters repeat, honoring query_settings.array_format), header parameters
become request headers, and cookie parameters fold into a Cookie header. --help (globally or
per command) prints the derived command list and flags.
Auth and environments
Auth resolves like the SDKs, from the same spec: bearer/OAuth2 tokens, API keys (header or
query, honoring the declared name), and HTTP basic — including per-endpoint security overrides
on multi-scheme APIs. Credentials come from per-scheme environment variables (or --api-key).
For OAuth2 schemes that declare a clientCredentials flow, the CLI performs the token handshake
itself: set <BINARY>_CLIENT_ID and <BINARY>_CLIENT_SECRET (or pass
--client-id/--client-secret) and it exchanges them at your token endpoint before the
request. Environments come from your spec too — select one with --environment <name> or
override with --base-url <url>.
Output, streaming, and exit codes
Successful JSON responses pretty-print to stdout; streaming operations (SSE/NDJSON) pass the raw
response body through as it arrives, so output pipes cleanly into jq or a file. Usage errors
exit 2, request failures exit 1, success exits 0 — script-friendly by construction.
Uploads
Request bodies follow the operation’s declared content type. JSON bodies take --data <json> or
--data @file; raw bodies (application/octet-stream and friends) take --data @file for file
bytes or inline --data for text; multipart/form-data operations take repeated
--field <name>=<value> flags, where a value starting with @ attaches that file as a file
part.
Pagination
Commands for paginated operations accept --all, which walks every page using the same
pagination locators the SDK iterators use — cursor, cursor-id, page/offset, and Link-header
strategies — and prints the concatenated items as a single JSON array.
Retries
The CLI honors the same retry policy as your SDKs (client_settings.retry): exponential backoff
with jitter, Retry-After honored, applied to network failures and 408/409/429/5xx responses on
GET commands and operations your spec marks idempotent.
Shell completions
Bash, zsh, and fish completion scripts for the full command tree and per-command flags are
emitted beside the CLI under completions/ — the emitted README documents where each installs.
Kept true, not just generated
Like every Glotto artifact, the CLI is a deterministic projection of your spec: byte-stable output, locked by golden tests, regenerated in lockstep with your SDKs and docs, and verified by the same drift detection and compile-verification gates. Add an operation, rename a parameter, tighten auth — the CLI is provably current on the next regeneration, forever.