AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Cli Creation

skill-shyamsridhar123-agentsmith-cli-cli-creation · by shyamsridhar123

Build professional command-line interface (CLI) applications following industry best practices. Covers argument parsing, help text, output formatting, error handling, subcommands, configuration, and distribution across multiple languages.

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-shyamsridhar123-agentsmith-cli-cli-creation

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-shyamsridhar123-agentsmith-cli-cli-creation)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Cli Creation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

CLI Creation

Build professional, delightful command-line applications that follow established conventions and modern best practices.

When to Use This Skill

  • Creating new CLI tools or utilities
  • Adding command-line interfaces to existing applications
  • Refactoring CLI programs for better usability
  • User asks to "build a CLI", "create a command-line tool", or "add CLI commands"

Core Philosophy

Human-First Design

Design for humans first, machines second. The CLI is a text-based UI, not just a scripting interface.

Simple Parts That Work Together

Follow UNIX philosophy: small programs with clean interfaces that compose via pipes and standard I/O.

Consistency

Follow existing patterns. Terminal conventions are muscle memory—don't break expectations.

Ease of Discovery

Help users learn. Provide comprehensive help, examples, and suggestions.

Robustness

Handle errors gracefully. Be responsive. Show progress for long operations.


Project Structure

mycli/
├── src/
│   ├── main.{ts,py,go,rs}    # Entry point
│   ├── commands/              # Subcommands
│   │   ├── init.{ts,py,go,rs}
│   │   └── run.{ts,py,go,rs}
│   ├── utils/
│   │   ├── output.{ts,py,go,rs}  # Colors, formatting
│   │   └── config.{ts,py,go,rs}  # Configuration handling
│   └── types.{ts,py,go,rs}
├── tests/
├── README.md
└── package.json / pyproject.toml / go.mod / Cargo.toml

Recommended Libraries

| Language | Library | Notes | |----------|---------|-------| | Node.js | oclif, Commander | oclif for complex CLIs, Commander for simple | | Python | Typer, Click | Typer uses type hints, Click is battle-tested | | Go | Cobra, urfave/cli | Cobra powers kubectl, Hugo, GitHub CLI | | Rust | clap | Derive macros for type-safe parsing | | Deno | parseArgs | Built-in standard library |


Arguments and Flags

Terminology

  • Arguments (args): Positional parameters (cp source dest)
  • Flags: Named parameters (--verbose, -f file.txt)

Best Practices

# Prefer flags over positional args for clarity
mycli --input file.txt --output result.json  # ✅ Clear
mycli file.txt result.json                    # ❌ Ambiguous

# Have full-length versions of all flags
mycli -v          # Short form
mycli --verbose   # Long form (prefer in scripts)

# Use standard flag names
-h, --help       # Help
-v, --version    # Version (or use for verbose, pick one)
-q, --quiet      # Suppress output
-f, --force      # Force operation
-n, --dry-run    # Preview without executing
-o, --output     # Output file/path
--json           # JSON output format
--no-color       # Disable colors

Flag Conventions

// TypeScript with Commander
import { Command } from 'commander';

const program = new Command()
  .name('mycli')
  .description('A delightful CLI tool')
  .version('1.0.0')
  .option('-v, --verbose', 'Enable verbose output')
  .option('-c, --config ', 'Config file path')
  .option('--dry-run', 'Preview changes without applying');
# Python with Typer
import typer

app = typer.Typer()

@app.command()
def main(
    verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose output"),
    config: str = typer.Option(None, "--config", "-c", help="Config file path"),
    dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Preview changes"),
):
    """A delightful CLI tool."""
    pass
// Go with Cobra
var rootCmd = &cobra.Command{
    Use:   "mycli",
    Short: "A delightful CLI tool",
}

func init() {
    rootCmd.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose output")
    rootCmd.PersistentFlags().StringP("config", "c", "", "Config file path")
    rootCmd.Flags().Bool("dry-run", false, "Preview changes")
}

Help Text

Display Help When Asked

Respond to -h, --help, and help subcommand:

