id = "openapi"
name = "OpenAPI CLI"
homepage = "https://github.com/speakeasy-api/openapi"
description = "A set of packages and tools for working with OpenAPI Specification documents."
executables = ["openapi"]
platforms = ["macos", "linux"]
[dotfiles]
paths = ["~/.openapi/lint.yaml"]
exclude = []
secret = []
[commands]
format = 1
label = "OpenAPI CLI"
description = "Validate, lint or bundle an OpenAPI specification. Overlays, Arazzo workflows, sanitize, optimize, join and the other spec commands are left out."
quality = "ai-draft"
parser = { end_of_options = "--", interleave = "permute", long_equals = true, short_attached = true, short_bundles = false }
[[commands.subcommand]]
path = ["spec", "validate"]
label = "Validate a specification"
[[commands.subcommand.source]]
id = "readme"
kind = "manual"
url = "https://github.com/speakeasy-api/openapi/blob/main/cmd/openapi/commands/openapi/README.md"
revision = "2026-10"
evidence = """
openapi spec validate ./spec.yaml
openapi spec validate -v ./spec.yaml
"""
[[commands.subcommand.field]]
id = "verbose"
label = "Verbose"
type = "boolean"
option = ["-v"]
sources = ["readme"]
[[commands.subcommand.field]]
id = "spec"
label = "Specification"
type = "path"
position = 0
path = { kind = "file", role = "input" }
sources = ["readme"]
[[commands.subcommand.task]]
id = "validate"
label = "Validate"
fields = ["spec", "verbose"]
required = ["spec"]
[[commands.subcommand.group]]
id = "basic"
label = "Basic"
fields = ["spec", "verbose"]
[[commands.subcommand]]
path = ["spec", "lint"]
label = "Lint a specification"
[[commands.subcommand.source]]
id = "readme"
kind = "manual"
url = "https://github.com/speakeasy-api/openapi/blob/main/cmd/openapi/commands/openapi/README.md"
revision = "2026-10"
evidence = """
openapi spec lint ./spec.yaml
openapi spec lint -f json ./spec.yaml
openapi spec lint -c ./lint.yaml ./spec.yaml
openapi spec lint -d rule-id-1 -d rule-id-2 ./spec.yaml
openapi spec lint --fix ./spec.yaml
openapi spec lint --fix-interactive --dry-run ./spec.yaml
| `--format` | `-f` | Output format: `text` (default) or `json` |
| `--config` | `-c` | Path to lint configuration file |
| `--ruleset` | `-r` | Ruleset to use (default: `all`) |
| `--disable` | `-d` | Rules to disable (can be specified multiple times) |
| `--summary` | | Print a per-rule summary table of findings |
| `--fix` | | Automatically apply non-interactive fixes and write back |
| `--dry-run` | | Show what fixes would be applied without changing the file (requires `--fix` or `--fix-interactive`) |
"""
[[commands.subcommand.field]]
id = "format"
label = "Output format"
type = "enum"
option = ["--format", "-f"]
choices = [{ value = "text", label = "Text" }, { value = "json", label = "JSON" }]
sources = ["readme"]
[[commands.subcommand.field]]
id = "config"
label = "Lint configuration"
type = "path"
option = ["--config", "-c"]
path = { kind = "file", role = "input" }
sources = ["readme"]
[[commands.subcommand.field]]
id = "ruleset"
label = "Ruleset"
description = "Default is all."
type = "string"
option = ["--ruleset", "-r"]
sources = ["readme"]
[[commands.subcommand.field]]
id = "disable"
label = "Disabled rules"
type = "string"
option = ["--disable", "-d"]
multiple = true
sources = ["readme"]
[[commands.subcommand.field]]
id = "summary"
label = "Per-rule summary"
type = "boolean"
option = ["--summary"]
sources = ["readme"]
[[commands.subcommand.field]]
id = "fix"
label = "Apply fixes in place"
description = "Writes the non-interactive fixes back to the specification file."
type = "boolean"
option = ["--fix"]
effect = "overwrite"
sources = ["readme"]
[[commands.subcommand.field]]
id = "dry_run"
label = "Dry run"
description = "Only meaningful together with --fix."
type = "boolean"
option = ["--dry-run"]
sources = ["readme"]
[[commands.subcommand.field]]
id = "spec"
label = "Specification"
type = "path"
position = 0
path = { kind = "file", role = "input" }
sources = ["readme"]
[[commands.subcommand.task]]
id = "lint"
label = "Lint"
fields = ["spec", "format", "config", "disable"]
required = ["spec"]
[[commands.subcommand.task]]
id = "fix_preview"
label = "Preview fixes"
fields = ["spec", "fix", "dry_run"]
required = ["spec"]
set = { fix = [true], dry_run = [true] }
[[commands.subcommand.group]]
id = "basic"
label = "Basic"
fields = ["spec", "format", "config", "disable", "summary"]
[[commands.subcommand.group]]
id = "advanced"
label = "Advanced"
fields = ["ruleset", "fix", "dry_run"]
[[commands.subcommand]]
path = ["spec", "bundle"]
label = "Bundle external references"
[[commands.subcommand.source]]
id = "readme"
kind = "manual"
url = "https://github.com/speakeasy-api/openapi/blob/main/cmd/openapi/commands/openapi/README.md"
revision = "2026-10"
evidence = """
openapi spec bundle ./spec.yaml ./bundled-spec.yaml
openapi spec bundle -w --naming counter ./spec.yaml
openapi spec bundle --naming filepath ./spec.yaml ./bundled.yaml
- `filepath` (default): Uses file path-based naming like `external_api_yaml__User` for conflicts
- `counter`: Uses counter-based suffixes like `User_1`, `User_2` for conflicts
"""
[[commands.subcommand.field]]
id = "write"
label = "Rewrite the input file in place"
type = "boolean"
option = ["-w"]
effect = "overwrite"
sources = ["readme"]
[[commands.subcommand.field]]
id = "naming"
label = "Naming strategy"
type = "enum"
option = ["--naming"]
choices = [{ value = "filepath", label = "File path (default)" }, { value = "counter", label = "Counter" }]
sources = ["readme"]
[[commands.subcommand.field]]
id = "spec"
label = "Specification"
type = "path"
position = 0
path = { kind = "file", role = "input" }
sources = ["readme"]
[[commands.subcommand.field]]
id = "output"
label = "Output file"
description = "Omit to print to stdout."
type = "path"
position = 1
path = { kind = "file", role = "output" }
sources = ["readme"]
[[commands.subcommand.task]]
id = "bundle"
label = "Bundle to a file"
fields = ["spec", "output", "naming"]
required = ["spec", "output"]
[[commands.subcommand.group]]
id = "basic"
label = "Basic"
fields = ["spec", "output", "naming", "write"]