Skip to content Documentation index for agents (llms.txt)
Glotto Beta
Get started

CLI reference

The Glotto CLI is invoked as glotto <command>. Run glotto with no arguments to print the command list. Every command exits 0 on success, 1 on a run failure, and 2 on a usage or load error (an unknown flag, a missing glotto.yml).

This page documents the CLI you can install, and only that. Every command below is in the published @glotto/cli; there are no others, and nothing here requires a plan, a flag, or an invitation to unlock. Glotto also delivers most of these capabilities without your running anything — keeping your committed SDKs verified, detecting drift, publishing to registries — on your pull request and your dashboard; those routes are described by what they produce and where you collect it, under What Glotto also runs for you below.

Most commands discover the config automatically: with no --config, Glotto looks for .glotto/workspace.json, then glotto.yml, then glotto.yaml — first in the current directory, then in each parent directory up to the filesystem root. So commands work from anywhere inside your project, not only from the directory holding the config. See Getting started for the end-to-end workflow and the glotto.yml reference for the configuration these commands consume.

The workspace file

A .glotto/workspace.json declares which project a directory belongs to. You only need one when a single repository holds more than one glotto.yml, or when you want an SDK written somewhere other than sdks/<language>/. A repository with one config at its root needs no workspace file — the upward walk already finds that config from any subdirectory, which is why glotto init does not write one.

{
  "config": "api/glotto.yml",
  "targets": {
    "typescript": "clients/typescript",
    "python": "clients/python"
  }
}
  • config (required) — path to the glotto.yml this workspace binds to.
  • targets (optional) — where each language’s SDK is written. A language you leave out is written to sdks/<language>/ as usual. Drift detection reads the same map, so it compares each language against the directory declared here — there is no second root to keep in step with the layout.

Both are relative to the workspace root — the directory containing .glotto/ — and must stay inside it. Absolute paths and .. escapes are rejected. glotto workspace writes, checks, and explains the file: glotto workspace show prints the binding for the directory you are standing in, glotto workspace validate checks the file on its own, and glotto workspace init writes one with the config path filled in for you.

Two keys you might expect are deliberately not accepted, because glotto.yml already owns those values and a second copy would drift out of step: project (that is hosted.project) and openapi_spec (that is openapi.source, resolved relative to the config). Setting either one reports GLOTTO_WORKSPACE_KEY_OWNED_ELSEWHERE naming where the value belongs.

Nearest declaration wins. In a monorepo, give each project its own workspace file (or just its own glotto.yml): a command run inside services/billing/ binds to the nearest declaration above it, not to the repository root. Where output lands follows the same rule — with a workspace file in effect, a relative output path is resolved against the workspace root rather than wherever you happened to run the command, so glotto generate writes to the same place from every directory. An explicit --out is always resolved against the current directory.

How you get each command

The published @glotto/cli on npm is a thin client: code generation runs on Glotto’s infrastructure, so the codegen engines never ship in the installed binary. Sixteen commands are in it — login, logout, init, migrate, schema, workspace, generate, mcp, breaking-changes, verify, verify-compile, verify-contract, verify-upload, verify-attestation, publish, and code-owners.

That list is complete. glotto <anything-else> exits 2 with unknown command, and every section below carries the same label because every section below is a command you can run:

  • Available in the published CLInpm i -g @glotto/cli gives you this command.

Thin client does not mean everything is remote. Which side a command runs on follows from what it needs, not from a policy. verify-compile and verify-contract invoke your committed SDKs’ own toolchains and test suites, and publish pushes with your own registry credentials — all three run entirely on your machine, and nothing about them reaches Glotto. generate, verify and breaking-changes need the code-generation and spec-normalisation engines, which stay server-side, so those three need glotto login or a GLOTTO_API_TOKEN. Each section below says which it is.

What you will not find here is a reference section for a command you cannot obtain. Documenting one would mean printing a flag table and a shell sample under a note saying you cannot run it, which is not a caveat so much as an instruction that fails — so the one capability with no command left (glotto migrate fern, which needs the spec pipeline) is described by its outcome instead. See What Glotto also runs for you.

glotto init

Available in the published CLInpm i -g @glotto/cli