$ mycli --help
A delightful CLI tool for managing widgets

Usage: mycli [command] [options]

Commands:
  init        Initialize a new project
  build       Build the project
  deploy      Deploy to production

Options:
  -v, --verbose    Enable verbose output
  -c, --config     Path to config file
  -h, --help       Show this help
  --version        Show version

Examples:
  $ mycli init my-project
  $ mycli build --verbose
  $ mycli deploy --dry-run

Run 'mycli  --help' for more information on a command.

Help Text Principles

  1. Lead with examples - Users learn from examples first
  2. Show common flags first - Most-used options at the top
  3. Be concise by default - Full help on --help, brief on no args
  4. Suggest next steps - Tell users what to run next
  5. Link to documentation - Include URLs to web docs

Output

Human-Readable by Default

# Check if stdout is a TTY
if [ -t 1 ]; then
  # Interactive terminal - use colors, formatting
else
  # Piped/redirected - plain output
fi

Machine-Readable with --json

$ mycli status
✓ Connected to server
✓ 3 widgets deployed
✓ Last sync: 2 minutes ago

$ mycli status --json
{"connected": true, "widgets": 3, "lastSync": "2025-01-24T10:30:00Z"}

Color Guidelines

// Use color with intention
import chalk from 'chalk';

console.log(chalk.green('✓'), 'Success: Widget deployed');
console.log(chalk.yellow('⚠'), 'Warning: Deprecated API');
console.log(chalk.red('✗'), 'Error: Connection failed');

// Respect NO_COLOR environment variable
if (process.env.NO_COLOR || !process.stdout.isTTY) {
  chalk.level = 0;
}

Progress Indicators

from tqdm import tqdm
import time

# Show progress for long operations
for item in tqdm(items, desc="Processing"):
    process(item)

Errors

Write Errors for Humans

# Bad - cryptic error
Error: ENOENT

# Good - helpful error with suggestion
✗ Error: Cannot find config file 'widget.yaml'
  
  The file doesn't exist at the expected location.
  
  To fix this, either:
    • Run 'mycli init' to create a new config
    • Specify a path with --config 

Error Handling Pattern

try {
  await deploy();
} catch (error) {
  if (error.code === 'ENOENT') {
    console.error(chalk.red('✗'), `File not found: ${error.path}`);
    console.error('\n  Run "mycli init" to create the required files.\n');
    process.exit(1);
  }
  
  if (error.code === 'ECONNREFUSED') {
    console.error(chalk.red('✗'), 'Cannot connect to server');
    console.error(`\n  Check that the server is running at ${serverUrl}\n`);
    process.exit(1);
  }
  
  // Unexpected error - show debug info
  console.error(chalk.red('✗'), 'Unexpected error:', error.message);
  console.error('\n  Please report this issue:');
  console.error('  https://github.com/org/mycli/issues\n');
  if (process.env.DEBUG) {
    console.error(error.stack);
  }
  process.exit(1);
}

Subcommands

Git-Style Subcommands

mycli  [subcommand] [options]

# Examples
mycli config get theme
mycli config set theme dark
mycli widget list
mycli widget create --name "My Widget"

Subcommand Consistency

// Be consistent: noun-verb or verb-noun across all commands
// Noun-verb (recommended for complex CLIs)
mycli config get
mycli config set
mycli widget list
mycli widget create

// Verb-noun
mycli get config
mycli list widgets

Configuration

Configuration Precedence (highest to lowest)

  1. Command-line flags
  2. Environment variables
  3. Project-level config (.myclirc, mycli.config.js)
  4. User-level config (~/.config/mycli/config.yaml)
  5. System-wide config (/etc/mycli/config.yaml)

XDG Base Directory Spec

import os from 'os';
import path from 'path';

const configDir = process.env.XDG_CONFIG_HOME 
  || path.join(os.homedir(), '.config');
const configPath = path.join(configDir, 'mycli', 'config.yaml');

Environment Variables

