urfave/cli
A declarative, simple, fast, and fun package for building command line tools in Go
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6d ago
- ✓21+ active contributors
- ✓Distributed ownership (top contributor 46% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/urfave/cli)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/urfave/cli on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: urfave/cli
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/urfave/cli shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 6d ago
- 21+ active contributors
- Distributed ownership (top contributor 46% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live urfave/cli
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/urfave/cli.
What it runs against: a local clone of urfave/cli — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in urfave/cli | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 36 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of urfave/cli. If you don't
# have one yet, run these first:
#
# git clone https://github.com/urfave/cli.git
# cd cli
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of urfave/cli and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "urfave/cli(\\.git)?\\b" \\
&& ok "origin remote is urfave/cli" \\
|| miss "origin remote is not urfave/cli (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "cli.go" \\
&& ok "cli.go" \\
|| miss "missing critical file: cli.go"
test -f "command.go" \\
&& ok "command.go" \\
|| miss "missing critical file: command.go"
test -f "command_parse.go" \\
&& ok "command_parse.go" \\
|| miss "missing critical file: command_parse.go"
test -f "command_run.go" \\
&& ok "command_run.go" \\
|| miss "missing critical file: command_run.go"
test -f "flag.go" \\
&& ok "flag.go" \\
|| miss "missing critical file: flag.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 36 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~6d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/urfave/cli"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
urfave/cli is a declarative Go package for building command-line applications with zero dependencies beyond the Go standard library. It provides structured command parsing, dynamic shell completion (bash/zsh/fish/powershell), flexible flag handling (including compound short flags like -abc), and automatic help generation—enabling developers to define CLI tools via simple struct definitions rather than manual argument parsing. Single-package architecture: core parsing and execution logic lives in the root directory (cli.go, command.go, args.go, completion.go) with companion files for specific concerns (command_parse.go, command_run.go, command_setup.go). Autocomplete scripts (bash_autocomplete, zsh_autocomplete, etc.) are vendored in autocomplete/. Extensive docs in docs/ directory with versioned migration guides and examples in docs/v1/examples/.
👥Who it's for
Go developers building CLI tools and internal utilities who need a robust, zero-dependency framework for command parsing, subcommands, and shell completion. DevOps engineers, infrastructure tool builders, and open-source maintainers use it to ship professional command-line interfaces without pulling in heavy dependencies.
🌱Maturity & risk
This is a production-ready, actively maintained project. The codebase shows mature CI/CD setup (.github/workflows/test.yml, .github/workflows/lint.yml), versioned migration guides (docs/migrate-v2-to-v3.md), comprehensive test coverage (args_test.go, cli_test.go, command_test.go), and a GitHub-native issue/PR system with templated bug reports for v1/v2/v3. It's stable enough for wide adoption but under active development.
Minimal dependency risk—urfave/cli explicitly avoids external dependencies except Go's stdlib. The project is volunteer-run (see README: 'run by unpaid volunteers'), which could affect maintenance velocity if lead maintainers step back. Breaking changes between major versions (v1→v2, v2→v3) are documented but require user migration. No single-file bottleneck; architecture is modular across command.go, command_parse.go, command_run.go, args.go.
Active areas of work
The project is at v3 with active maintenance. Recent work includes v3-specific bug reports and feature requests (.github/ISSUE_TEMPLATE/v3-*.md), documentation publishing via CI (.github/workflows/publish-docs.yml), and dependent package updates (urfave/cli-altsrc/v3, urfave/cli-docs referenced in README). No specific milestone visible, but the codecov integration and dependabot configuration indicate ongoing quality monitoring.
🚀Get running
git clone https://github.com/urfave/cli.git && cd cli && go mod download. Then run tests with: make test (see Makefile). For the docs subdirectory: cd docs && go mod download && go run ./package.go.
Daily commands: make test runs the test suite. make (alone) likely invokes the default Makefile target—check Makefile for others. To use the package in a Go program: import 'github.com/urfave/cli/v3' and instantiate *cli.App with Commands, Flags, etc., then call app.Run(os.Args).
🗺️Map of the codebase
cli.go— Entry point defining the App struct and Run method—every CLI application starts here.command.go— Core Command struct definition and command-level abstractions that all subcommands inherit.command_parse.go— Argument and flag parsing logic—handles the critical path of converting CLI input into usable data structures.command_run.go— Command execution and action invocation—where user-defined handlers are dispatched.flag.go— Flag type definitions and value parsing for all supported flag types (strings, ints, bools, etc.).completion.go— Shell completion logic for bash/zsh/fish/powershell—enables dynamic CLI introspection.args.go— Argument collection and retrieval utilities—handles positional arguments after flags are parsed.
🧩Components & responsibilities
- App (cli.go) (os.Args, os.Exit(), flag.FlagSet (internally)) — Root entry point; orchestrates command matching, flag resolution, and action dispatch; manages help/version/completion flags.
- Failure mode: If action panics or returns non-ExitCoder error, app exits with code 1 and prints error message.
- Command (command.go, command_parse.go) (strings, slices, flag matching logic) — Represents a CLI command; parses its own flags, matches subcommands, and invokes its action handler with resolved context.
- Failure mode: If subcommand not found or flags invalid, parse returns error and app exits with code 1.
- Flag System (flag.go, context.go)* (strconv, time, type assertions) — Defines typed flags (string, int, bool, duration, etc.); unmarshals raw strings to typed values; provides retrieval via Context getters.
- Failure mode: If string cannot be converted to target type (e.g., 'abc' as int), parsing fails and app exits with code 1.
- Completion (completion.go, autocomplete/) (Bash, Zsh, Fish, PowerShell scripting) — Generates shell-specific completion candidates for bash/zsh/fish/powershell; introspects command tree and flags.
- Failure mode: If completion script not sourced correctly or app not in PATH, no completions are generated; shell degrades gracefully.
- Help & Documentation (help.go, docs.go) — Generates human-readable help text and machine-
🛠️How to make changes
Add a new command with subcommands
- Define a new Command struct in your code with Name, Description, and Action fields (
command.go) - Register subcommands by adding Command structs to the parent command's Subcommands slice (
command.go) - Implement the Action function signature accepting context.Context and *Command, extracting flags via ctx.String(flagName) (
command_run.go)
Add a new flag type
- Create a new file flag_<type>.go following the pattern of flag_string.go or flag_int.go (
flag.go) - Implement the Flag interface: String(), IsSet(), Value(), and type-specific parsing logic (
flag.go) - Register the flag type in any command's Flags slice, and retrieve values in actions via ctx.Float64(flagName) or equivalent (
context.go)
Customize help and completion output
- Override App.HelpFunc or Command.HelpFunc with a custom function signature accepting Writer and any App/Command (
help.go) - For completions, set App.EnableBashCompletion = true and App.BashComplete handler if default behavior needs customization (
completion.go) - Test custom help and completion by calling app.Run(os.Args) and examining generated text (
cli_test.go)
Handle errors and exit codes
- Return errors from your Action functions; they are caught by the command runner (
command_run.go) - For custom exit codes, define an Exit error type in your main or wrap errors in ExitCoder interface (
errors.go) - Set App.ExitErrHandler to customize final exit behavior before the process terminates (
cli.go)
🔧Why these technologies
- Go standard library only — Reduces deployment friction; urfave/cli is embedded in thousands of projects and must have zero runtime dependencies.
- Declarative struct-based configuration — Allows static analysis and introspection for help/completion generation without reflection overhead at runtime.
- Interface-based flag system — Enables extensibility for custom types while keeping core parsing logic simple and testable.
- Context.Context threading — Modern Go idiom for cancellation, timeouts, and passing request-scoped values through the execution chain.
⚖️Trade-offs already made
-
No fluent builder API; flags/commands defined as struct slices instead
- Why: Simplifies static analysis, introspection, and marshaling to documentation formats.
- Consequence: Slightly more verbose initialization but enables completion and help generation without runtime trickery.
-
Eager flag parsing before command dispatch
- Why: Catches invalid flags early and provides unified error messages.
- Consequence: Global flags cannot be defined per-command; they must be hoisted to the App level or duplicated.
-
No built-in config file or environment variable binding in core
- Why: Keeps the library focused; urfave/cli-altsrc module handles structured configs.
- Consequence: Users must manually wire env var lookups or use the altsrc companion library.
🚫Non-goals (don't propose these)
- Does not handle configuration file parsing (delegated to urfave/cli-altsrc).
- Does not provide built-in authentication or authorization.
- Does not manage process lifecycle or daemonization.
- Does not enforce command-line UX standards (e.g., POSIX compliance); users are free to define any interface.
- Does not support interactive/REPL mode—only request/response CLI flow.
🪤Traps & gotchas
No required env vars for basic operation. No external services required. Flag type constraints are Go-version dependent (e.g. time.Duration parsing uses stdlib). Completion scripts are POSIX shell—Windows uses powershell_autocomplete.ps1 separately. The docs/ subdirectory is a separate Go module with its own go.mod, so changes there require separate dependency updates. Command name matching supports prefix matching, which can cause ambiguity if two commands share a prefix—not always obvious from API docs.
🏗️Architecture
💡Concepts to learn
- Declarative Command Definition — urfave/cli inverts the typical imperative arg-parsing approach—you declare Command and Flag structs, then call Run(); this is central to the library's design philosophy and reduces boilerplate.
- Prefix Matching for Commands — The library supports ambiguous prefix matching ('myapp run' matches 'run' even if you only type 'myapp ru')—this is powerful for user ergonomics but can cause confusion; documented in command_parse.go.
- Compound Short Flags — urfave/cli supports -abc as shorthand for -a -b -c, which is common in Unix tools but requires careful parsing logic to avoid conflicts with flag values.
- Dynamic Shell Completion — The library generates completion scripts for bash/zsh/fish/powershell at runtime based on your command structure; completion.go is the engine that reflects your CLI definition into shell autocompletion.
- Flag Slices and Maps — urfave/cli supports not just scalar flags but slices (StringSliceFlag, IntSliceFlag) and maps; this allows --tag foo --tag bar syntax, which requires specialized parsing in args.go.
- Environment Variable Fallback — Flags can read from environment variables as a fallback using EnvVars property; this enables docker-style configuration where flags or env vars both work, reducing user friction.
- Action Chaining and Hooks — Commands support Before, Action, After hooks and context passing via Context type; understanding the execution lifecycle (setup in command_setup.go, parse in command_parse.go, run in command_run.go) is critical for advanced features like global flags.
🔗Related repos
spf13/cobra— Competing CLI framework for Go with more features (nested subcommands, middleware) but heavier than urfave/cli; used when you want code generation and decorators.alecthomas/kong— Lightweight alternative using struct tags for CLI definition; different philosophy but solves the same problem with less verbosity.urfave/cli-altsrc— Official companion package for urfave/cli that adds config file parsing (YAML, TOML, JSON) on top of CLI flags; explicitly required in docs/go.mod.urfave/cli-docs— Official companion package for generating man pages and Markdown documentation from urfave/cli command definitions; mentioned in README as external dependency.hashicorp/cli— HashiCorp's CLI library used in Terraform, Consul, Nomad; older, more opinionated alternative predating modern Go idioms.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive v3 examples documentation matching v1/v2 coverage
The docs/v2/examples directory has 9 markdown files covering various CLI features (arguments, bash-completions, flags, subcommands, etc.), but docs/v3/examples appears to be missing or incomplete. New contributors can port and adapt these examples for v3, ensuring feature parity documentation across all versions. This is critical since v3 is the current version and users migrating need clear examples.
- [ ] Review all files in docs/v2/examples/ to understand covered topics
- [ ] Create docs/v3/examples/ directory structure matching v2
- [ ] Adapt v2 examples to v3 API (reference docs/migrate-v2-to-v3.md)
- [ ] Create missing v3 examples: arguments.md, bash-completions.md, combining-short-options.md, exit-codes.md, flags.md, full-api-example.md, generated-help-text.md, greet.md, subcommands-categories.md, subcommands.md, suggestions.md
- [ ] Test each example code snippet runs without errors
- [ ] Add index or navigation linking to v3 examples from docs/v3/index.md
Add integration tests for v3 shell completion across bash, zsh, fish, and powershell
The repo has autocomplete scripts in autocomplete/ directory (bash_autocomplete, zsh_autocomplete, fish_autocomplete, powershell_autocomplete.ps1) and completion_test.go exists, but there are no dedicated integration tests verifying that completion actually works end-to-end for each shell. A new contributor can create a comprehensive test suite in completion_test.go or a new test file that validates completion output for various CLI scenarios (flags, subcommands, arguments) across all shells.
- [ ] Review existing completion_test.go to understand current test coverage
- [ ] Review completion.go to identify completion-generating functions
- [ ] Create test cases for bash completion with real shell invocations
- [ ] Create test cases for zsh completion with real shell invocations
- [ ] Create test cases for fish completion with real shell invocations
- [ ] Create test cases for powershell completion with real shell invocations
- [ ] Test scenarios: basic flags, subcommands, nested subcommands, argument completion
- [ ] Add new integration test file (e.g., completion_integration_test.go) or extend completion_test.go
Add missing unit tests for command_parse.go and command_setup.go
The repo has command_test.go, command_run_test.go, and command_stop_on_nth_arg_test.go, but there are no dedicated test files for command_parse.go and command_setup.go. These files handle critical parsing and setup logic for commands. A new contributor can create comprehensive unit tests for edge cases in argument parsing, flag parsing, and command initialization that may not be covered by existing command_test.go.
- [ ] Review command_parse.go to identify all exported and internal functions
- [ ] Review command_setup.go to identify all exported and internal functions
- [ ] Create command_parse_test.go with tests for: flag parsing edge cases, argument ordering, error handling
- [ ] Create command_setup_test.go with tests for: command initialization, dependency resolution, error handling
- [ ] Test complex scenarios: conflicting flags, multiple subcommand levels, special characters in args
- [ ] Aim for >90% code coverage for both new test files
- [ ] Verify all tests pass with 'make test' or the test workflow
🌿Good first issues
- Add missing test coverage for command_setup.go—it appears in the file list but has no corresponding *_test.go file visible; writing unit tests for command setup would strengthen test suite.
- Expand examples in docs/v3/examples/ for compound short flags (e.g., -abc syntax)—the README mentions this feature but there's only docs/v1/examples/combining-short-options.md visible; create v3-specific examples.
- Document the prefix-matching behavior for command names in docs/index.md or a new docs/v3/examples/command-matching.md—this is a powerful but non-obvious feature that could confuse users.
⭐Top contributors
Click to expand
Top contributors
- @dearchap — 46 commits
- @TimSoethout — 8 commits
- @dependabot[bot] — 8 commits
- @Juneezee — 7 commits
- @kolyshkin — 5 commits
📝Recent commits
Click to expand
Recent commits
f2cd020— Merge pull request #2319 from barry3406/fix/help-subcommand-flag-parsing (dearchap)5af9500— fix: parse flags for help subcommand (#2271) (barry3406)b79d768— Merge pull request #2316 from morozov/fix-completion-double-dash (dearchap)2925d6f— Merge pull request #2317 from barry3406/fix/completion-shebang (dearchap)65406c0— Merge pull request #2308 from gabelluardo/refactor-bash (dearchap)eb4cfc3— fix: drop shebang from bash completion template (barry3406)bc00bd4— Merge pull request #2311 from alliasgher/fix-boolwithinverse-string-panic (dearchap)efc6352— Merge pull request #2310 from Yanhu007/fix/exit-empty-message (dearchap)afd7b86— Merge pull request #2309 from lawrence3699/fix/slice-separator-env-var (dearchap)f831e58— Merge pull request #2307 from gabelluardo/fix-ci (dearchap)
🔒Security observations
The urfave/cli codebase demonstrates a strong security posture. As a declarative CLI framework with no dependencies in the main library (only standard library), it has minimal attack surface. The identified vulnerabilities are low-severity items related to documentation examples, optional test dependencies, and general best practices for shell script integration. No evidence of hardcoded secrets, SQL injection, XSS vulnerabilities, or critical misconfigurations was found. Recommend regular dependency updates and continued security monitoring of transitive dependencies.
- Low · Outdated Go Version in Documentation —
docs/go.mod. The docs/go.mod file specifies Go 1.23.2, which may become outdated. While this is documentation-only and not the main library, it could lead to users following outdated best practices. Fix: Regularly update the Go version in documentation examples to the latest stable release and consider documenting minimum Go version requirements. - Low · Transitive Dependency: github.com/stretchr/testify —
docs/go.mod (indirect). The testify package is included as an indirect dependency in the documentation module. While testify is widely used and generally safe, it's a non-essential test dependency that increases the attack surface. Fix: Verify that testify is actually needed for the documentation build. If not, consider removing it or ensuring it's only included in dev/test builds. - Low · Potential Command Injection via Shell Completion Scripts —
autocomplete/ directory (bash_autocomplete, zsh_autocomplete, fish_autocomplete, powershell_autocomplete.ps1). The repository includes shell completion scripts (bash, zsh, fish, powershell) in the autocomplete directory. These scripts are executed by shells during command completion and could potentially be vectors for injection attacks if the CLI tool doesn't properly sanitize user input before passing to these completion scripts. Fix: Review shell completion implementations to ensure proper input validation and escaping. Document security best practices for users integrating these completions. Consider using shell-safe parameter passing mechanisms. - Low · Third-party YAML Parser Dependency —
docs/go.mod (indirect: gopkg.in/yaml.v3). The repository depends on gopkg.in/yaml.v3 (indirectly via testify), which parses YAML input. YAML parsers have historically been targets for deserialization attacks. Fix: Monitor for security advisories on gopkg.in/yaml.v3. If the main CLI library accepts YAML input from users, ensure strict parsing modes are enabled and untrusted YAML is not executed.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.