Scaffold a new glotto.yml and spec/openapi.yaml in the current directory, then print the next steps. Without --force it refuses to overwrite an existing glotto.yml or spec/openapi.yaml.

  • --force — overwrite existing files without prompting.
glotto init           # scaffold glotto.yml + spec/openapi.yaml
glotto init --force   # overwrite an existing scaffold

glotto migrate

Available in the published CLInpm i -g @glotto/cli

Convert a competitor’s config into a glotto.yml, and print a migration report saying what happened to every key — what was carried, what was normalized, what was dropped and why, and which values are placeholders you have to fill in. Nothing already on disk is overwritten without --force, and your OpenAPI document is never modified in place.

  • --in <path> — input file (default: stainless.yml).
  • --out <path> — output file (default: glotto.yml).
  • --force — overwrite an existing --out.
  • --report <path> — also write the migration report to a file.
  • --openapi <path> — read x-stainless-naming / x-stainless-param into naming, and resolve every transforms target against your real document so the translation is exact rather than inferred. See Migrate from Stainless.
  • --openapi-out <path> — also write that document back out with the Terraform attribute-shaping extensions translated to their x-glotto-* equivalents.
glotto migrate stainless                                  # stainless.yml -> glotto.yml
glotto migrate stainless --openapi openapi.yaml           # exact transform + naming translation
glotto migrate stainless --report migration-report.txt    # keep the report alongside the config

Fern. Glotto also converts a fern/generators.yml (and fern/docs.yml), but that conversion reads your API surface through the spec pipeline, which stays server-side — so it is not something the published CLI runs. glotto migrate fern exits 2 and says so. What it converts is documented in Migrate from Fern; to have us run it, email hello@glotto.dev.

glotto workspace

Available in the published CLInpm i -g @glotto/cli

Inspect and author the workspace file. Every subcommand answers a question about which project the current directory belongs to, so none of them takes --config — that flag is what bypasses discovery, and these commands exist to report what discovery does.

glotto workspace show

Print the resolved binding for the current directory: the workspace root, the config it binds to, which file declared it and how far up the tree that was, the root relative output is anchored to, and where each enabled target’s SDK is written. Exits 2 when no config is found anywhere above the current directory, or when the config it found cannot be parsed (the binding is still printed).

  • --json — emit the same facts as a JSON object instead of prose.
glotto workspace show          # "which project am I in, and where does my output go?"
glotto workspace show --json   # the same, for a script
workspace root: /repo
config:         /repo/api/glotto.yml
declared by:    .glotto/workspace.json (in this directory)
output root:    /repo

targets:
  python      /repo/clients/python  (declared)
  typescript  /repo/sdks/typescript

The directories it reports are the directories glotto generate writes to — both commands resolve them through the same code, so the report cannot drift from the writer. (declared) marks a directory that came from the workspace file’s targets map rather than the sdks/<language>/ default.

glotto workspace validate

Validate the nearest .glotto/workspace.json at or above the current directory, without generating anything and without requiring glotto.yml to be valid. Prints nothing and exits 0 when the file is clean, so it drops into a pre-commit hook or CI step. Exits 1 with the diagnostic code when the file is wrong, and 2 when there is no workspace file to check (an ambient glotto.yml is not a declaration and is never reported as one).

  • --json — emit the outcome as a JSON object. The exit code is unchanged.
glotto workspace validate          # silent + exit 0 when the file is clean
glotto workspace validate --json   # {"ok": false, "code": "GLOTTO_WORKSPACE_CONFIG_MISSING", …}

glotto workspace init

Write a .glotto/workspace.json in the current directory, which becomes the workspace root. The config path is derived rather than typed — from --config when you pass one, otherwise from the config found by walking up — and written relative to the root with / separators, so the committed file is portable. A config that does not exist, or that sits outside the workspace root, is refused rather than written for a later command to reject.

targets is never written: it declares an output layout only you can choose. Add it by hand when you want one, and glotto workspace validate will check it.

  • --config <path> — bind to this config (relative to the current directory) instead of the discovered one.
  • --force — overwrite an existing .glotto/workspace.json.
glotto workspace init --config api/glotto.yml   # writes {"config": "api/glotto.yml"}
glotto workspace init --force                   # overwrite an existing declaration

