What This Template Is For
A CLI tool specification defines every command, flag, argument, and output format your command-line tool will support. It serves as the contract between the engineering team building the tool and the developers who will use it daily.
Many CLI tools ship without a written spec and accumulate inconsistent flag names, conflicting output formats, and undocumented behaviors. A specification written before implementation prevents these problems. It forces you to think through the full command tree, validate naming conventions, and design error messages before writing code.
This template works for internal developer tools, open-source CLIs, and platform SDKs. If you are deciding whether a CLI is the right interface at all, the RICE framework can help you score it against alternatives like a web dashboard or API-only approach. For the broader context of building developer-facing products, the Technical PM Handbook covers how to gather requirements from engineering users. You can also reference the feature spec template for individual commands that need deeper product detail, or check developer experience for principles that apply to CLI design.
When to Use This Template
Use this template when you are building a new CLI tool or adding a major command group to an existing one. It is most useful when multiple engineers will contribute commands and you need a consistent design language across the tool.
Skip this template for one-off scripts or internal automation that only one person will run. Those can be documented with inline comments and a README.
How to Use This Template
- Start by defining the tool name, purpose, and installation method. This section should be clear enough that someone unfamiliar with the project understands what the tool does in 30 seconds.
- Map out the full command hierarchy before specifying individual commands. Group related commands under subcommands (e.g.,
tool auth login,tool auth logout). - For each command, document required arguments, optional flags, default values, and output format. Be explicit about what happens when required arguments are missing.
- Write example invocations for every command. Developers learn CLIs by copying examples, not by reading flag descriptions.
- Define a consistent error format and exit code convention. Every command should return 0 on success and non-zero on failure, with structured error output that scripts can parse.
The Template
Tool Overview
| Field | Details |
|---|---|
| Tool Name | [name] |
| Purpose | [One sentence describing what the tool does] |
| Target Users | [Who will use this tool] |
| Installation | [How to install: npm, brew, binary, etc.] |
| Runtime Requirements | [Node.js version, OS support, dependencies] |
| Config File | [Path and format: ~/.toolrc, .tool.yaml, etc.] |
| Auth Method | [API key, OAuth, token file, none] |
Command Hierarchy
tool
āāā init [Initialize a new project]
āāā config
ā āāā set [Set a configuration value]
ā āāā get [Get a configuration value]
ā āāā list [List all configuration values]
āāā [command-group-1]
ā āāā [subcommand-1] [Description]
ā āāā [subcommand-2] [Description]
ā āāā [subcommand-3] [Description]
āāā [command-group-2]
ā āāā [subcommand-1] [Description]
ā āāā [subcommand-2] [Description]
āāā version [Print version information]
Global Flags
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--help | -h | boolean | false | Show help for any command |
--verbose | -v | boolean | false | Enable verbose output |
--quiet | -q | boolean | false | Suppress non-error output |
--format | -f | string | text | Output format: text, json, yaml |
--config | -c | string | ~/.toolrc | Path to config file |
--no-color | boolean | false | Disable colored output |
Command: [command-name]
Description. [What this command does]
Usage:
tool [command-name] <required-arg> [optional-arg] [flags]
Arguments:
| Argument | Required | Type | Description |
|---|---|---|---|
| Yes | string | [What this argument represents] |
[optional-arg] | No | string | [What this argument represents, default value] |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--flag-1 | -a | string | [Description] | |
--flag-2 | -b | boolean | false | [Description] |
--dry-run | boolean | false | Preview changes without executing |
Output (text):
[Expected output format]
Output (json):
{
"status": "success",
"data": {}
}
Examples:
# Basic usage
tool [command-name] my-arg
# With flags
tool [command-name] my-arg --flag-1 value --dry-run
# Piped output
tool [command-name] my-arg --format json | jq '.data'
[Repeat for each command]
Error Handling
Exit codes:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Invalid arguments or flags |
| 3 | Authentication failure |
| 4 | Network error |
| 5 | Resource not found |
Error output format:
Error: [Human-readable message]
Code: [ERROR_CODE]
Hint: [Suggested fix]
Run 'tool [command] --help' for usage information.
JSON error format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"hint": "Suggested fix"
}
}
Configuration File Format
# ~/.toolrc
version: 1
defaults:
format: text
verbose: false
profiles:
default:
[config-key]: [value]
staging:
[config-key]: [value]
Filled Example: Deployment CLI (shipit)
Tool Overview
| Field | Details |
|---|---|
| Tool Name | shipit |
| Purpose | Deploy applications to staging and production environments |
| Target Users | Backend and frontend engineers on the platform team |
| Installation | npm install -g @acme/shipit |
| Runtime Requirements | Node.js 18+, macOS or Linux |
| Config File | .shipit.yaml in project root |
| Auth Method | OAuth token stored in ~/.shipit/credentials |
Command Hierarchy
shipit
āāā init Initialize shipit in current project
āāā auth
ā āāā login Authenticate with the platform
ā āāā logout Clear stored credentials
ā āāā status Show current auth status
āāā deploy
ā āāā create Create a new deployment
ā āāā status Check deployment status
ā āāā logs Stream deployment logs
ā āāā rollback Roll back to previous version
āāā env
ā āāā list List environments
ā āāā set Set an environment variable
ā āāā get Get an environment variable
āāā version Print shipit version
Command: deploy create
Description. Create a new deployment from the current branch to the specified environment.
Usage:
shipit deploy create <environment> [flags]
Arguments:
| Argument | Required | Type | Description |
|---|---|---|---|
| Yes | string | Target environment: staging, production |
Flags:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--branch | -b | string | current branch | Git branch to deploy |
--tag | -t | string | Specific git tag to deploy | |
--skip-tests | boolean | false | Skip pre-deploy test suite | |
--dry-run | boolean | false | Preview deployment plan without executing | |
--notify | -n | string | Slack channel for deployment notifications |
Examples:
# Deploy current branch to staging
shipit deploy create staging
# Deploy specific tag to production
shipit deploy create production --tag v2.4.1
# Preview deployment without executing
shipit deploy create production --dry-run
# Deploy and notify the team
shipit deploy create staging --notify #platform-deploys
Output (text):
Deploying acme-api@v2.4.1 to production...
Build: āāāāāāāāāāāāāāāāāāāā 100%
Tests: āāāāāāāāāāāāāāāāāāāā 100%
Deploy: āāāāāāāāāāāāāāāāāāāā 40%
Deployment dep_8a3b2c1d in progress.
Run 'shipit deploy status dep_8a3b2c1d' to check progress.
Output (json):
{
"id": "dep_8a3b2c1d",
"environment": "production",
"branch": "main",
"tag": "v2.4.1",
"status": "in_progress",
"started_at": "2026-03-05T14:30:00Z",
"url": "https://deploy.acme.com/dep_8a3b2c1d"
}
Key Takeaways
- Define the full command hierarchy before specifying individual commands to ensure consistent naming
- Include example invocations for every command. Developers learn CLIs by copying examples
- Use consistent exit codes so scripts can reliably detect and handle failures
- Support both human-readable and machine-parseable output formats (text and JSON)
- Document error messages with actionable hints that tell the user how to fix the problem
- Write the spec before implementation to prevent naming drift and inconsistent flag behavior
About This Template
Created by: Tim Adair
Last Updated: 3/5/2026
Version: 1.0.0
License: Free for personal and commercial use
