Creating CLI Commands
This guide is for developers contributing new commands to the EAC CLI in go/eac/commands/impl/.
Overview
The EAC CLI uses a structured comment-based system to define command metadata, help text, and flags. This guide provides templates and best practices for creating new commands that integrate seamlessly with the CLI's help system, command registry, and shell completion.
Command File Header Template
Every command file must include structured comment headers that define help metadata. Copy this template and fill in the placeholders:
// Command: <parent> <subcommand>
// Short: <One sentence describing what this command does>
// Long: <First paragraph explaining the purpose and what problem it solves>
// Long: <Second paragraph describing the behavior and how it works>
// Long: <Third paragraph describing inputs, outputs, and important details>
// Flag.<flagname>: type=<type>, default=<value>, shorthand=<letter>, usage=<Educational description of what this flag does, when to use it, and why>, required=<true|false>, completion=<val1,val2,...>
package mypackage
Header Field Descriptions
Command: (Required)
The command name as users will type it, with spaces separating parent and subcommand.
Examples:
build- Standalone commandcreate spec- Subcommand under createshow modules- Subcommand under show
Short: (Required)
A single sentence (50-80 characters) that concisely describes what the command does. This appears in command listings.
Best Practices:
- Start with a verb (e.g., "Generate", "Display", "Validate")
- Be specific about what the command operates on
- Avoid generic phrases like "Manages things" - be concrete
Good Examples:
Generate AI-powered commit messages from staged changesDisplay all module contracts in a human-readable tableValidate Gherkin specifications against quality contracts
Bad Examples:
- ❌
Handles commits(too vague) - ❌
A command for creating specifications(unnecessary words) - ❌
This command validates files(don't say "this command")
Long: (Required, Multiple Lines)
Detailed multi-paragraph description explaining the command thoroughly. Each // Long: line becomes a paragraph in the help output.
Structure:
- First paragraph: What does this command do? What problem does it solve?
- Second paragraph: How does it work? What's the behavior?
- Third paragraph: What inputs does it accept? What outputs does it produce?
- Additional paragraphs (optional): Default behaviors, validation requirements, special notes
Best Practices:
- Write in present tense
- Be specific about formats, locations, and behaviors
- Mention default behaviors explicitly
- Explain validation or error conditions
- Reference related commands if relevant
Example:
// Long: The create spec command uses AI to transform natural language feature descriptions into
// Long: properly formatted Gherkin specifications following Rule/Scenario patterns. The generated specifications
// Long: include Feature, Rule, and Scenario blocks with appropriate tags and structure.
// Long: All specifications are validated against the specification contract to ensure they meet quality standards.
// Long: The command automatically saves the specification to the specs/ directory, organized by module.
// Long: Use --debug to inspect intermediate outputs and understand how the AI generates specifications.
Flag.<name>: (Optional, One per Flag)
Structured flag definition with key=value attributes.
Format:
// Flag.<flagname>: type=<type>, default=<value>, shorthand=<letter>, usage=<description>, required=<true|false>, completion=<values>
Attributes:
type(required):bool,string,int,floatdefault(optional): Default value as string (e.g.,false,text,0)shorthand(optional): Single letter for short flag (e.g.,dfor-d)usage(required): Educational description (can contain commas)required(optional):trueorfalse(default:false)completion(optional): Comma-separated list of valid values
Usage Field Guidelines: The usage field is the most important part - make it educational and specific:
- Explain WHAT the flag does
- Explain WHEN to use it
- Explain WHY it's useful
- Mention any side effects or important details
- Provide examples of valid values if applicable
Good Flag Examples:
// Flag.debug: type=bool, shorthand=d, default=false, usage=Enable debug mode to save intermediate outputs (context, prompts, AI responses) to the 'out' directory for troubleshooting and analysis
// Flag.module: type=string, shorthand=m, usage=Target module for the specification (e.g., eac-commands, eac-core). If not provided, the module will be inferred from the description
// Flag.format: type=string, shorthand=f, default=text, completion=text,json, usage=Output format for validation results (text for human-readable, json for machine-readable)
// Flag.quiet: type=bool, shorthand=q, default=false, usage=Suppress success messages and show only validation errors and warnings
Bad Flag Examples:
// ❌ Flag.debug: type=bool, usage=Debug mode
// (Too vague - what does debug mode do?)
// ❌ Flag.output: type=string, usage=Output path
// (Missing details - what goes in this path? What format? What's the default?)
// ❌ Flag.verbose: type=bool, usage=More output
// (Not educational - more output of what? When would I use this?)
Complete File Template
Here's a complete template with placeholder explanations:
// Command: <command-name> or <parent> <subcommand>
// Short: <One sentence describing what this command does>
// Long: <Purpose: What does this do and what problem does it solve?>
// Long: <Behavior: How does it work? What's the workflow?>
// Long: <I/O: What inputs? What outputs? What format?>
// Long: <Details: Default behaviors, validation, special notes>
// Flag.flagname1: type=bool, shorthand=f, default=false, usage=<Educational description: what, when, why>
// Flag.flagname2: type=string, shorthand=s, usage=<Educational description with details and examples>, required=true, completion=option1,option2
package mypackage
import (
"fmt"
"os"
"strings"
"github.com/ready-to-release/eac/go/eac/commands/internal/registry"
"github.com/ready-to-release/eac/go/eac/core/repository"
)
func init() {
registry.Register(MyCommand)
}
// Config holds configuration for this command
type Config struct {
// Add fields for each flag
FlagName1 bool
FlagName2 string
// Add other configuration fields
}
// MyCommand is the main entry point for the command
func MyCommand() int {
// Parse configuration
config, err := parseConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
return 1
}
// Get repository root if needed
workspaceRoot, err := repository.GetRepositoryRoot("")
if err != nil {
fmt.Fprintf(os.Stderr, "Error: failed to find repository root: %v\n", err)
return 1
}
// Implement command logic here
// ...
return 0
}
// parseConfig parses command line arguments into configuration
func parseConfig() (*Config, error) {
config := &Config{}
args := os.Args[2:] // Skip program name and command name
for i := 0; i < len(args); i++ {
arg := args[i]
switch arg {
case "--flagname1", "-f":
config.FlagName1 = true
case "--flagname2", "-s":
if i+1 < len(args) {
config.FlagName2 = args[i+1]
i++
} else {
return nil, fmt.Errorf("--flagname2 requires a value")
}
default:
if !strings.HasPrefix(arg, "-") {
// Handle positional arguments
} else {
return nil, fmt.Errorf("unknown flag: %s", arg)
}
}
}
// Validation
if config.FlagName2 == "" {
return nil, fmt.Errorf("--flagname2 is required\n\nUsage: mycommand [--flagname1] --flagname2 <value>")
}
return config, nil
}
Best Practices
Writing Clear Help Text
- Be Specific: Instead of "Process files", write "Validate all .feature files in the specs/ directory"
- Explain Defaults: "By default, output is in human-readable text format"
- Mention Validation: "The command validates that the module exists before proceeding"
- Reference Examples: "e.g., eac-commands, eac-core" when describing modules
- Explain Exit Codes: "Exit code is 0 if all validations pass, 1 if any critical errors are found"
Flag Design
- Provide Shorthands: Common flags (
-dfor debug,-vfor verbose,-qfor quiet) - Use Completion: Provide static completion values when options are limited
- Required Flags: Only use
required=truewhen the flag is absolutely necessary - Default Values: Always specify defaults for optional flags
- Consistent Naming: Use kebab-case (
--output-path, not--outputPath)
Command Organization
- Group Related Commands: Use parent commands (specs, show, get, etc.)
- Clear Naming: Command names should be verb-noun (create, validate) or verb (show)
- Consistent Structure: All commands follow the same pattern
- Error Handling: Always return meaningful error messages with context
Testing Your Help Text
After creating your command, test the help output:
# View command list
go run . help
# View specific command help
go run . help your-command
# Test flag parsing
go run . your-command --help
# Generate completion (verify flags appear)
go run . completion bash
Examples to Reference
See these well-documented commands for examples:
go/eac/commands/impl/commit/message.go- Complex command with AI integrationgo/eac/commands/impl/create/spec/create.go- Multiple flags with completiongo/eac/commands/impl/validate/specs.go- Format flag with completiongo/eac/commands/impl/show/modules.go- Simple read-only commandgo/eac/commands/impl/help/help.go- Command with verbose flag
Tutorials | How-to Guides | Explanation | Reference
You are here: Reference — information-oriented technical descriptions of the system.