# Use MYCLI_ prefix for your app's env vars
MYCLI_API_KEY=xxx
MYCLI_DEBUG=1
MYCLI_NO_COLOR=1

# Check standard env vars
NO_COLOR          # Disable colors
DEBUG             # Enable debug output
EDITOR            # User's preferred editor

Interactivity

Only Prompt in TTY

import { stdin, stdout } from 'process';

if (stdin.isTTY && stdout.isTTY) {
  // Interactive mode - can prompt
  const answer = await prompt('Continue? [y/N]');
} else {
  // Non-interactive (script/pipe) - require flags
  if (!options.force) {
    console.error('Use --force to confirm in non-interactive mode');
    process.exit(1);
  }
}

Confirm Dangerous Operations

// Mild danger: simple confirmation
const confirm = await prompt('Delete file.txt? [y/N]');

// Moderate danger: require explicit yes
const confirm = await prompt('Delete 47 files? Type "yes" to confirm:');
if (confirm !== 'yes') process.exit(1);

// Severe danger: type the resource name
const confirm = await prompt('Delete production database? Type "prod-db" to confirm:');
if (confirm !== 'prod-db') process.exit(1);

// Always allow --force for scripting
if (options.force) {
  // Skip confirmation
}

Signals and Exit Codes

Exit Codes

process.exit(0);  // Success
process.exit(1);  // General error
process.exit(2);  // Misuse of command (bad args)

Handle Ctrl-C Gracefully

process.on('SIGINT', async () => {
  console.log('\n\nInterrupted. Cleaning up...');
  await cleanup();
  process.exit(130);  // 128 + signal number
});

// For long cleanup, allow second Ctrl-C to force quit
let interrupted = false;
process.on('SIGINT', () => {
  if (interrupted) {
    console.log('\nForce quitting...');
    process.exit(1);
  }
  interrupted = true;
  console.log('\nGracefully stopping... (press Ctrl+C again to force)');
  gracefulShutdown();
});

Distribution

Single Binary is Best

  • Go: Compiles to single binary by default
  • Rust: Compiles to single binary by default
  • Node.js: Use pkg or nexe
  • Python: Use PyInstaller or shiv

Package Managers

# npm (Node.js)
npm install -g mycli

# Homebrew (macOS/Linux)
brew install mycli

# pip (Python)
pip install mycli

# Go
go install github.com/org/mycli@latest

Make Uninstall Easy

Document how to remove your tool at the bottom of install instructions.


Checklist

Essential (Must Have)

  • [ ] Use argument parsing library (don't roll your own)
  • [ ] Return exit code 0 on success, non-zero on failure
  • [ ] Send output to stdout, errors/logs to stderr
  • [ ] Support -h and --help flags
  • [ ] Support --version flag
  • [ ] Handle Ctrl-C gracefully

Recommended (Should Have)

  • [ ] Provide examples in help text
  • [ ] Use colors (respect NO_COLOR)
  • [ ] Show progress for long operations
  • [ ] Support --json for machine-readable output
  • [ ] Support --quiet to suppress non-essential output
  • [ ] Validate input early with helpful errors
  • [ ] Suggest corrections for typos

Nice to Have

  • [ ] Shell completions (bash, zsh, fish)
  • [ ] Man pages
  • [ ] Configuration file support
  • [ ] Auto-update mechanism
  • [ ] Telemetry (opt-in only!)

Anti-Patterns to Avoid

# ❌ Don't require specific argument order for flags
mycli --flag subcommand    # This should work
mycli subcommand --flag    # This should also work

# ❌ Don't hide errors in silent failure
mycli dostuff              # *hangs forever with no output*

# ❌ Don't use ambiguous subcommands
mycli update               # Update what?
mycli upgrade              # How is this different?

# ❌ Don't break existing interfaces without warning
mycli --old-flag           # Deprecation warning first, then remove

# ❌ Don't read secrets from command line flags
mycli --password=secret    # Visible in ps, shell history

# ✅ Do read secrets from files or stdin
mycli --password-file=/path/to/secret
echo "secret" | mycli --password-stdin

Resources

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.