Mitchell Hashimoto — CLI & Infrastructure Mastery
Write CLI tools and infrastructure software in the style of Mitchell Hashimoto, founder of HashiCorp (Vagrant, Packer, Terraform, Consul, Vault, Nomad) and creator of Ghostty.
Core Philosophy
1. Human-Friendly by Default, Machine-Parseable by Flag
code
# Default: human-readable
$ corey status
✓ GitHub CLI: authenticated as @user
✓ Git config: user.email configured
✗ SSH agent: no keys loaded
# Machine: structured output
$ corey status --json
{"github_cli":{"status":"ok","user":"user"},"git_config":{"status":"ok"},"ssh_agent":{"status":"error","message":"no keys loaded"}}
2. Progressive Disclosure
- •Simple commands do simple things
- •Advanced behavior via explicit flags
- •Never surprise the user with implicit actions
3. Composable Unix Tools
- •Single responsibility per command
- •Stdin/stdout for pipelines
- •Exit codes are contracts (0=success, 1=user error, 2=system error)
CLI Design Principles
Command Structure
code
<tool> <noun> <verb> [flags] [args] corey credential list corey credential get github.com corey credential set github.com --from-gh corey sync pull --source=gh corey sync push --target=git-credential
Flag Conventions
- •
--json— machine-readable output - •
--porcelain— stable output for scripts - •
--verbose/-v— show what's happening - •
--dry-run— preview without modification - •
--force— skip confirmations (dangerous) - •
--quiet/-q— suppress non-error output
Error Messages
code
Error: GitHub CLI not authenticated
The `gh` CLI is installed but not logged in.
To fix this, run:
gh auth login
Or use a different credential source:
corey sync pull --source=git-credential
Always provide:
- •What went wrong
- •Why it matters
- •How to fix it
Secrets Management (Vault-Inspired)
Never Store Secrets in Plain Text
- •Use OS keychain (libsecret on Linux, Keychain on macOS)
- •Encrypt at rest with user-derived key
- •Memory-safe handling (zero on drop)
Audit Trail
- •Log credential access (not values)
- •Support
--audit-logfor compliance
Principle of Least Privilege
- •Request only needed scopes
- •Support credential expiry
- •Rotate on schedule
Configuration Philosophy
Layered Configuration
code
1. CLI flags (highest priority) 2. Environment variables 3. Local config (.corey/config.toml) 4. User config (~/.config/corey/config.toml) 5. System config (/etc/corey/config.toml) 6. Compiled defaults (lowest priority)
Config File Format
toml
# Prefer TOML: readable, typed, no footguns [defaults] output = "human" # or "json" color = "auto" # or "always", "never" [sources.github] priority = 1 enabled = true [targets.git-credential] enabled = true
Implementation Patterns
Subcommand Dispatch
zig
const commands = .{
.{ "credential", @import("cmd/credential.zig") },
.{ "sync", @import("cmd/sync.zig") },
.{ "status", @import("cmd/status.zig") },
.{ "config", @import("cmd/config.zig") },
};
pub fn main() !void {
const args = try std.process.argsAlloc(allocator);
if (args.len < 2) return showHelp();
inline for (commands) |cmd| {
if (std.mem.eql(u8, args[1], cmd[0])) {
return cmd[1].run(args[2..]);
}
}
return error.UnknownCommand;
}
Graceful Degradation
zig
fn getCredential(host: []const u8) !Credential {
// Try sources in priority order
if (tryGitHubCLI(host)) |cred| return cred;
if (tryGitCredential(host)) |cred| return cred;
if (tryKeychain(host)) |cred| return cred;
return error.NoCredentialFound;
}
Testing Philosophy
Test the Interface, Not Implementation
- •Run CLI as subprocess
- •Verify stdout, stderr, exit code
- •Test with real (mock) credentials
Golden File Tests
code
tests/
golden/
status_ok.stdout
status_ok.stderr
status_ok.exitcode
When to Apply This Skill
- •Designing CLI argument parsing
- •Structuring subcommands
- •Handling credentials and secrets
- •Writing configuration systems
- •Creating human-friendly error messages
- •Building for both humans and scripts