All skills
Skillintermediate
CLI Design Patterns
``` mycli # Root command ├── init [options] # Simple command ├── config │ ├── get <key> # Nested subcommand │ ├── set <key> <value> │ └── list ├── deploy [environment] # Command with args │ ├── --dry-run # Flag │ ├── --force │ └── --config <file> # Option with value └── plugins ├── install <name> ├── list └── remove <name> ```
Claude Code Knowledge Pack7/10/2026
Overview
CLI Design Patterns
Command Hierarchy
mycli # Root command
├── init [options] # Simple command
├── config
│ ├── get <key> # Nested subcommand
│ ├── set <key> <value>
│ └── list
├── deploy [environment] # Command with args
│ ├── --dry-run # Flag
│ ├── --force
│ └── --config <file> # Option with value
└── plugins
├── install <name>
├── list
└── remove <name>
Flag Conventions
# Boolean flags (presence = true)
mycli deploy --force --dry-run
# Short + long forms
mycli -v --verbose
mycli -c config.yml --config config.yml
# Required vs optional
mycli deploy <env> # Positional (required)
mycli deploy --env production # Flag (optional)
# Multiple values
mycli install pkg1 pkg2 pkg3 # Variadic args
mycli --exclude node_modules --exclude .git
Configuration Layers
Priority order (highest to lowest):
- Command-line flags - Explicit user intent
- Environment variables - Runtime context
- Config files (project) -
.myclirc,mycli.config.js - Config files (user) -
~/.myclirc,~/.config/mycli/config.yml - Config files (system) -
/etc/mycli/config.yml - Defaults - Hard-coded sensible defaults
// Example config resolution
const config = {
...systemDefaults,
...loadSystemConfig(),
...loadUserConfig(),
...loadProjectConfig(),
...loadEnvVars(),
...parseCliFlags(),
};
Exit Codes
Standard POSIX exit codes:
const EXIT_CODES = {
SUCCESS: 0,
GENERAL_ERROR: 1,
MISUSE: 2, // Invalid arguments
PERMISSION_DENIED: 77,
NOT_FOUND: 127,
SIGINT: 130, // Ctrl+C
};
Plugin Architecture
mycli/
├── core/ # Core functionality
├── plugins/
│ ├── aws/ # Plugin: AWS integration
│ │ ├── package.json
│ │ └── index.js
│ └── github/ # Plugin: GitHub integration
│ ├── package.json
│ └── index.js
└── plugin-loader.js # Discovery & loading
Plugin discovery:
- Check
~/.mycli/plugins/ - Check
node_modules/mycli-plugin-* - Check
MYCLI_PLUGIN_PATHenv var
Error Handling Patterns
// Good: Actionable error messages
Error: Config file not found at /path/to/config.yml
Tried locations:
• ./mycli.config.yml
• ~/.myclirc
• /etc/mycli/config.yml
Run 'mycli init' to create a config file, or use --config to specify location.
// Bad: Unhelpful errors
Error: ENOENT
Interactive vs Non-Interactive
// Detect if running in CI/CD
const isCI = process.env.CI === 'true' || !process.stdout.isTTY;
if (isCI) {
// Non-interactive: fail fast with clear errors
if (!options.environment) {
throw new Error('--environment required in non-interactive mode');
}
} else {
// Interactive: prompt user
const environment = await prompt({
type: 'select',
message: 'Select environment:',
choices: ['development', 'staging', 'production'],
});
}
State Management
~/.mycli/
├── config.yml # User configuration
├── cache/ # Cached data
│ ├── plugins.json
│ └── api-responses/
├── credentials.json # Sensitive data (600 perms)
└── state.json # Session state
Performance Patterns
// Lazy loading: Don't load unused dependencies
if (command === 'deploy') {
const deploy = require('./commands/deploy'); // Load on demand
await deploy.run();
}
// Caching: Avoid repeated API calls
const cache = new Cache('~/.mycli/cache', { ttl: 3600 });
let plugins = await cache.get('plugins');
if (!plugins) {
plugins = await fetchPlugins();
await cache.set('plugins', plugins);
}
// Async operations: Don't block unnecessarily
await Promise.all([
validateConfig(),
checkForUpdates(),
loadPlugins(),
]);
Versioning & Updates
// Check for updates (non-blocking)
checkForUpdates().then(update => {
if (update.available) {
console.log(`Update available: ${update.version}`);
console.log(`Run: npm install -g mycli@latest`);
}
}).catch(() => {
// Silently fail - don't interrupt user workflow
});
// Version compatibility
const MIN_NODE_VERSION = '18.0.0';
if (!semver.satisfies(process.version, `>=${MIN_NODE_VERSION}`)) {
console.error(`mycli requires Node.js ${MIN_NODE_VERSION} or higher`);
process.exit(1);
}
Help Text Design
USAGE
mycli deploy [environment] [options]
ARGUMENTS
environment Target environment (development|staging|production)
OPTIONS
-c, --config <file> Path to config file
-f, --force Skip confirmation prompts
-d, --dry-run Preview changes without executing
-v, --verbose Show detailed output
EXAMPLES
# Deploy to production
mycli deploy production
# Preview staging deployment
mycli deploy staging --dry-run
# Use custom config
mycli deploy --config ./custom.yml
Learn more: https://docs.mycli.dev/deploy