CLI Design
Design patterns and conventions for the vm0 CLI user experience
SKILL.md
Full skill instructions
CLI Design Skill
This skill defines the design patterns and conventions for the vm0 CLI. These patterns ensure a consistent, professional user experience across all commands.
When to Use This Skill
Use this skill when:
- Writing new CLI commands
- Reviewing CLI code in pull requests
- Fixing inconsistencies in existing commands
- Understanding CLI output conventions
Quick Reference
Symbols
| Symbol | Color | Usage |
|---|---|---|
✓ | chalk.green | Success, completion |
✗ | chalk.red | Error, failure |
⚠ | chalk.yellow | Warning, deprecation |
▶ | chalk.bold | Operation started |
Colors
| Color | Usage | Example |
|---|---|---|
chalk.red() | Errors | ✗ Not authenticated |
chalk.green() | Success | ✓ Created successfully |
chalk.yellow() | Warnings | ⚠ Field deprecated |
chalk.cyan() | Commands, code | vm0 auth login |
chalk.dim() | Secondary info | Timestamps, hints |
chalk.bold() | Headers | ▶ Run started |
Message Patterns
// Success
console.log(chalk.green(`✓ Created: ${name}`));
// Error
console.error(chalk.red(`✗ Not found: ${name}`));
console.error(chalk.dim(" Run: vm0 auth login"));
// Warning
console.log(chalk.yellow(`⚠ Field deprecated`));
// Empty state
console.log(chalk.dim("No items found"));
// Commands/code examples
console.log(chalk.cyan(" vm0 compose <file>"));
The Five Rules
1. Use Unicode Symbols, Not ASCII
// ✅ Correct
console.error(chalk.red("✗ Failed"));
console.log(chalk.green("✓ Success"));
// ❌ Wrong
console.error(chalk.red("x Failed"));
console.error(chalk.red("Error: Failed"));
2. Two-Space Indentation for Details
console.error(chalk.red("✗ Operation failed"));
console.error(chalk.dim(" Details here")); // 2 spaces
console.error(chalk.dim(" Run: vm0 help")); // 2 spaces
3. No Periods in Messages
// ✅ Correct
console.log(chalk.dim("No items found"));
console.log(chalk.dim("Cancelled"));
// ❌ Wrong
console.log(chalk.dim("No items found."));
console.log(chalk.dim("Cancelled."));
4. Use Shared Utilities
// ✅ Correct - use shared utilities
import { formatBytes } from "../../lib/utils/file-utils";
import { promptConfirm } from "../../lib/utils/prompt-utils";
// ❌ Wrong - local implementations
function formatBytes(bytes: number) { ... } // Duplicate!
5. Check Interactive Mode
import { isInteractive, promptText } from "../../lib/utils/prompt-utils";
if (options.name) {
name = options.name;
} else if (!isInteractive()) {
console.error(chalk.red("✗ --name required in non-interactive mode"));
process.exit(1);
} else {
name = await promptText("Enter name");
}
Detailed Guidelines
For comprehensive patterns and examples:
- Colors & Symbols → Read
colors.md - Output Formatting → Read
output.md - Interactive Prompts → Read
prompts.md - Error Handling → Read
errors.md - Tables → Read
tables.md
Common Violations
Wrong Error Symbol
// ❌ Wrong (lowercase x)
console.error(chalk.red("x Invalid input"));
console.error(chalk.red("Error: Invalid input"));
// ✅ Correct (Unicode ✗)
console.error(chalk.red("✗ Invalid input"));
Wrong Success Format
// ❌ Wrong
console.log(chalk.green("Done Created item"));
// ✅ Correct
console.log(chalk.green("✓ Created item"));
Custom Confirmation
// ❌ Wrong - custom readline
const rl = readline.createInterface({ ... });
rl.question("Confirm? (y/N)", (answer) => { ... });
// ✅ Correct - use shared utility
import { promptConfirm } from "../../lib/utils/prompt-utils";
const confirmed = await promptConfirm("Confirm?");
Duplicate Utilities
// ❌ Wrong - local formatBytes
function formatBytes(bytes: number): string {
// ... implementation
}
// ✅ Correct - import shared
import { formatBytes } from "../../lib/utils/file-utils";
File Locations
Shared Utilities
lib/utils/prompt-utils.ts- Interactive promptslib/utils/file-utils.ts- formatBytes, formatRelativeTimelib/events/event-renderer.ts- Run event rendering
Example Commands
commands/agent/list.ts- Table outputcommands/init.ts- Interactive promptscommands/compose.ts- Complex workflowcommands/credential/set.ts- Error handling
