Customization

Beta
View as Markdown
Early access

The CLI generator is in early access. Reach out to get started.

A generated CLI can be customized at three levels: the OpenAPI spec it’s built from, the configuration that combines multiple specs into a single command tree, and code that adds custom commands alongside the spec-derived ones.

Overrides and overlays

The CLI generator supports both overrides and overlays for customizing the OpenAPI spec before the CLI is built. This lets you add Fern extensions, rename parameters, or remove internal endpoints without modifying your original spec.

Overlays follow the OpenAPI Overlay Specification and use JSONPath to target elements:

overlay.yaml
1overlay: 1.0.0
2info:
3 title: CLI customizations
4 version: 1.0.0
5actions:
6 - target: $.paths['/plants'].get
7 update:
8 x-fern-sdk-group-name: plants
9 x-fern-sdk-method-name: list
10 - target: $.paths['/internal/debug']
11 remove: true

When both are present, overrides are applied first, then overlays.

Multi-spec merging

A single CLI can combine multiple OpenAPI specs into one command tree. This is useful for APIs that split their spec across domains or versions.

Specs can be merged flat (all commands at the top level) or under a namespace prefix:

main.rs
1CliApp::new("my-api")
2 .spec(include_str!("core.yaml"))
3 .spec_under("billing", include_str!("billing.yaml"))
4 .run()

This produces a CLI where core commands live at the top level and billing commands live under a billing subcommand:

$my-api users list # from core.yaml
$my-api billing invoices list # from billing.yaml

When a namespace matches a top-level resource in the incoming spec, the CLI hoists that resource’s methods into the namespace to avoid repetition (for example, billing billing invoices list becomes billing invoices list).

Custom commands

Generated CLIs can include custom commands alongside the spec-derived ones. Custom commands have access to the same API executor, so they can chain multiple API calls into a single workflow.

main.rs
1CliApp::new("my-api")
2 .spec(include_str!("openapi.yaml"))
3 .auth_scheme_env("bearerAuth", "MY_API_TOKEN")
4 .command(whoami_cmd(), whoami_handler)
5 .run()