spf13/cobra
github.com/spf13/cobra ↗ · 65 files · 617 KB
Cobra is a library for creating powerful modern CLI applications.
Overview
Cobra is a Go library for developers building command-line applications with nested commands, POSIX-style flags, validation, lifecycle hooks, and generated help. A shared Command tree drives execution, completion for four shells, and reference documentation in Markdown, man, ReST, and YAML formats. This brief examines commit adbc8813901bba65827259daa8e22ff94ec1f30e through public-source reads; tests and CI were inspected, not executed.
System map
The runtime is a library embedded in a consuming application's executable. Command owns the tree, flags, callbacks, context, and streams; separate generators consume that model. Persistent artifacts are explicitly generated files, while execution state lives in memory. Repository automation supplies testing, linting, license checking, dependency updates, and PR labeling.
- The public application entrypoints are Command.Execute, ExecuteC, ExecuteContext, and ExecuteContextC; the user guide places the application's main function outside the library.
- Command combines command metadata, argument validation, lifecycle callbacks, pflag sets, parent/child links, context, and configurable IO streams.
- go.mod declares github.com/spf13/cobra with Go 1.15 and dependencies on pflag, mousetrap, go-md2man/v2, and YAML v3.
- The doc package renders the Command model through writer APIs and directory-based tree generators; Markdown uses os.Create, man uses md2man.Render, and YAML uses yaml.Marshal.
- Platform build tags select an unset pre-execution hook on non-Windows and an Explorer-launch detection hook using mousetrap on Windows.
- Makefile exposes formatting, lint, go test, and richgo test targets; both test targets depend on install_deps, which runs go get -v ./....
- Test CI defines license and lint jobs, Ubuntu/macOS matrices for Go 1.17–1.24, and a Windows MSYS2 job; Unix and Windows jobs invoke make richtest.
- PR labeling runs actions/labeler on pull_request_target with PR-write permission, while Dependabot schedules weekly Go-module and GitHub Actions updates.
Feature catalog
Cobra exposes developer APIs that become end-user CLI behavior. Its features cover command resolution, flag and argument handling, help, validation, lifecycle callbacks, and shell assistance. The same command descriptions can produce distributable reference documentation. Most behavior is configurable through Command fields or registration methods.
- Nested commands resolve by name or alias; optional prefix matching accepts a unique match, and failed lookup can produce distance-based suggestions.
- Local and persistent flags use pflag; persistent flags merge into descendants, and TraverseChildren additionally parses parent flags while walking the command path.
- Positional validation includes NoArgs, OnlyValidArgs, NoDuplicateArgs, minimum/maximum/exact/range counts, and MatchAll composition.
- Required flags and required-together, one-required, and mutually-exclusive groups produce execution errors; group marking annotates existing flags.
- Automatic help provides a help command and -h/--help flag; a nonempty Version enables --version and adds -v only when that shorthand is free.
- Applications can define persistent/local pre- and post-hooks plus Run or RunE, use command deprecation messages, and silence default error or usage output.
- The default completion command generates Bash V2, Zsh, Fish, and PowerShell scripts, with configurable descriptions; callbacks can return descriptive choices, file filters, and Active Help.
- Reference generation supports Markdown, man, ReST, and YAML; custom link/prepend handlers and man headers tailor generated output.
Data flow
Execution starts with an argument slice and a caller-built command graph. Resolution selects a stateful Command, pflag separates flags from positional arguments, and validators gate its action. Completion exchanges a textual protocol with a separate shell process. Documentation and completion-file APIs form the explicit filesystem output boundary.
- ExecuteC selects c.args when supplied; otherwise it reads os.Args[1:], except for the cobra.test executable-name guard.
- Find strips flags to identify successive subcommands while preserving remaining input for execution; with nil Args it applies legacyArgs, whose root/subcommand rules differ.
- ParseFlags merges local persistent and ancestor flag sets, transfers FParseErrWhitelist into pflag's allowlist, parses input, and emits buffered warnings only when parsing succeeds.
- The action receives pflag's remaining arguments, or the untouched argument slice under DisableFlagParsing; positional validation runs before pre-hooks, while required/group validation runs after them.
- Output, error, and input stream lookup walks parent commands before falling back to stdout, stderr, or stdin, allowing root-level stream injection to serve descendants.
- getCompletions extracts the incomplete final token, copies preceding tokens, resolves the target, propagates context, and parses flags before choosing completion results.
- Completion responses filter disabled Active Help, optionally remove tab-delimited descriptions, truncate embedded newlines, trim choices, and append :<directive>; diagnostics use the error stream.
- Markdown tree generation maps CommandPath spaces to underscores, joins the basename to a supplied directory, creates the file, writes a custom prefix, and streams rendered command metadata into it.
Behavior traces
Three concrete flows were followed through source: normal command execution, dynamic shell completion, and documentation persistence. Help and script generation provide additional branches through the same command tree. The traces describe source execution order rather than observed runtime results. Early returns and option-dependent branches materially change which callbacks run.
- Startup: Execute → ExecuteC supplies context, redirects to Root when necessary, invokes preExecHookFn, initializes help and completion commands, checks groups, then selects Find or Traverse.
- Primary action: cmd.execute initializes help/version flags → ParseFlags → preRun → deferred postRun → ValidateArgs → persistent/local pre-hooks → required/group validation → RunE or Run → local/persistent post-hooks.
- Execution exits early for parsing errors, help, version, or a non-runnable command; after execute returns ErrHelp, ExecuteC calls HelpFunc and returns nil error.
- Named help: the generated help command calls Root.Find → initializes the target's help/version flags → Help; an unknown topic prints a message and routes through Root.Usage and CheckErr.
- Dynamic completion starts when a generated Bash V2 function evaluates a request to __complete or __completeNoDesc; initCompleteCmd creates the hidden, flag-parsing-disabled command only for an actual completion invocation.
- Completion resolution runs getCompletions → Find/Traverse → checkIfFlagCompletion → ParseFlags → help/version suppression → annotation/static/callback selection; it does not call the target command's execute method.
- Script generation: completion bash dispatches its RunE to Root.GenBashCompletionV2 → genBashCompletion → genBashComp, buffers the script, and writes it to the configured output.
- Persistence: GenMarkdownTree → GenMarkdownTreeCustom recursively processes available descendants → os.Create → filePrepender → GenMarkdownCustom → printOptions → buffer.WriteTo, returning on the first encountered error.
Testing signals
Tests and CI were inspected, not executed; their existence establishes intended checks, not passing results. The inspected suite uses Go's testing package and exercises execution, completion, validation, and generated documentation. Some checks invoke external tools or depend on tool availability. This is a bounded inventory, not an exhaustive coverage assessment or vulnerability verification.
- Root-level tests use testing.T and shared executeCommand helpers that inject arguments and capture both output streams in a bytes.Buffer before calling ExecuteC.
- TestHooks verifies arguments delivered to every lifecycle stage; TestPersistentHooks asserts different ordered hook lists with EnableTraverseRunHooks enabled and disabled.
- TestValidateFlagGroups uses table-driven cases for required-together, one-required, exclusive, overlapping, and persistent flag groups, including deterministic error ordering.
- TestFlagCompletionConcurrentRegistration registers 50 callbacks across goroutines and checks completion responses for the first six flags; TestCompletionDoesNotMutateOsArgs checks the shared-slice regression with TraverseChildren.
- TestActiveHelpAlone checks exact protocol output for both root and child completion callbacks, including the marker, directive, and diagnostic line.
- Documentation tests inspect descriptions, examples, inherited/hidden flags, and generation tags; filesystem tests check do.md and do.2, and the man-tree test verifies its caller header remains unchanged.
- Inspected Bash tests use generated-text assertions and conditionally run shellcheck only when found; a separate dead-code test writes a fixture, runs go build and go tool nm, and skips Windows.
- CI definitions run make richtest on Unix and Windows, use external linking for macOS Go versions below 1.24, and configure linting including gosec; the inspected commands do not explicitly add race or coverage flags.
Risk map
These findings are source observations and explicitly labeled hypotheses, not confirmed vulnerabilities. Sensitive boundaries include evaluated shell requests, caller-selected file destinations, environment-controlled logging, and process termination. Mutable command and global state also couples otherwise separate uses of the library. Actual exploitability and downstream application security were not tested.
- Generated Bash requests use eval, PowerShell uses Invoke-Expression, and Fish escapes arguments before eval; hypothesis: quoting regressions at these boundaries could reinterpret shell input and need shell-specific reproduction. (inferred)
- CompDebug accepts BASH_COMP_DEBUG_FILE as an unrestricted destination and opens it with append/create/write flags and mode 0644; open failures are ignored, while write errors flow through CheckErr.
- Documentation and completion-file APIs use os.Create on caller-selected paths, which permits overwriting existing files; tree generation can leave earlier descendant files written when a later step fails.
- Normal pre-hooks run before required-flag and flag-group validation; RunE errors bypass command post-hooks, whereas deferred global finalizers are already installed after preRun.
- Template functions, initializer/finalizer lists, and execution switches are package-global mutable state without synchronization in their setters; completion callback registration separately uses an RWMutex.
- Legacy Bash generation iterates the global callback registry and rewrites each registered flag's BashCompCustom annotation using the current command's root name, including flags outside that command tree.
- Completion group enforcement mutates required annotations and Hidden flags; YAML genFlagResult visits all flags without the hidden/deprecated filtering implemented by manPrintFlags.
- Malformed custom templates can panic through template.Must, missing group IDs panic during ExecuteC, and YAML marshal failure or CheckErr can terminate the embedding process.
Extension points
Extension uses ordinary Go values, callbacks, and metadata rather than requiring a special constructor. Command composition defines new actions and hierarchies. Registration APIs customize completion, validation, templates, lifecycle behavior, and generated documentation. Compatibility APIs include both supported extension surfaces and explicitly disabled legacy methods.
- Applications instantiate Command directly and register children through AddCommand, which assigns parents, propagates normalization, and invalidates command sorting.
- Run/RunE and persistent/local pre/post callback fields provide action and lifecycle extension points; error-returning variants take precedence when both forms are defined.
- PositionalArgs is a function type; MatchAll builds a validator that runs supplied validators in order and returns the first error.
- RegisterFlagCompletionFunc keys callbacks by the resolved pflag.Flag pointer, rejects missing or already-registered flags, and complements command-level ValidArgsFunction.
- Flag annotations plug into required-flag, filename, directory, and legacy Bash custom completion behavior; portable Go callbacks are recommended over MarkFlagCustom.
- SetHelpFunc, SetUsageFunc, template setters, and AddTemplateFunc customize inherited help/usage behavior and template function lookup.
- CommandDisplayNameAnnotation adapts displayed identity for external plugins such as kubectl-myplugin presented as kubectl myplugin; DisplayName reads this metadata.
- Documentation custom APIs accept link handlers and file prependers; GenManTreeOptions adds output path and command separator, while GenManHeader supplies title, section, date, source, and manual.
Contributor handoff
Start by identifying whether a change affects resolution, parsing, lifecycle, completion protocol, or document rendering. Read its implementation and nearby tests together, because command state and generated output are coupled. Preserve compatibility branches and use existing test helpers for focused changes. Tests and CI were inspected, not executed here; proposed checks require separate execution authorization under the task's restrictions.
- Use the README and user guide to distinguish this library from the separately installed cobra-cli generator; consuming applications construct their own root Command and main function.
- Read ExecuteC, execute, Find/Traverse, and ParseFlags together before changing dispatch; TraverseChildren changes parent parsing, and nil Args invokes legacy lookup validation.
- Preserve Go 1.15 compatibility and dual platform build tags; lint explicitly disables govet's buildtag check for that compatibility requirement.
- Use executeCommand/executeCommandC to inject arguments and capture streams; tests manipulating global hook behavior should account for EnableTraverseRunHooks affecting other command trees.
- For completion edits, preserve the copied input slice, static ValidArgs precedence, final :<directive> protocol line, and the regression that verifies os.Args remains unchanged.
- Avoid treating rendering as pure observation: Markdown initializes help and redirects flag output, while legacy Bash sorts argument/alias slices and changes completion annotations.
- Recommended implementation validation is a focused Go test followed by go test ./... and applicable formatting/lint checks; make test and make richtest first invoke go get, so they cross a dependency-download boundary.
- Tests and CI were inspected, not executed in this investigation: conditional shellcheck and Windows-skipped dead-code checks limit what suite definitions establish, and CI runs richgo without explicit race/coverage options.
Languages
| Language | Files | Share of source |
|---|---|---|
| Go | 36 | 100% |
| Markdown | 17 | docs/config |
| YAML | 5 | docs/config |
Start reading here
Probable source entrypoint: go.mod — inferred from the directory tree and manifest, not the upstream docs.
Source roots
site/ (13 files)
Source layout — site/
| Path | Files |
|---|---|
site/content/ | 13 |
Repository structure
| Top-level path | Files |
|---|---|
site/ | 13 |
doc/ | 11 |
.github/ | 4 |
Docs found: CONTRIBUTING.mdREADME.md
Package
go.mod — github.com/spf13/cobra, 0 declared dependencies.
CI & config entrypoints
README.md— Repository readme.github/workflows/labeler.yml— GitHub Actions workflow.github/workflows/test.yml— GitHub Actions workflow
Structural health signals
Average score 8/10 across 36 analyzed source files; 8 hotspots surfaced.
command.go— 1700 lines, score 5.5 (Large file, Long function/block)bash_completions.go— 709 lines, score 5.5 (Large file, Deep nesting)bash_completionsV2.go— 484 lines, score 5.5 (Large file, Deep nesting)
These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.
Recent history
adbc8813901b2026-07-11 — fix: resolve macOS test link failure and update lint rules (#2429)ad460ea8f2492026-04-25 — Add cobra unique args validator (#2397)746ef07158722026-04-24 — fix: prevent completions from mutating os.Args via append side effect (#2356)f2878bab8c962026-04-15 — Ignore the linter error (#2390)85c12c2201a72026-04-16 — projects_using_cobra: add Ollama (#2389)