Note that glotto init deliberately does not write a workspace file — a fresh single-config project does not need one. Reach for glotto workspace init when a repository grows a second project, or when you want SDKs written somewhere other than sdks/<language>/.

glotto schema

Available in the published CLInpm i -g @glotto/cli

Emit the JSON Schema for glotto.yml (the same schema core-config exports as glottoConfigJsonSchema()). With no flags it prints to stdout; reference it from your config with a # yaml-language-server: $schema=… header for editor completion and validation.

  • --out <file> — write the schema to a file (relative to the current directory) instead of stdout.
glotto schema                            # print the schema to stdout
glotto schema --out glotto.schema.json   # write it, then reference it from glotto.yml:
                                         #   # yaml-language-server: $schema=./glotto.schema.json

glotto generate

Available in the published CLInpm i -g @glotto/cli

Validate the config, then generate SDKs from the spec across enabled targets. Writes all files atomically: nothing is written if the run fails. A target an engine refuses is different — it is dropped, the remaining targets are written normally, and the command exits non-zero naming the target it could not build (see Reserved model names). Each SDK’s customer-owned lib/ extension files are written only if absent, and managed files with local edits are preserved (or, with --merge, three-way-merged) unless --force is passed — see Custom code.

  • --config <path> — use this config instead of auto-discovery.
  • --out <dir> — output directory, relative to the current directory (default sdks, resolved against the workspace root when a workspace file is in effect). Overrides any targets path a workspace file declares.
  • --target <target> — restrict to a target; repeatable. Omit to generate all configured targets.
  • --version <semver> — stamp the generated SDKs with this version (X.Y.Z or X.Y.Z-pre).
  • --dry-run — print the files that would be generated without writing.
  • --force — overwrite managed files that have local edits.
  • --merge — three-way-merge managed files that have local edits with the regenerated output (conflicts are written with git conflict markers), keeping a pristine baseline under .glotto/baseline/ (gitignore it). Without the flag, edited files are preserved untouched.
  • --format — run each language’s native formatter over the generated source (gofmt, rustfmt, dart format, swift-format, mix format, rubocop, php-cs-fixer, google-java-format, ktfmt). A formatter that isn’t installed degrades with a warning — that language is emitted unformatted; point GLOTTO_<TOOL> (e.g. GLOTTO_RUSTFMT) at a binary to override resolution.
glotto generate                              # generate every configured target into ./sdks
glotto generate --target typescript          # one target only (repeat --target for more)
glotto generate --out build/sdks --version 1.4.0
glotto generate --dry-run                    # preview the file list, write nothing

glotto mcp

Available in the published CLInpm i -g @glotto/cli

Work with the MCP server artifact. Three subcommands:

  • glotto mcp generate — emit only the MCP server from glotto.yml, without the SDKs or the docs site. Runs server-side, like generate, so it needs glotto login.
    • --out <dir> — write the server here instead of the configured output directory.
    • --config <path> — use this glotto.yml instead of auto-discovery.
    • --dry-run — print the file list, write nothing.
    • --force — overwrite managed files that have local edits.
  • glotto mcp serve — run an emitted MCP server over stdio, so an MCP client can launch it directly. Local only: it spawns the artifact already on disk and generates nothing.
    • --dir <path> — the emitted server to run (default sdks/mcp).
    • Any remaining flags are forwarded to the server unchanged.
  • glotto mcp annotate — author tool descriptions into glotto.yml’s mcp.operations block. Runs server-side and needs glotto login.
    • --tool <name> — annotate one tool; repeatable.
    • --config <path>, --dry-run, --force — as above.
glotto mcp generate                    # emit just the MCP server (runs server-side)
glotto mcp serve                       # run the emitted server over stdio
glotto mcp serve --dir build/mcp       # run one from a non-default directory
glotto mcp annotate --tool listPets    # author one tool's description into glotto.yml

glotto breaking-changes

Available in the published CLInpm i -g @glotto/cli

Classify what changed between your current spec and a baseline: which changes break a caller, which do not, and what each does to the generated SDK surface. With --gate it fails the run when a breaking change lands without a major version bump, which is what the CI workflow Glotto emits for your repository does on every pull request.

