Generate agent-friendly Cobra CLIs from OpenAPI, Swagger, protobuf, and GraphQL API specs.
Lathe is an API-to-CLI generator for teams that want one binary humans can use
and AI agents can inspect safely. It turns Swagger 2.0, OpenAPI 3, and
google.api.http protobuf APIs, plus curated GraphQL schemas, into
production-grade Cobra CLIs with structured command discovery, auth metadata,
request body builders, and machine-readable output.
Generated CLIs ship with command catalog JSON, intent search, per-command detail
JSON, auth metadata, body builders, structured output formats, and a repo-local
Skill directory under skills/<cli-name>/.
Start with the CLI usage guide:
- CLI Usage: generate a downstream CLI with
lathe bootstrap, wirecmd/<name>/main.go, build it, and verify the agent loop.
Lathe generates single-binary command-line tools from existing API specifications. Instead of hand-writing a CLI that can drift away from the API, you pin upstream specs, configure the CLI identity, optionally add overlays for better help text, and regenerate when the API changes.
The result is more than a human-facing API wrapper. Lathe emits an agent-friendly CLI surface where commands can be searched, inspected, validated, and executed through machine-readable contracts.
Use Lathe when you need to:
- Generate a Cobra CLI from OpenAPI 3, Swagger 2.0, protobuf services, or GraphQL control-plane APIs.
- Keep an internal or customer-facing CLI synchronized with upstream API specs.
- Expose API operations to AI agents without making them guess flags, auth, body shape, or output format.
- Ship one binary with command discovery, auth preflight, structured output, and generated agent Skill documentation.
- Improve generated help text and examples through overlays without editing generated Go code.
Every serious API eventually needs a CLI. Most teams still hand-write command trees that mirror an existing API spec, then spend the rest of the project's life keeping those commands from drifting.
Lathe makes the API spec the source of truth.
You declare pinned upstream specs or local working-tree specs, declare the CLI identity, add optional help-text overlays, and generate the binary. When the API changes, bump the pinned tag or rerun sync for the local source, then regenerate.
The result is not just a wrapper. It is an agentic-friendly CLI surface with a runtime catalog that tells agents what commands exist, which flags are required, whether auth is needed, what HTTP request will be made, how request bodies are built, and which output format to prefer.
| Capability | What it means |
|---|---|
| Multi-backend generation | Swagger 2.0, OpenAPI 3, protobuf services with google.api.http annotations, and curated GraphQL schemas become Cobra command trees. |
| Single runtime shape | Generated modules share one runtime for auth, request building, output formatting, pagination, streaming, and error handling. |
| Agentic-friendly discovery | search, commands --json, commands show, and commands schema expose the CLI as structured data. |
| Generated Skills | Codegen writes skills/<cli-name>/ so agents can load the CLI's operating guide and module references. |
| Reproducible inputs | Git specs are pinned by tag and resolved to commit SHA; local sources are staged from checked-in configuration. |
| Real CLI UX | Hostname-keyed auth, --file, --set, --set-str, -o table|json|yaml|raw, enum validation, pagination, and streaming. |
| Overlay polish | Improve summaries, aliases, parameter help, grouping, and examples without editing generated code. |
- Governance: decision process and compatibility expectations.
- Maintainers: maintainer responsibilities and review expectations.
- Showcase: CLI generation paths and real-world usage notes.
- CLI Usage: command sequence for generating and validating a downstream CLI.
- Adopters: public and anonymized user entries.
- Contributing: local setup, PR workflow, and project scope.
- Security: private vulnerability reporting and supported versions.
Create a repository from github.com/lathe-cli/lathe, then configure two files.
Lathe release archives include one command-line tool, lathe, with generation
subcommands:
lathe specsync: sync declared API specs into the local cache.lathe codegen: generate runtime command specs and optional Skill files.lathe bootstrap: runspecsyncandcodegenin one pass.
Download the archive for your platform from the latest release, unpack it, and put lathe on your PATH.
When working from a source checkout, you can use the Make targets shown below instead of installing the release tools.
cli.yaml:
cli:
name: acmectl
short: "Command-line tool for Acme services"
auth:
validate:
method: GET
path: /api/v1/whoami
display:
username_field: data.username
fallback_field: data.emailcli.command_path defaults to auto: one source module uses
<cli> <group> <operation> when safe, while multiple modules keep
<cli> <module> <group> <operation>. Use namespaced to always keep the
module segment.
specs/sources.yaml:
sources:
iam:
repo_url: https://github.com/acme/iam.git
pinned_tag: v1.4.0
backend: swagger
swagger:
files:
- api/openapi/user.swagger.json
billing:
repo_url: https://github.com/acme/billing.git
pinned_tag: v0.9.2
backend: proto
proto:
staging:
- from: api/proto
to: "."
entries:
- v1/accounts.proto
payments:
repo_url: https://github.com/acme/payments.git
pinned_tag: v2.1.0
backend: openapi3
openapi3:
files:
- api/openapi.yaml
console:
repo_url: https://github.com/acme/graphql-console.git
pinned_tag: v3.0.0
backend: graphql
graphql:
schema: schema/console.graphql
expose:
queries: ["listApps", "getApp"]
mutations: ["createApp"]
groups:
- match: ["*App*"]
group: Apps
output:
- match: ["listApps"]
list_path: data.listApps.nodes
default_columns: ["id", "name", "status"]
selection:
max_depth: 2
prune: ["App.secretToken"]
awire:
local_path: ../awire
backend: openapi3
openapi3:
files:
- openapi/awire.yamllathe bootstrap
go build -o bin/acmectl ./cmd/acmectllathe bootstrap syncs declared specs and runs codegen. Codegen emits generated Go
modules and, by default, a Skill directory at skills/acmectl/.
Log in, discover the generated command, inspect its exact shape, then run it:
./bin/acmectl auth login --hostname api.acme.com
./bin/acmectl search "create user" --json
./bin/acmectl commands show iam users create-user --json
./bin/acmectl auth status --hostname api.acme.com
./bin/acmectl iam users create-user \
--set email=alice@example.com \
--set role=viewer \
-o jsonGenerated CLIs are designed so an agent does not have to guess.
| Command | Purpose |
|---|---|
<cli> search "<intent>" --json |
Find candidate commands from natural-language intent. Supports --limit. Search output is for discovery only. |
<cli> commands --json |
Read the complete generated command catalog. Use --include-hidden when hidden commands matter. |
<cli> commands show <path...> --json |
Inspect the source of truth for one command before execution: flags, body, auth, HTTP method/path, and output hints. |
<cli> commands schema --json |
Check the catalog schema version before durable machine parsing. |
<cli> auth status --hostname <host> |
Confirm credentials before running a command whose detail says auth.required=true. |
Recommended agent loop:
- Use
search "<intent>" --jsonto find candidates. - Use
commands show <path...> --jsonfor the selected command. - If
auth.required=true, runauth status --hostname <host>and stop if the user is not logged in. - Execute only after flags, body requirements, auth, HTTP path, and output hints are clear.
- Prefer
-o jsonfor machine-readable command output unless the user asked for a human-readable table.
Codegen writes a standard Skill directory by default:
skills/<cli-name>/
|-- SKILL.md
|-- agents/openai.yaml
`-- references/
|-- catalog.md
`-- modules/<source-name>.md
The Skill is a compact operating guide for agents. It explains command discovery, catalog inspection, auth preflight, body input, output formats, and per-source module references.
The runtime catalog remains the source of truth. Agents should use the Skill to
learn how to operate the CLI, then use commands show <path...> --json for exact
execution details.
Disable Skill output when needed:
go run ./cmd/lathe codegen -skill-root ""Defines CLI identity and optional auth validation behavior.
| Field | Notes |
|---|---|
cli.name |
Binary and command name, for example acmectl. |
cli.short |
Root command summary. |
auth.validate |
Optional endpoint used by auth status to display the logged-in user. |
Declares which upstream specs become modules.
| Field | Required | Notes |
|---|---|---|
repo_url |
Git sources | Any URL git clone accepts. |
pinned_tag |
Git sources | Floating branches are rejected; reproducibility is mandatory. |
local_path |
Local sources | Local filesystem path or file:// URL, relative paths resolve from specs/sources.yaml. Mutually exclusive with repo_url and pinned_tag. |
backend |
Yes | One of swagger, openapi3, proto, or graphql. |
swagger.files |
Swagger only | One or more Swagger 2.0 JSON specs. |
openapi3.files |
OpenAPI 3 only | JSON or YAML OpenAPI specs. |
proto.staging |
Proto only | Files staged into the protoc include root before parsing. |
proto.entries |
Proto only | Entry proto files; only RPCs with google.api.http become commands. |
graphql.schema |
GraphQL only | Pinned SDL file staged from the upstream repository. |
graphql.expose |
GraphQL only | Explicit queries and/or mutations allow policy; missing policy fails closed. |
graphql.groups |
GraphQL only | Operation-name globs mapped to CLI groups. Ambiguous matches fail closed. |
graphql.output |
GraphQL only | Configured list path and default columns for generated output hints. |
graphql.selection |
GraphQL only | Selection-set max depth and per-type field pruning. Explicit max_depth must be greater than zero. |
Grouping rules:
- Swagger and OpenAPI 3 use the operation's first tag.
- Proto uses the service name.
- GraphQL uses
graphql.groupspolicy and falls back to the source module name when no group policy matches.
GraphQL commands execute POST /graphql with a baked {query, variables}
request envelope. Scalar and enum arguments become typed flags that merge under
variables. Input-object arguments expand scalar and enum leaf fields into
dotted variable flags such as --input-name; required fields that cannot be
represented as flags fail codegen instead of publishing an incomplete command.
Optional complex fields can still be supplied with --set or --file.
Relay-style outputs with list_path: data.<operation>.nodes or .edges,
pageInfo.endCursor, pageInfo.hasNextPage, and an after argument get
--all; subsequent pages write the cursor back under variables.after.
Overlays polish generated commands without changing the upstream spec or editing generated Go code.
internal/overlay/iam.yaml:
defaults:
pagination:
match_commands: ["list-*", "query-*"]
params:
page: "1"
pageSize: "20"
commands:
create-user:
short: "Create a user in the IAM service"
aliases: [adduser]
shortcuts:
- use: quick-user
params:
type: human
role: viewer
example: |
acmectl iam create-user \
--set email=alice@example.com \
--set role=viewer
params:
type:
help: "Required by the backend even when the upstream spec omits it"
required: true
role:
help: "User role (viewer, editor, admin)"
default: viewerCommand ignore: true removes a generated command. Command hidden: true
keeps it generated but hidden from normal help and catalog output unless
--include-hidden is used. Parameter hidden: true is a legacy alias for
deprecated: true; prefer deprecated: true for parameter overlays.
Bulk pagination defaults fill matching command params that have no spec default.
Explicit commands.<use>.params.<name>.default still wins when a command needs a
different value. Parameter required: true marks an existing generated flag as
required when an upstream spec is incomplete; it does not create new flags.
Command shortcuts add root-level commands that execute the same generated
operation with preset values for existing parameters. Shortcut params may use
the parameter name or flag name; invocation flags can still override the preset.
Run codegen with an overlay directory:
go run ./cmd/lathe codegen -overlay internal/overlay| Flag | Effect |
|---|---|
--hostname |
Select host for this invocation. |
-o, --output |
Output format: table, json, yaml, or raw. |
Lathe runtime commands that should not occupy generated API command names live under the hidden __lathe command:
| Command | Effect |
|---|---|
<cli> __lathe version |
Print version information. |
<cli> __lathe completion <shell> |
Generate shell completion scripts. |
| Env var | Effect |
|---|---|
$<NAME>_HOST |
Select host without editing the host config. |
$<NAME>_CONFIG_DIR |
Override the config directory, defaulting to ~/.config/<name>. |
LATHE_SPECS_CACHE |
Where spec sync stages upstream specs, defaulting to .cache. |
<NAME> is the uppercased cli.name.
Generated commands expose request body helpers when the API operation accepts a body:
| Flag | Use |
|---|---|
--file path.json |
Load the request body from a JSON file. |
--set key.path=value |
Build JSON from repeated key/value assignments. |
--set-str key.path=value |
Build JSON while forcing the value to remain a string. |
Lathe has two phases:
lathe specsyncchecks out pinned Git sources or stageslocal_pathsources, then writes local spec state.lathe codegennormalizes specs into one intermediate representation, applies overlays, renders Go command modules, and renders the Skill directory.
The generated CLI uses pkg/lathe and pkg/runtime for the shared command
catalog, auth, request construction, output formatting, pagination, streaming,
and stable error handling.
- Spec is truth. Generated command behavior should come from the API spec.
- Catalog is contract. Humans can read help text; agents need structured command facts.
- Search is not execution. Search finds candidates;
commands showconfirms exact command shape. - Auth is explicit. Credentials are keyed by hostname, and agents should preflight auth before protected calls.
- Overlay after generation. Polish weak spec text without forking generated code.
- One binary at runtime. The generated CLI should be easy to install, inspect, and automate.
See CONTRIBUTING.md. All commits must be signed off with
git commit -s per the Developer Certificate of Origin.
See SECURITY.md for private vulnerability disclosure.
MIT (c) lathe-cli
