Summary
Add two small convenience methods to *cli.Command that several third-party extensions reimplement today:
// Walk visits cmd and every descendant in pre-order. Returning a non-nil
// error from fn short-circuits the walk and is returned to the caller.
func (cmd *Command) Walk(fn func(*Command) error) error
// Path returns the path of command names from the root to cmd, inclusive.
// Each element is a Command.Name. Useful for tools that need to manipulate
// the segments (dot-joined for tool names, slash-joined for URLs, etc).
// FullName(), which already exists, is equivalent to strings.Join(cmd.Path(), " ").
func (cmd *Command) Path() []string
Motivation
I maintain a family of small urfave/cli extensions where each repo independently reimplements both of these:
- cli-mcp — projects a command tree as an MCP server.
registerTree is a hand-rolled walker; tool names are dot-joined paths.
- cli-web-docs — emits static HTML docs.
buildNavList and renderPerPage each walk the tree; nav slugs use dash-joined paths.
- cli-web-ops — mobile-first MCP-client web UI. Walks an MCP tool surface, but the underlying motivation is the same.
The pattern across all three is:
var walk func(prefix []string, cmd *cli.Command)
walk = func(prefix []string, cmd *cli.Command) {
if cmd.Hidden { return }
path := append(prefix, cmd.Name)
// ... do per-command work using `path` ...
for _, sub := range cmd.Commands {
walk(path, sub)
}
}
walk(nil, root)
Three flavors of the same thing. Walk removes the recursion boilerplate; Path() removes the manual append(prefix, cmd.Name) accumulation. Both are non-breaking additions.
Alternatives considered
- Just keep the local reimplementations. Has worked, but the third extension to need it (cli-web-ops) shipped before promotion. Two reasonable choices for ergonomic extension surface seems like the threshold.
- A separate
urfave/cli-walk helper module. Possible but seems silly for ~15 lines of code that fit cleanly on *Command.
Happy to send a PR if the team is interested.
Summary
Add two small convenience methods to
*cli.Commandthat several third-party extensions reimplement today:Motivation
I maintain a family of small urfave/cli extensions where each repo independently reimplements both of these:
registerTreeis a hand-rolled walker; tool names are dot-joined paths.buildNavListandrenderPerPageeach walk the tree; nav slugs use dash-joined paths.The pattern across all three is:
Three flavors of the same thing.
Walkremoves the recursion boilerplate;Path()removes the manualappend(prefix, cmd.Name)accumulation. Both are non-breaking additions.Alternatives considered
urfave/cli-walkhelper module. Possible but seems silly for ~15 lines of code that fit cleanly on*Command.Happy to send a PR if the team is interested.