The comparison builds two IRs through Glotto’s spec pipeline and diffs them, so it runs on Glotto’s infrastructure and needs glotto login or a GLOTTO_API_TOKEN. Both spec documents are read from your machine and sent with any configured companion spec documents. The published CLI accepts local file sources. URL, git, command and introspect sources are refused: fetch, check out or export those documents first, then point the config at local files.

  • --against <path> — the baseline spec document to compare against. A local file.
  • --provider <github|gitlab|bitbucket|azure> with --repo <ref> and --branch <branch> — fetch the baseline from a repository instead. --spec-path <path> overrides which file is fetched.
  • --gate — exit 1 when breaking changes were introduced without a major version bump. Also enabled by settings.detect_breaking_changes in your glotto.yml.
  • --format json — emit the classified report as JSON instead of text.
  • --emit-workflow <github|gitlab|bitbucket|azure> — print the CI workflow that runs this gate.

--against-ref <ref> is available in the first-party build only: it names a git object, which needs the spec loader that clones repositories. Use --against with a checked-out file, or --provider.

The emitted workflows require a GLOTTO_API_TOKEN: configure an Actions secret on GitHub, a masked CI/CD variable on GitLab, a secured repository variable on Bitbucket, or a secret pipeline variable on Azure. The GitHub and Azure templates map that secret into the gate’s environment. For a self-hosted control plane, follow the template’s GLOTTO_API_URL instructions; the default is https://api.glotto.dev.

glotto breaking-changes --against baseline.openapi.yaml
glotto breaking-changes --against baseline.openapi.yaml --gate

glotto verify

Available in the published CLInpm i -g @glotto/cli

Verify committed SDK output against a fresh regeneration and write the verification report: per target, whether the committed files drifted from what your spec produces, whether any checksum-stamped managed file was hand-edited, and — when you feed it a check-results document — the real compile and contract status of each target. This is the gate step of the CI workflow Glotto emits for your repository.

It regenerates, so it runs on Glotto’s infrastructure and needs glotto login or a GLOTTO_API_TOKEN. The comparison itself is local: your committed files are read and diffed on your machine, and only the spec is sent.

  • --against <dir> — the committed output tree to verify. --against-default sdks yields to a .glotto/workspace.json when one is in effect, and falls back to sdks/.
  • --provider <github|gitlab|bitbucket|azure> with --repo <ref> and --branch <branch> — verify the output committed on a branch, with no checkout. --prefix <path> names the subpath it lives under.
  • --checks <path> — fold in a check-results document produced by verify-compile / verify-contract, so the report carries real compile and contract statuses instead of “not run”.
  • --out <dir> — write verification-report.json and verification-report.md here.
glotto verify --against-default sdks --out glotto-verification
glotto verify --against-default sdks --checks glotto-verification/check-results.json --out glotto-verification

glotto verify-compile

Available in the published CLInpm i -g @glotto/cli

Compile every committed SDK in place, with that SDK’s own toolchain, and write the check-results document glotto verify folds into its report. This is the first produce step of the CI workflow Glotto emits for your repository.

It runs entirely on your machine and needs no Glotto account: it regenerates nothing and sends nothing. What it does need is your targets’ toolchains installed in the job — it invokes them.

Each target’s command comes from targets.<slug>.verify.compile in your glotto.yml, or a built-in default for the languages where compiling a committed SDK is unambiguous (TypeScript, React Native, Go, Python, Rust). A target with neither is skipped rather than guessed at, and the document records the omission.

  • --against <dir> / --against-default sdks — the committed output tree to compile.
  • --out <dir> — where to write check-results.json.
glotto verify-compile --against-default sdks --out glotto-verification

glotto verify-contract

Available in the published CLInpm i -g @glotto/cli

Run the integration test suite each committed SDK ships — the self-contained suite Glotto emits beside the client, which boots an in-process mock and round-trips the generated code against it — and merge the contract statuses into the same check-results document verify-compile wrote.

It runs entirely on your machine, like verify-compile, and needs each target’s dependencies installed as well as its toolchain: the emitted suite imports the built SDK.

  • --against <dir> / --against-default sdks — the committed output tree to test.
  • --out <dir> — the directory holding the document to merge into (and to write).
