This project introduces a canonical JSON Schema to create a universal, declarative standard for defining CLIs. The goal is to move beyond inconsistent, code-first frameworks and enable a future where command-line tools are self-describing, interoperable, and supported by a rich ecosystem of automated tooling.
By defining the structure of a CLI in a simple, standardized YAML file, we can unlock massive productivity gains and create more robust, consistent, and user-friendly tools.
Adopting a schema-first, declarative approach for your CLI offers a significant return on investment by:
- Drastically Reducing Boilerplate: Define your commands, arguments, and options in YAML. Let the ecosystem handle the parsing, validation, and help text generation.
- Enforcing Consistency: A single source of truth ensures that your CLI's behavior is consistent and predictable, reducing bugs and user confusion.
- Enabling Automation: Once your CLI is defined in a machine-readable format, you can automate documentation generation, create client libraries, and even build GUIs on top of your existing CLI logic.
- Decoupling Logic from Definition: Your core application logic remains separate from the CLI definition, making your code cleaner, easier to test, and simpler to refactor.
To get started with cli-schema, you have several options:
To install the package for use in your project:
npm install cli-schemaTo install it globally, making the cli-schema command available everywhere on your system:
npm install -g cli-schemaIf you prefer Yarn, you can install the package for use in your project:
yarn add cli-schemaTo install it globally:
yarn global add cli-schemaIf you want to contribute to the project or need the source code directly:
git clone https://github.com/ioncakephper/cli-schema.git
cd cli-schema
npm install # Or yarn installThis package can be used both as a command-line tool for quick validation and as a library in your own projects.
The package includes a cli-schema executable for instantly validating one or more YAML definition files.
# Validate a single file
npx cli-schema path/to/your/file.yml
# Validate multiple files
npx cli-schema file1.yml file2.ymlRun the command with no arguments or with the --help flag to see the full list of options and examples.
On success, you will see output similar to this:
✅ path/to/your/file.yml is valid against cli.schema.json
Integrate validation directly into your build process or application.
const { validateYaml } = require('cli-schema');
const result = validateYaml('./examples/demo-init.yml');
if (result.valid) {
console.log('CLI definition is valid!');
} else {
console.error('Validation failed:', result.errors);
}To get autocompletion and real-time validation when writing your CLI definition files, you can link the schema directly in your YAML file. Most modern editors (like VS Code with the YAML extension) support this via a special comment.
Add the following line to the top of your YAML file:
# yaml-language-server: $schema=https://cdn.jsdelivr.net/npm/cli-schema@3.0.0/schema/cli.schema.json
cli:
name: my-cli
description: A sample CLI defined with cli-schema.
version: 1.0.0
# ... rest of your definitionBy adding this comment, your editor will provide:
- Autocompletion for all properties (
name,commands,options, etc.). - Validation to catch typos and structural errors as you type.
- Descriptions on hover for each property.
Note: For the latest schema, you can use
.../npm/cli-schema/schema/cli.schema.json, but using a specific version is recommended for stability.
While the examples show a simple command, the schema is designed to handle enterprise-grade CLIs with dozens of nested commands, complex options, and varied argument structures. Advanced features like command hierarchies, option dependencies, and reusable type definitions are modeled directly in the schema, ensuring that it scales with your project's needs without sacrificing clarity.
- Description: Validates a YAML document against the canonical CLI schema.
- Parameters:
input(string): The YAML document as a string or a path to a file.options(object, optional):isFile(boolean): Set totrueifinputis a file path. Defaults totrue.
- Returns:
object- An object containing avalidboolean and anerrorsarray.
Important
All CLI definitions must be nested under a top-level cli object. This root object is mandatory and serves as the container for all commands, arguments, and options that define your command-line interface. While other properties can exist alongside the cli object, they will not be validated by the schema.
The cli object is the root of your CLI definition. It contains the following properties:
| Property | Type | Description |
|---|---|---|
arguments |
array |
An array of argument objects for the root command. |
commands |
array |
An array of nested command objects (subcommands). |
defaultConfigFile |
string |
The path to a default configuration file that the CLI should load. |
description |
string |
A brief description of your CLI's purpose. |
fallbackConfig |
object |
An object containing fallback configuration values to be used if the default configuration file is not found or does not contain a required value. |
name |
string |
The name of your CLI application. (Required) |
options |
array |
An array of option objects for the root command. |
showGlobalOptions |
boolean |
If true, global options will be displayed in the help output for subcommands. |
sortCommands |
boolean |
If true, help output will display commands in alphabetical order. |
sortOptions |
boolean |
If true, help output will display options in alphabetical order. |
version |
string |
The version of your CLI. It is recommended to follow semantic versioning (e.g., 1.0.0). |
The cli-schema defines the structure for your CLI definition file. Here are the main building blocks:
| Property | Type | Description |
|---|---|---|
alias |
string |
An alternative name for the command. Follows the same pattern as name. |
arguments |
array |
An array of argument objects for this command. |
commands |
array |
An array of nested command objects (subcommands). |
description |
string |
A brief description of what the command does. |
name |
string |
The name of the command. Must be ^[a-zA-Z](?:-?[a-zA-Z])*$. (Required) |
options |
array |
An array of option objects for this command. |
| Property | Type | Description |
|---|---|---|
default |
object |
A default object defining the default value for this argument. |
description |
string |
A brief description of the argument. |
name |
string |
The name of the argument. Must be ^[a-zA-Z](?:-?[a-zA-Z])*$. (Required) |
required |
boolean |
Whether the argument is required. Defaults to false. |
type |
string |
The data type. Can be string, number, boolean. Defaults to string. |
variadic |
boolean |
Whether the argument can accept multiple values. Defaults to false. |
| Property | Type | Description |
|---|---|---|
arguments |
array |
An array of argument objects that can be associated with this option. |
choices |
array |
A list of allowed values for the option. |
default |
object |
A default object defining the default value for this option. |
description |
string |
A brief description of the option. |
name |
string |
The long name of the option (e.g., port). (Required) |
range |
object |
A numerical range with min and max properties for the option's value. |
required |
boolean |
Whether the option is required. Defaults to false. |
short |
string |
The single-letter short alias (e.g., p). Must be ^[a-zA-Z]$. |
type |
string |
The data type. Can be string, number, boolean. |
Important
The default object is used to define a default value for an argument or option. It must have exactly one of the following properties:
| Property | Type | Description |
|---|---|---|
value |
string, number, boolean, array, object |
A literal value to use as the default. |
fromConfig |
string |
A dot-notation path to retrieve a value from a configuration file (e.g., user.name). |
fn |
string |
A JavaScript arrow function that returns the default value. The program object is available as an argument. |
Explore various CLI definition examples adhering to the cli.schema.json in the EXAMPLES.md file. These practical demonstrations showcase how to structure your CLI metadata declaratively, covering different scenarios from simple tools to complex command structures.
A schema is just the foundation. The true power will come from the ecosystem built around it. This is where we are headed:
- Code Generators: Create CLI boilerplate in multiple languages (Node.js, Python, Go) directly from the schema.
- Documentation Generators: Automatically generate professional, versioned web documentation and man pages.
- IDE Integration: Provide real-time validation, autocompletion, and tooltips for CLI definition files in editors like VS Code.
- Dynamic GUI Generation: Create simple graphical interfaces for your CLI on the fly.
- CLI Discovery & Interoperability: Enable tools to programmatically understand and interact with each other.
We are actively seeking contributors to help build this ecosystem.
This is an ambitious project, and contributions are essential to its success. Please read our Contributing Guidelines to learn how you can help shape the future of CLIs.
This project is licensed under the MIT License. See the LICENSE file for details.