Skip to content

Commit 61713ce

Browse files
committed
add skill for cobra cli
Signed-off-by: samzong <samzong.lu@gmail.com>
1 parent ec1111f commit 61713ce

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

skills/cobra-cli-dev/SKILL.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
name: cobra-cli-dev
3+
description: Develop and review Cobra CLI commands for Go projects. Use when creating new commands, reviewing CLI code, adding flags, implementing shell completions, or debugging command behavior.
4+
---
5+
6+
# Cobra CLI Development Standards
7+
8+
First-principles CLI architecture for production-grade open source projects.
9+
10+
## Core Philosophy
11+
12+
| Principle | Meaning | Validation Question |
13+
|-----------|---------|---------------------|
14+
| **Consistency** | All commands follow the same pattern | Can users guess usage intuitively? |
15+
| **Predictability** | Same input produces same output | Can scripts call it reliably? |
16+
| **Composability** | Output can feed into other commands | Can it be piped? |
17+
| **Least Surprise** | Behavior matches expectations | Any "magic" behavior? |
18+
| **Graceful Degradation** | Errors provide useful information | Does the user know how to fix it? |
19+
20+
## Three-Layer Architecture
21+
22+
```
23+
Layer 1: Command (cmd/*.go) - cobra.Command + Flag binding + Args validation
24+
Layer 2: Runner Function - Build Options from flags → Call Layer 3 → Format output
25+
Layer 3: Business Logic (internal/*) - No CLI dependencies, testable, returns structured data
26+
```
27+
28+
**Principle**: One file = one command group. Split files when subcommands > 3.
29+
30+
## Command Definition Template
31+
32+
```go
33+
var exampleCmd = &cobra.Command{
34+
Use: "example <required-arg> [optional-arg]",
35+
Short: "One-line description (< 50 chars)",
36+
Long: `Full description including functionality, use cases, and notes.`,
37+
Example: ` gmc example foo
38+
gmc example foo --verbose`,
39+
Args: cobra.ExactArgs(1),
40+
SilenceUsage: true,
41+
SilenceErrors: false,
42+
RunE: runExample,
43+
}
44+
```
45+
46+
## Flag Standards
47+
48+
**Naming**: Use hyphens for long names `--dry-run`, single letter for short `-n`. No camelCase or underscores.
49+
50+
**Type Selection**:
51+
```go
52+
BoolVarP(&dryRun, "dry-run", "n", false, "Preview without executing")
53+
StringVarP(&output, "output", "o", "", "Output file path")
54+
StringSliceVarP(&tags, "tag", "t", nil, "Add tags (can be repeated)")
55+
```
56+
57+
**Relationship Constraints**:
58+
```go
59+
cmd.MarkFlagsMutuallyExclusive("json", "yaml") // Mutually exclusive
60+
cmd.MarkFlagsRequiredTogether("user", "pass") // Must be used together
61+
cmd.MarkFlagsOneRequired("stdin", "file") // At least one required
62+
```
63+
64+
## Output Stream Separation
65+
66+
```go
67+
// stdout: Primary data (pipeable)
68+
fmt.Fprintln(cmd.OutOrStdout(), result)
69+
70+
// stderr: Progress, hints, errors
71+
fmt.Fprintln(cmd.ErrOrStderr(), "Processing...")
72+
73+
// Forbidden: fmt.Println() / os.Stdout.Write()
74+
```
75+
76+
## Error Handling
77+
78+
```go
79+
// User error: Include hints
80+
type UserError struct {
81+
Message string
82+
Hint string
83+
}
84+
85+
// System error: Wrap with context
86+
return fmt.Errorf("failed to process %q: %w", args[0], err)
87+
88+
// main.go unified handling
89+
if err := cmd.Execute(); err != nil {
90+
fmt.Fprintf(os.Stderr, "gmc: %v\n", err)
91+
os.Exit(1)
92+
}
93+
```
94+
95+
## Testing Pattern
96+
97+
```go
98+
func TestExampleCommand(t *testing.T) {
99+
cmd := NewRootCmd() // Factory function, avoid global state
100+
outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
101+
cmd.SetOut(outBuf)
102+
cmd.SetErr(errBuf)
103+
cmd.SetArgs([]string{"example", "foo"})
104+
err := cmd.Execute()
105+
// Assert...
106+
}
107+
```
108+
109+
## Shell Completion
110+
111+
```go
112+
// Static completion
113+
ValidArgs: []string{"json", "yaml", "table"}
114+
115+
// Dynamic completion
116+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
117+
return getBranches(toComplete), cobra.ShellCompDirectiveNoFileComp
118+
}
119+
120+
// Flag completion
121+
cmd.RegisterFlagCompletionFunc("output", ...)
122+
cmd.MarkFlagFilename("config", "yaml", "yml")
123+
```
124+
125+
## Code Review Checklist
126+
127+
- [ ] Use follows POSIX syntax: `command <required> [optional]`
128+
- [ ] Short < 50 characters
129+
- [ ] Example field present
130+
- [ ] Uses RunE instead of Run
131+
- [ ] Args validator correctly set
132+
- [ ] Flags use hyphen-case naming
133+
- [ ] Output uses cmd.OutOrStdout()
134+
- [ ] Errors use cmd.ErrOrStderr()
135+
- [ ] Test cases exist
136+
- [ ] Shell completion configured
137+
138+
## Common Anti-Patterns
139+
140+
| BAD | GOOD |
141+
|-----|------|
142+
| `fmt.Println(...)` | `fmt.Fprintln(cmd.OutOrStdout(), ...)` |
143+
| `Run: func(...)` | `RunE: func(...) error` |
144+
| `var globalFlag bool` | Closure capture or factory function |
145+
146+
## References
147+
148+
- [Cobra Official Documentation](https://cobra.dev)
149+
- [Cobra GitHub Repository](https://github.com/spf13/cobra)
150+
- [12 Factor CLI Apps](https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46)
151+
- [Command Line Interface Guidelines](https://clig.dev)

0 commit comments

Comments
 (0)