glotto verify-contract --against-default sdks --out glotto-verification

glotto verify-upload

Available in the published CLInpm i -g @glotto/cli

Publish a check-results document to the control-plane run for a commit, so the console’s surface-health panel, the run history and the verification attestation carry your real compile and contract statuses instead of “not run”. This is the dashboard step of the CI workflow Glotto emits for you; leave it out and the report still reaches your pull request as a job summary and an artifact.

It is pure HTTP: it reads the produced document and posts it. It runs no generation and needs no toolchain.

  • --checks <path> — the check-results document to publish. Required.
  • --project <id> — the control-plane project. Resolves --project, then GLOTTO_PROJECT_ID, then hosted.project in your glotto.yml.
  • --commit <sha> — the commit the run belongs to. Read from the CI environment when omitted.

GLOTTO_API_TOKEN authenticates the upload. Verified provenance is optional and turn-key: set GLOTTO_CI_OIDC_TOKEN to a pre-minted CI-run OIDC token (GitLab, Bitbucket, Azure Pipelines or self-hosted), or grant GitHub Actions id-token: write — the dashboard then marks the run verified, meaning it can prove which workflow produced the statuses, not merely that a valid token uploaded them. The token’s audience must equal your API URL, which must match the server’s CI_OIDC_AUDIENCE (default https://api.glotto.dev).

glotto verify-upload --checks glotto-verification/check-results.json

glotto verify-attestation

Available in the published CLInpm i -g @glotto/cli

Verify a downloaded verification attestation — the signed, self-contained DSSE envelope that binds one verification report to the run that produced it. This is the command a buyer’s compliance reviewer runs: it turns a JSON file into a verdict without requiring anyone to construct DSSE pre-authentication bytes by hand.

Exits 0 when the envelope is verified, 1 when it is not, and 2 on a usage or configuration error — every usage error is reported before any network call, so a mistake never costs a round trip and never looks like a failed verification.

  • --key <path> — a public key file: one SPKI PEM, or a bundle of several concatenated. Repeatable. Keys are matched to signatures by their own derived fingerprint, never by filename or the order you pass them.
  • --offline — never contact the API. With --key material covering every key the envelope names, verification is completely self-contained — which is the point of filing an attestation for years.
  • --api-url <url> — control-plane base URL (env GLOTTO_API_URL; default https://api.glotto.dev). Used only for the keys --key did not resolve.
  • --allow-revoked — report a signature made by a revoked key as a warning instead of a failure.
  • --require-countersignature — fail unless at least one verified non-issuing signature is present (see below).
  • --countersign <pkcs8.pem> — co-sign this envelope with your own Ed25519 key. Verification runs first: an envelope that failed is never counter-signed. Your private key is never printed, logged, or uploaded — only the public half and the signature.
  • --upload — send the co-signature to the run the attestation itself names (needs GLOTTO_API_TOKEN). There is deliberately no --project/--run flag: the signature can only be filed against the run it describes.
  • --json — machine-readable verdict.
# Verify against the key the API serves for this envelope
glotto verify-attestation attestation.json

# Fully offline, with a key you archived alongside the artifact
glotto verify-attestation attestation.json --key glotto-attestation.pem --offline

# Co-sign it with your own key, so the artifact no longer rests on Glotto's alone
glotto verify-attestation attestation.json --countersign my-key.pem --upload

What the verdict means. The first signature is Glotto’s; any that follow are second-party counter-signatures. A counter-signature that fails against a key you hold is tampering and fails the whole verification; one whose key you simply do not hold is reported and does not fail anything — holding fewer keys should not make an artifact look worse. If a key resolves as revoked, the command tells you both facts separately: the signature is genuine, and the key is not to be trusted. Under --offline no key carries a status at all, so the command says revocation was not checked rather than implying a clean bill of health.

glotto publish

Available in the published CLInpm i -g @glotto/cli

Publish your generated SDKs to their language package registries — npm, PyPI, crates.io, Hex, Maven Central, NuGet, pub.dev and RubyGems. This is the single step of the release CI workflow Glotto emits for your repository, which runs when a release pull request merges.

It runs entirely on your machine, with your own registry credentials. Nothing is sent to Glotto, and Glotto never holds a registry token — each publisher reads the credential its registry expects from the environment, exactly as you would publishing by hand.

  • --all — publish every configured target.
  • --lang <slug> — publish one target.
  • --dir <path> — the committed output tree to publish from.
  • --version <version> — the release version. Read from the committed manifest when omitted.
  • --dry-run — print the plan without publishing.
  • --emit-workflow <github|gitlab|bitbucket|azure> — print the release CI workflow.
glotto publish --all --dry-run
glotto publish --all

glotto code-owners

Available in the published CLInpm i -g @glotto/cli

Apply your glotto.yml’s code_owners block to a repository’s review configuration.

This exists because review ownership is a file on only half the forges Glotto manages: GitHub and GitLab read the CODEOWNERS file glotto generate emits, so this command reports the path and writes nothing. Bitbucket and Azure Repos have no such file — their equivalents are default reviewers and a required-reviewers branch policy, both API configuration — so on those two this is the only way a code_owners block takes effect at all.

It runs on your machine and talks to your forge, not to Glotto.

  • --provider <github|gitlab|bitbucket|azure> — required.
  • --repo <ref>owner/name, or org/project/repo for Azure Repos. Required.
  • --host <host> — self-managed GitLab or Azure DevOps host.
  • --config <path> — path to glotto.yml.

Credentials come from GLOTTO_VCS_TOKEN, or GITHUB_TOKEN / GITLAB_TOKEN / BITBUCKET_TOKEN / AZURE_DEVOPS_TOKEN.

glotto code-owners apply --provider bitbucket --repo acme/payments-sdks

glotto login

Available in the published CLInpm i -g @glotto/cli

Authenticate to the Glotto control plane via the device-authorization (RFC 8628) flow and store the resulting token under ~/.glotto/. The published thin-client CLI requires this — glotto generate dispatches codegen to the control plane.

  • --api-url <url> — control-plane base URL (env GLOTTO_API_URL; default https://api.glotto.dev).
  • --scope <scope> — OAuth scope to request; repeatable.
  • --refresh — renew the stored session instead of starting a new device flow.
glotto login                                  # device-flow login to api.glotto.dev
glotto login --api-url https://api.example.com
glotto login --refresh                        # renew the stored session in place

A session token is valid for 30 days. --refresh renews it without a browser round-trip: the old token is revoked and a replacement is stored, so a leaked copy stops working as soon as you renew. The renewal inherits the existing token’s scopes (so --refresh cannot be combined with --scope), and it never falls back to an interactive flow. Renewals are capped at 90 days from the original login — past that, --refresh says so and you sign in again with glotto login.

glotto logout

Available in the published CLInpm i -g @glotto/cli

Remove the stored control-plane credential for the resolved API URL, leaving other URLs untouched. Idempotent — exits 0 whether or not a credential was present.

  • --api-url <url> — control-plane base URL (env GLOTTO_API_URL; default https://api.glotto.dev).
glotto logout
glotto logout --api-url https://api.example.com

What Glotto also runs for you

Most of the capabilities above are also delivered without your running anything. Glotto produces them on its own infrastructure or inside the CI workflow it emits for your repository, and puts the result where you already look — a pull request, a job summary, your dashboard. The command and the delivery are two routes to the same output, not two different features:

  • Verification report — what glotto verify writes, also produced for your release pull request and your dashboard, with a signed attestation you can check offline using glotto verify-attestation.
  • Drift detection — the specific finding that committed SDK output no longer matches the spec it was generated from, including which files and why.
  • Breaking-change detection — every pull request that changes your spec is classified against the last build, whether or not you run glotto breaking-changes yourself.
  • The release flow — the release pull request that precedes the glotto publish step above.
  • Migration — converting an existing project into a glotto.yml, non-destructively: from Stainless (glotto migrate stainless), from Fern, or one endpoint at a time.

One capability is still delivery-only: the Fern conversion needs the spec pipeline, which runs server-side, so glotto migrate fern refuses by name in the published CLI rather than half-running. The boundary is which of Glotto’s engines would have to ship to your machine, not which capabilities we are willing to offer.