Summary
Let downstream aggregators control the root command namespace more aggressively than MetaCommandRegistry allows today. Three discrete mechanisms:
- Nest under a sub-command:
wtf dz list (library commands tucked under "dz") instead of wtf list.
- Selective exposure:
wtf list stays at root, but wtf tree / wtf setup go under wtf dz tree / wtf dz setup.
- Rename:
wtf tools as an alias for list, sysdiag monitors for list, etc.
All three are aggregator-configurable; the library defaults to today's flat structure (no breaking change).
Problem
v0.7.23 shipped MetaCommandRegistry with register / override / unregister as the primary extension API. For an aggregator like wtf-windows this is sufficient — drop tree / setup, override list / info, add mode / new / add, done.
But for aggregators with richer domain vocabulary (sysdiagnose-public, future consumers), the top-level name space gets crowded or inappropriate:
- Name collisions: a diagnostic aggregator with a tool legitimately named
info (e.g., "info gathering") can't use that name today — it's reserved by the library's built-in info meta-command. Same for list, setup, etc.
- Weak defaults for the domain:
sysdiag list is grammatically weaker than sysdiag monitors. The library's generic verbs don't fit every domain.
- Discoverability pollution:
wtf --help shows 6+ library meta-commands intermixed with 2-10 domain tools. Ratio gets worse as tool counts grow.
Proposed API
# Full nesting
engine.meta_registry.nest_all_under("dz")
# Result: wtf dz list, wtf dz info, wtf dz kit, etc.
# Top-level only contains: tools + aggregator-registered meta-commands
# Partial nesting
engine.meta_registry.nest_under("dz", members=["kit", "tree", "setup"])
engine.meta_registry.keep_at_root(["list", "info"])
# Result: wtf list / wtf info at root, wtf dz kit / wtf dz tree / wtf dz setup nested
# Rename
engine.meta_registry.rename("info", "inspect")
engine.meta_registry.rename("list", "tools")
# Result: wtf inspect (from info), wtf tools (from list)
# Combined
engine.meta_registry.nest_all_under("manage")
engine.meta_registry.rename("setup", "bootstrap")
# Result: wtf manage list, wtf manage inspect, wtf manage bootstrap, etc.
Semantics
nest_under(group_name, members=[...]): moves specified commands to a sub-parser; top-level reserves only group_name.
nest_all_under(group_name): shorthand for "every command the library auto-registered."
keep_at_root(members): explicitly opts command(s) out of a group.
rename(old_name, new_name): changes the CLI surface name; _meta tag and handler identification still use old_name internally (so handlers stay stable).
Dispatch: args._meta routes by the ORIGINAL command identifier. A rename("info", "inspect") still dispatches _meta="info" to the info handler. Rename is CLI-surface only.
Reserved commands: dynamically derived. nest_all_under("dz") means only "dz" is reserved at root + aggregator's own tool / extra reservations.
Help text: nest_under automatically groups commands in argparse's subparser rendering. Aggregator can still provide epilog_builder for custom section layout.
Backward compat: none of the new methods must be called. Default behavior (flat top-level namespace) is unchanged from v0.7.23.
Acceptance criteria
Dependencies
- Depends on: v0.7.23
MetaCommandRegistry — done
- Likely drives: sysdiagnose-public adoption (will be the first demanding use case)
- Not blocking: wtf-windows adoption (wtf doesn't need this feature; default flat namespace works)
Design tradeoffs considered
Pattern A (full nesting only): simpler surface but too rigid. Forces wtf dz <cmd> for everything or nothing. Most aggregators will want to keep list / info at root because those are universally useful top-level verbs.
Pattern B (selective + rename, this proposal): more surface area but matches real need. Costs ~120 LOC library + ~30 tests.
Pattern C (help-only grouping via epilog_builder): purely cosmetic, works today in v0.7.23, doesn't solve name-collision. Useful as a stopgap but not a substitute.
Status
Design-stage. Implementation deferred until there's a real aggregator asking for it (the sysdiagnose-public adoption issue will likely surface this need).
Related
Summary
Let downstream aggregators control the root command namespace more aggressively than
MetaCommandRegistryallows today. Three discrete mechanisms:wtf dz list(library commands tucked under "dz") instead ofwtf list.wtf liststays at root, butwtf tree/wtf setupgo underwtf dz tree/wtf dz setup.wtf toolsas an alias forlist,sysdiag monitorsforlist, etc.All three are aggregator-configurable; the library defaults to today's flat structure (no breaking change).
Problem
v0.7.23 shipped
MetaCommandRegistrywithregister / override / unregisteras the primary extension API. For an aggregator like wtf-windows this is sufficient — droptree/setup, overridelist/info, addmode/new/add, done.But for aggregators with richer domain vocabulary (sysdiagnose-public, future consumers), the top-level name space gets crowded or inappropriate:
info(e.g., "info gathering") can't use that name today — it's reserved by the library's built-ininfometa-command. Same forlist,setup, etc.sysdiag listis grammatically weaker thansysdiag monitors. The library's generic verbs don't fit every domain.wtf --helpshows 6+ library meta-commands intermixed with 2-10 domain tools. Ratio gets worse as tool counts grow.Proposed API
Semantics
nest_under(group_name, members=[...]): moves specified commands to a sub-parser; top-level reserves onlygroup_name.nest_all_under(group_name): shorthand for "every command the library auto-registered."keep_at_root(members): explicitly opts command(s) out of a group.rename(old_name, new_name): changes the CLI surface name;_metatag and handler identification still useold_nameinternally (so handlers stay stable).Dispatch:
args._metaroutes by the ORIGINAL command identifier. Arename("info", "inspect")still dispatches_meta="info"to the info handler. Rename is CLI-surface only.Reserved commands: dynamically derived.
nest_all_under("dz")means only"dz"is reserved at root + aggregator's own tool / extra reservations.Help text:
nest_underautomatically groups commands in argparse's subparser rendering. Aggregator can still provideepilog_builderfor custom section layout.Backward compat: none of the new methods must be called. Default behavior (flat top-level namespace) is unchanged from v0.7.23.
Acceptance criteria
MetaCommandRegistry.nest_under(group, members)implementedMetaCommandRegistry.nest_all_under(group)convenience methodMetaCommandRegistry.keep_at_root(members)overrideMetaCommandRegistry.rename(old, new)method_metaname even after renamebuild_parsersbuilds nested sub-parsers per groupepilog_builderoptional)tests/README.md+docs/guides/manifests.mdupdates + library module docstringDependencies
MetaCommandRegistry— doneDesign tradeoffs considered
Pattern A (full nesting only): simpler surface but too rigid. Forces
wtf dz <cmd>for everything or nothing. Most aggregators will want to keeplist/infoat root because those are universally useful top-level verbs.Pattern B (selective + rename, this proposal): more surface area but matches real need. Costs ~120 LOC library + ~30 tests.
Pattern C (help-only grouping via epilog_builder): purely cosmetic, works today in v0.7.23, doesn't solve name-collision. Useful as a stopgap but not a substitute.
Status
Design-stage. Implementation deferred until there's a real aggregator asking for it (the
sysdiagnose-publicadoption issue will likely surface this need).Related
notes/cli/2026-04-18__20-41-16__both_sysdiagnose-adoption-and-root-command-namespace-flexibility.md(project-private)notes/cli/2026-04-18__19-55-32__both_wtf-manage-subcommand-grouping-pattern.md(earlier, narrower version of the same idea)