Research: can the cobra bootstrap boilerplate be reduced without losing cobra API power? #6

Closed
opened 2026-08-06 16:45:53 +00:00 by ginjiruu · 2 comments
Owner

Question

Can the cobra bootstrap boilerplate be reduced without losing power access to the underlying cobra API?

cmd/ totals ~1,048 lines (go-template), ~959 (ttrpg), ~381 (example): root.go, serve.go, config.go, dev.go, pager.go — near-identical across consumers. This passes the "example proves it" boundary (the example hand-wrote it; consumers duplicate it). The boilerplate includes the -v/-vv verbosity ladder, the config list/describe/set command, the embedded-OIDC dev command, and a pager.

Research this: what would a shared toolbelt/cmd (or config-driven) bootstrap look like that still exposes the raw cobra API (*cobra.Command, persistent flags, custom hooks) to apps? Survey cobra's extensibility surface and how much of the three repos' cmd/ is genuinely common vs per-app divergence (verbosity model, KCL vs YAML config save).

The decision: absorb a shared bootstrap, or rule "keep per-app" because the divergence is structural? The answer graduates into a fresh absorption ticket or a keep-per-app ruling — resolve with a /research subagent on a throwaway research/<name> branch, then write the plan to docs/plans/.

## Question Can the cobra bootstrap boilerplate be reduced without losing power access to the underlying cobra API? `cmd/` totals ~1,048 lines (go-template), ~959 (ttrpg), ~381 (example): `root.go`, `serve.go`, `config.go`, `dev.go`, `pager.go` — near-identical across consumers. This passes the "example proves it" boundary (the example hand-wrote it; consumers duplicate it). The boilerplate includes the `-v/-vv` verbosity ladder, the `config list/describe/set` command, the embedded-OIDC `dev` command, and a pager. Research this: what would a shared `toolbelt/cmd` (or config-driven) bootstrap look like that still exposes the raw cobra API (`*cobra.Command`, persistent flags, custom hooks) to apps? Survey cobra's extensibility surface and how much of the three repos' `cmd/` is genuinely common vs per-app divergence (verbosity model, KCL vs YAML config save). The decision: absorb a shared bootstrap, or rule "keep per-app" because the divergence is structural? The answer graduates into a fresh absorption ticket or a keep-per-app ruling — resolve with a `/research` subagent on a throwaway `research/<name>` branch, then write the plan to `docs/plans/`.
Author
Owner

RESOLVED — research complete.

Answer: absorb — and the divergence is not structural. A shared toolbelt/cmd bootstrap is feasible while preserving full raw cobra API access.

Key findings:

  • pager.go (54 lines), dev_build.go, dev_nobuild.go are byte-identical across go-template ↔ ttrpg; serve.go differs in exactly 2 lines; config.go's generic core (~357 lines) is 100% reusable against the Fields() registry.
  • ~86% of package cmd (≈611/711 lines in go-template) is absorbable via a parent-command factory NewRootCommand(...) *cobra.Command — cobra is data-driven, so raw *cobra.Command is preserved (AddCommand, persistent flags, hooks, groups, completions).
  • Recommended shape (Option B): NewRootCommand(RootOptions), AddConfigCommand(root, SaveOptions) (injectable KCL/YAML save), Pager(), Serve(...) scaffold, DevSetup(prefix) in embeddedoidc, and one shared BuildLogger.
  • The KCL-vs-YAML save path is a ~47-line injectable strategy, not structure. Verbosity model: the int -v/-vv/-vvv ladder is already toolbelt-owned (config.VerboseToLevel).
  • ttrpg is a stale fork of go-template (its go.mod declares the go-template module path, imports go-template internals, pins an old toolbelt, and its FieldFlagVerbose refs already can't build against the current toolbelt). Treat it as a migration target, NOT a compat constraint.

Full findings: docs/research/cobra-bootstrap.md on branch research/cobra-bootstrap (commit 742c60e).

Decision recorded. The design of the toolbelt/cmd surface graduates into a new absorption ticket.

**RESOLVED — research complete.** **Answer: absorb — and the divergence is not structural.** A shared `toolbelt/cmd` bootstrap is feasible while preserving full raw cobra API access. Key findings: - `pager.go` (54 lines), `dev_build.go`, `dev_nobuild.go` are **byte-identical** across go-template ↔ ttrpg; `serve.go` differs in exactly 2 lines; `config.go`'s generic core (~357 lines) is 100% reusable against the `Fields()` registry. - **~86% of `package cmd`** (≈611/711 lines in go-template) is absorbable via a parent-command factory `NewRootCommand(...) *cobra.Command` — cobra is data-driven, so raw `*cobra.Command` is preserved (AddCommand, persistent flags, hooks, groups, completions). - Recommended shape (Option B): `NewRootCommand(RootOptions)`, `AddConfigCommand(root, SaveOptions)` (injectable KCL/YAML save), `Pager()`, `Serve(...)` scaffold, `DevSetup(prefix)` in `embeddedoidc`, and one shared `BuildLogger`. - The KCL-vs-YAML save path is a ~47-line injectable strategy, not structure. Verbosity model: the int `-v/-vv/-vvv` ladder is already toolbelt-owned (`config.VerboseToLevel`). - **ttrpg is a stale fork of go-template** (its `go.mod` declares the go-template module path, imports go-template internals, pins an old toolbelt, and its `FieldFlagVerbose` refs already can't build against the current toolbelt). Treat it as a migration target, NOT a compat constraint. Full findings: `docs/research/cobra-bootstrap.md` on branch `research/cobra-bootstrap` (commit `742c60e`). Decision recorded. The design of the `toolbelt/cmd` surface graduates into a new absorption ticket.
Author
Owner

Research resolved: absorb is viable — graduates into a cobra absorption ticket. Full findings on research/cobra-bootstrap branch.

Research resolved: absorb is viable — graduates into a cobra absorption ticket. Full findings on research/cobra-bootstrap branch.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ginjiruu/toolbelt#6
No description provided.