Cobra CLI Command Grouping and Gating

Claude Code·Opus 4.8[1m]·gtrrz-victor·2mo ago·120hr 11min·9 Checkpoints·46 file changes·+2373/-492·839.1K tokens

check if cobra golang cli tooling allows any kind of command grouping without being under same parent command

2mo ago·19.3s

Yes. Cobra has cobra.Group — groups commands in help output without nesting them under shared parent.

How:

login and logout stay top-level commands (entire login, not entire auth login), but help lists them under "Authentication:" header.

Rules:

  • Set Group.ID, reference via child GroupID.
  • AddGroup on parent before adding grouped children, else cobra panics at help render.
  • Built-in help/completion groups: set with SetHelpCommandGroupID / SetCompletionCommandGroupID.

Limits:

  • Pure display grouping. No shared flags, no shared PreRun, no invocation nesting.
  • One level — group headers in one command's help list. Not hierarchical.

This repo already uses real parent groups (session, checkpoint) for canonical paths + hidden top-level shortcuts. cobra.Group = alternative when want flat commands but grouped help.

great! Please create a branch where we put all the hidden commands on the same group called experimental. And please, I want to make them hidden or not based on an argument pass while building the binary. Build from command mise, means developer -> we want to see experimentals, build from goreleaser we don't want to see experimental

2mo ago·17.0s

Using superpowers:brainstorming to scope this before touching code — real ambiguity in "which hidden commands" and how build-tag gating should work.

Base directory for this skill: /Users/gtrrz-victor/.claude/plugins/cache/claude-plugins-official/superpowers/6.1.1/skills/brainstorming

Brainstorming Ideas Into Designs

Help turn ideas into fully formed designs and specs through natural collaborative dialogue.

Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval.

<HARD-GATE> Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity. </HARD-GATE>

Anti-Pattern: "This Is Too Simple To Need A Design"

Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval.

Checklist

You MUST create a task for each of these items and complete them in order:

  1. Explore project context — check files, docs, recent commits
  2. Offer the visual companion just-in-time — NOT upfront. The first time a question would genuinely be clearer shown than described, offer it then (its own message); on approval its browser tab opens for you. If no visual question ever arises, never offer it. See the Visual Companion section below.
  3. Ask clarifying questions — one at a time, understand purpose/constraints/success criteria
  4. Propose 2-3 approaches — with trade-offs and your recommendation
  5. Present design — in sections scaled to their complexity, get user approval after each section
  6. Write design doc — save to docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md and commit
  7. Spec self-review — quick inline check for placeholders, contradictions, ambiguity, scope (see below)
  8. User reviews written spec — ask user to review the spec file before proceeding
  9. Transition to implementation — invoke writing-plans skill to create implementation plan

Process Flow

The terminal state is invoking writing-plans. Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans.

The Process

Understanding the idea:

  • Check out the current project state first (files, docs, recent commits)
  • Before asking detailed questions, assess scope: if the request describes multiple independent subsystems (e.g., "build a platform with chat, file storage, billing, and analytics"), flag this immediately. Don't spend questions refining details of a project that needs to be decomposed first.
  • If the project is too large for a single spec, help the user decompose into sub-projects: what are the independent pieces, how do they relate, what order should they be built? Then brainstorm the first sub-project through the normal design flow. Each sub-project gets its own spec → plan → implementation cycle.
  • For appropriately-scoped projects, ask questions one at a time to refine the idea
  • Prefer multiple choice questions when possible, but open-ended is fine too
  • Only one question per message - if a topic needs more exploration, break it into multiple questions
  • Focus on understanding: purpose, constraints, success criteria

Exploring approaches:

  • Propose 2-3 different approaches with trade-offs
  • Present options conversationally with your recommendation and reasoning
  • Lead with your recommended option and explain why

Presenting the design:

  • Once you believe you understand what you're building, present the design
  • Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced
  • Ask after each section whether it looks right so far
  • Cover: architecture, components, data flow, error handling, testing
  • Be ready to go back and clarify if something doesn't make sense

Design for isolation and clarity:

  • Break the system into smaller units that each have one clear purpose, communicate through well-defined interfaces, and can be understood and tested independently
  • For each unit, you should be able to answer: what does it do, how do you use it, and what does it depend on?
  • Can someone understand what a unit does without reading its internals? Can you change the internals without breaking consumers? If not, the boundaries need work.
  • Smaller, well-bounded units are also easier for you to work with - you reason better about code you can hold in context at once, and your edits are more reliable when files are focused. When a file grows large, that's often a signal that it's doing too much.

Working in existing codebases:

  • Explore the current structure before proposing changes. Follow existing patterns.
  • Where existing code has problems that affect the work (e.g., a file that's grown too large, unclear boundaries, tangled responsibilities), include targeted improvements as part of the design - the way a good developer improves code they're working in.
  • Don't propose unrelated refactoring. Stay focused on what serves the current goal.

After the Design

Documentation:

  • Write the validated design (spec) to docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md
    • (User preferences for spec location override this default)
  • Use elements-of-style:writing-clearly-and-concisely skill if available
  • Commit the design document to git

Spec Self-Review: After writing the spec document, look at it with fresh eyes:

  1. Placeholder scan: Any "TBD", "TODO", incomplete sections, or vague requirements? Fix them.
  2. Internal consistency: Do any sections contradict each other? Does the architecture match the feature descriptions?
  3. Scope check: Is this focused enough for a single implementation plan, or does it need decomposition?
  4. Ambiguity check: Could any requirement be interpreted two different ways? If so, pick one and make it explicit.

Fix any issues inline. No need to re-review — just fix and move on.

User Review Gate: After the spec review loop passes, ask the user to review the written spec before proceeding:

"Spec written and committed to <path>. Please review it and let me know if you want to make any changes before we start writing out the implementation plan."

Wait for the user's response. If they request changes, make them and re-run the spec review loop. Only proceed once the user approves.

Implementation:

  • Invoke the writing-plans skill to create a detailed implementation plan
  • Do NOT invoke any other skill. writing-plans is the next step.

Key Principles

  • One question at a time - Don't overwhelm with multiple questions
  • Multiple choice preferred - Easier to answer than open-ended when possible
  • YAGNI ruthlessly - Remove unnecessary features from all designs
  • Explore alternatives - Always propose 2-3 approaches before settling
  • Incremental validation - Present design, get approval before moving on
  • Be flexible - Go back and clarify when something doesn't make sense

Visual Companion

A browser-based companion for showing mockups, diagrams, and visual options during brainstorming. Available as a tool — not a mode. Accepting the companion means it's available for questions that benefit from visual treatment; it does NOT mean every question goes through the browser.

Offering the companion (just-in-time): Do NOT offer it upfront. Wait until a question would genuinely be clearer shown than told — a real mockup / layout / diagram question, not merely a UI topic. The first time that happens, offer it then, as its own message:

"This next part might be easier if I show you — I can put together mockups, diagrams, and comparisons in a browser tab as we go. It's still new and can be token-intensive. Want me to? I'll open it for you."

This offer MUST be its own message. Only the offer — no clarifying question, summary, or other content. Wait for the user's response. If they accept, start the server with --open so their browser opens to the first screen automatically. If they decline, continue text-only and don't offer again unless they raise it.

Per-question decision: Even after the user accepts, decide FOR EACH QUESTION whether to use the browser or the terminal. The test: would the user understand this better by seeing it than reading it?

  • Use the browser for content that IS visual — mockups, wireframes, layout comparisons, architecture diagrams, side-by-side visual designs
  • Use the terminal for content that is text — requirements questions, conceptual choices, tradeoff lists, A/B/C/D text options, scope decisions

A question about a UI topic is not automatically a visual question. "What does personality mean in this context?" is a conceptual question — use the terminal. "Which wizard layout works better?" is a visual question — use the browser.

If they agree to the companion, read the detailed guide before proceeding: skills/brainstorming/visual-companion.md

2mo ago·3m

Here's the full hidden inventory, split into experimental candidates (safe to gate — maturing feature families) vs leave-alone (plumbing/legacy that must keep working in release):

Experimental candidates — pick from these:

CommandFileNote
expertsexperts_cmd.gohas --tui
searchsearch_cmd.gotop-level, no hint
tokens / tokens profiletokens_profile.goalready under labs
investigateinvestigate/cmd.goexplicitly "hidden while maturing"
reviewreview/cmd.goexplicitly "hidden while maturing"
importimport_cmd.go
blame / whyattribution.goattribution subtree
runnerrunner_group.go
checkpoint policycheckpoint_policy.go⚠️ subcommand of checkpoint, not root

Leave alone (always-hidden, untouched): hooks/hooks git, mcp, __send_analytics, curl-bash-post-install, trail, agent hook commands, deprecated shortcuts (resume/attach/explain/trace/reset/rewind), cobra aliases (sessions/cp/etc).

One design note before you pick: a single cobra.Group called "experimental" only renders as one help section for commands sharing a parent — i.e. top-level commands on root. checkpoint policy lives under checkpoint, so it can't join a root-level "experimental" group (it'd just be gated-visible under checkpoint instead).

Which do you want in the gated experimental set? (default recommendation: experts, search, tokens, investigate, review, import — the top-level maturing families; drop blame/why/runner/checkpoint policy unless you want them too)

I want also to be marked as experimental -> blame/why/runner/checkpoint policy

2mo ago·4m

Branch experimental-command-gating created. Design doc written + committed to docs/superpowers/specs/2026-07-10-experimental-command-gating-design.md (force-added — that dir is gitignored).

Recap of what got decided:

  • Gate = new experimental pkg, var State="true", goreleaser stamps State=false. Mirrors versioninfo.
  • experimental.Register(parent, child) — sets Hidden=!Enabled(), GroupID, adds group. Non-invasive (overrides constructor Hidden, no edits to review/investigate pkgs).
  • 10 gated: tokens, import, review, investigate, blame, why, search, experts, runner (root) + checkpoint policy.
  • Both goreleaser configs stamped State=false. Plus a mise build task.
  • Infra/deprecated/aliases untouched.

Please review the spec and tell me if you want changes before I write the implementation plan.

Not sure if experimental.State is the more semantically correct naming, as what this flag should do is just maken those commands visible or not, as they are and will be still experimental

2mo ago·1m

Renamed. Now experimental.Visible (var) / experimental.IsVisible() (func) — flag name says "visibility", not command status.

Spec updated + committed. Anything else to change, or good to move to the implementation plan?

Implement! Now!!

2mo ago·16m

Done. Branch experimental-command-gating, commit 8622db28a.

Built:

  • New pkg cmd/entire/cli/experimental — Visible var (default "true", goreleaser stamps "false"), IsVisible(), Register(parent, child).
  • Dev build → 10 commands visible, grouped under "Experimental commands:". Release build → hidden, still runnable.
  • Gated: tokens, import, review, investigate, blame, why, search, experts, runner + checkpoint policy.
  • .goreleaser.yaml stamped Visible=false. nonprod builds only git-remote-entire → no stamp needed.
  • mise run build task added.

Verified end-to-end:

  • Dev binary help shows grouped section; release binary hides all 10; both still runnable in release. ✓
  • Unit (all pkgs) ✓, integration ✓, E2E canary 4/4 ✓.
  • Lint clean on my files.

Two heads-up:

  1. Your env mise run lint is broken independent of this change — stale golangci-lint v1.64.8 (in ~/.local/share/mise/installs/go/1.26.4/bin) shadows mise's pinned v2 on PATH, so it errors "v2 config with v1". I verified lint using the correct v2 binary directly. Worth fixing your PATH/removing the stale binary.

  2. cobra quirk (expected): in dev help, introducing the experimental group relabels all other root commands from "Available Commands:" → "Additional Commands:". Release help is untouched (group only registered when visible). Flagged in the design doc.

Design doc committed at docs/superpowers/specs/2026-07-10-experimental-command-gating-design.md (force-added — dir is gitignored).

ship it as draft

2mo ago·10.6s

Base directory for this skill: /Users/gtrrz-victor/.claude/skills/ship

Ship Changes

Commit current changes, push to remote, and update the PR.

Step 1: Analyze changes

  1. Run git diff --stat and git diff to understand what changed
  2. Run git status to see untracked files
  3. Run git log --oneline -3 to match the repo's commit message style

Step 2: Commit

  1. Stage only the relevant changed/untracked files by name (never git add -A or git add .)
  2. Write a concise commit message that focuses on the "why" not the "what"
    • If `` is provided, use it as the commit message
    • Otherwise, draft one from the diff
  3. Commit. If hooks fail, diagnose and fix — do NOT use --no-verify

Step 3: Push

  1. Check if the branch tracks a remote: git rev-parse --abbrev-ref --symbolic-full-name @{u}
  2. If not tracking, push with -u origin <branch>
  3. If tracking, just git push
  4. If push is rejected (remote has new commits), pull with rebase first then push

Step 4: Update PR

  1. Find the open PR for the current branch: gh pr view --json number,body,title
  2. If no PR exists, skip this step and inform the user
  3. Compare the current PR body against the new changes:
    • If the changes are within the existing PR scope, update the description to reflect the current state
    • If the changes are additive or a follow-up, add a PR comment summarizing what was just pushed instead
  4. When updating the PR body, preserve the overall structure but refresh the summary bullets and test plan
  5. When adding a comment, keep it concise — bullet points of what changed and why
  6. Before making any PR update (description edit or comment), show the user the exact text you plan to post and ask for their approval. Do NOT post until they confirm.

Rules

  • Never commit files that look like secrets (.env, credentials, tokens)
  • Never force push
  • Always show the user what was committed and the PR URL when done
2mo ago·43.1s

Shipped as draft. 🚀

PR #1703 (draft): https://github.com/entireio/cli/pull/1703

  • Branch experimental-command-gating pushed, tracking origin.
  • 3 commits (design doc + rename + feature).
  • Draft PR opened against main with full summary + test plan.

Ready for review when you flip it out of draft.

2mo ago
2mo ago·5.1s

Dev build installed to ~/go/bin. Since it's a dev build (no Visible=false stamp), experimental commands now show — verify with entire help → "Experimental commands:" section.

this is how we want to have the experimental commands visible/hidden based on the build:

So, final shape?:

stable includes -> normal, lab and experimental ( but hidden ) nightly includes -> normal, lab and experimental NOT hidden local builds -> normal, lab and experimental NOT hidden [ same as nightly ]

2mo ago·4m

Pushed (commit 4b358a859). The draft PR body's build table is now inaccurate (it implied all goreleaser builds hide experimental). I'd like to update the PR description's "Build behavior" section to:

Want me to update the PR description with this?

y

2mo ago·1m

PR description updated. Draft PR #1703 now reflects the final shape:

Buildexperimental
Localvisible
Nightly (vX.Y.Z-nightly.*)visible
Stable (vX.Y.Z)hidden

Achieved via .goreleaser.yaml template Visible={{ if .Prerelease }}true{{ else }}false{{ end }} — verified with goreleaser check + snapshot build. Commit 4b358a859 pushed. labs stays always-visible in all three; experimental is the gated set.

ship it and change draft to ready

2mo ago·21.9s

Shipped. PR #1703 now ready for review (no longer draft), open against main.

https://github.com/entireio/cli/pull/1703

Nothing new to commit — the branch was already pushed at 4b358a859. Done.

Review target: GitHub pull request 1703.

Gather this target's diff with (instead of any local git diff):

  1. gh pr view 1703 --json title,body,author,baseRefName,headRefName,state,additions,deletions,changedFiles,labels for context
  2. gh pr diff 1703 for the unified diff

The PR's diff is the only review scope — local working-tree changes are out of scope. When you need surrounding code, Read the files in this checkout if it matches the PR's branch, otherwise fetch file contents via gh.

Analyze the changes and provide a thorough code review that includes:

  • An overview of what the PR does
  • Analysis of code quality and style
  • Specific suggestions for improvements
  • Any potential issues or risks

Keep your review concise but thorough. Focus on:

  • Code correctness
  • Following project conventions
  • Performance implications
  • Test coverage
  • Security considerations

Format your review with clear sections and bullet points.

2mo ago·2m

Reviewed PR #1703 (this checkout = PR head 4b358a859, so I read the files directly). Verified the two real interaction risks myself.

Overview

Build-time gate for a curated set of "experimental" commands. New experimental package exposes Visible (ldflags-stamped string) + Register(parent, child) that files commands under an "Experimental commands:" cobra group when visible, or marks them Hidden (no GroupID) when not. 10 commands gated: tokens, import, review, investigate, blame, why, search, experts, runner, checkpoint policy. .goreleaser.yaml keys the stamp off .Prerelease → hidden on stable, visible on nightly/local.

Correctness — solid

  • Gate logic correct across all 3 build shapes; .Prerelease template verified via goreleaser check + snapshot build.
  • Register overriding Hidden is the right call — non-invasive, no edits to the review/investigate packages, single source of truth.
  • Group registered only when visible — correctly avoids cobra shoving all other root commands under "Additional Commands:" in release. Good catch, and no panic risk since no GroupID references an unregistered group.
  • entire binary is gitignored ✓ — mise run build -o entire can't be accidentally committed.

Things to flag

  • ⚠️ agent-help surface is now build-dependent (worth documenting, not a blocker). agent_help_cmd.go:199 advertises a command when !Hidden OR it has agentHelpAnnotation. So dev builds now expose investigate/review/experts/search/tokens/etc. through entire agent-help; release builds don't (same as before — they were always Hidden). This means agents get a richer surface on dev builds. Intended, but the CLAUDE.md "agent-help is the single source of truth" contract now varies by channel. Confirmed no gated command sets agentHelpAnnotation, so nothing leaks in release.

  • Doc drift (minor): CLAUDE.md still states these are unconditionally hidden — e.g. "tokens: profile (hidden from root help while token diagnostics mature)" and "The search top-level remains hidden without a hint." Those are now build-conditional. Update CLAUDE.md's command-layout section to reference the experimental gate. (AGENTS.md is a symlink, so one edit.)

  • Test fragility (low risk): the Visible-mutating tests correctly omit t.Parallel(), and rely on Go running non-parallel tests (with cleanup-restore) before parallel ones resume — so parallel tests like TestCheckpointPolicyCommandIsExperimental always see the restored default. Works, but a future t.Parallel() added to a mutating test would flake. The in-code comments warn against it — acceptable.

Style / conventions — good

  • Package doc + var/func comments are clear; matches the versioninfo precedent the repo already uses.
  • Comment density and file naming consistent with surrounding code.
  • Test coverage is thorough: truth table, Register visible/hidden/shared-group, cli-level wiring for all 10, dev-vs-release help rendering. Existing Hidden-assertion tests correctly migrated to assert the gate.

Performance / security

  • None. Compile-time string, single ContainsGroup check per registration. No runtime, auth, or data-path changes. Hidden commands stay runnable — no capability removed.

Verdict

Ship-ready. No correctness blockers. Only follow-up worth doing: a one-line CLAUDE.md update for the doc drift, and optionally a sentence in the PR/design noting the dev-vs-release agent-help difference. Want me to make the CLAUDE.md edit?

fix the findings

2mo ago·2m

Findings fixed and pushed (commit 46dc6572b).

Fixed:

  • Doc drift — CLAUDE.md now documents the build-time gate: which 10 commands are experimental, visible in dev/nightly + hidden in stable (always runnable), how experimental.Visible/Register work. Corrected the stale "unconditionally hidden" lines for tokens and top-level search. (AGENTS.md symlink → covered.)
  • agent-help contract — added a note that the advertised surface is build-dependent (experimental commands appear in dev/nightly, absent in stable), matching entire help.

Not changed (no fix needed):

  • Test fragility — already mitigated: the Visible-mutating tests are non-parallel with cleanup-restore, and comments warn against adding t.Parallel(). No code change would improve on that without over-engineering.

PR #1703 up to date at 46dc6572b.

2mo ago
2mo ago·3.7s

Installed. Dev build → experimental visible. entire help shows the "Experimental commands:" group.

delete the created doc under superpowers

2mo ago·35.0s

Deleted and pushed (commit 1229f6c65).

Heads-up: the PR #1703 description still has a line Design doc: docs/superpowers/specs/... that now points at a deleted file. Want me to strip that line from the PR body?

do we need the new task.build inside mise.toml?

2mo ago·2m

PR #1703 up to date at e9ccb98a2. Two now-stale lines remain in the PR description I should fix:

  1. Notes: Design doc: docs/superpowers/specs/... → the file was deleted. Remove the line.
  2. Build behavior: ...Added a mise run build task (plain build, experimental visible). → false now. Change to: .goreleaser.nonprod.yaml builds only git-remote-entire, so it's not stamped. (drop the mise clause; the table's "Local (…/mise run build) → visible" row stays correct since the existing file task builds with no ldflags).

Want me to apply those two edits to the PR description?

y

2mo ago·1m

Done. PR #1703 description cleaned:

  • Removed the deleted design-doc line.
  • Dropped the false "Added a mise run build task" clause (kept the accurate build table + .Prerelease ldflags note).

Branch at e9ccb98a2; the auto-generated Cursor summary block at the bottom still mentions the old task/doc, but that regenerates on its own — the human-authored body is now accurate.

review copilot feedback from the PR

2mo ago·5m

Both bots reviewed rigorously. Verdict with evidence:

Cursor Bugbot — "release archives ship dev completions" (Medium)

False positive. The generated completion scripts are dynamic shims, not static enumerations:

  • grep for experimental command names in completions/entire.{bash,fish} → 0 hits.
  • They delegate to entire __complete at tab-time (5 refs in bash).

So the bundled script is identical no matter what Visible was at generation. Actual suggestions come from the installed binary at runtime — a stable release (stamped Visible=false) has experimental Hidden, and cobra excludes hidden commands from __complete. Completion correctly hides them in stable. No leak. No fix needed.

Copilot — "data race on experimental.Visible" (×2)

Not a bug. Ran the full cli package under go test -race: zero DATA RACE reports. (One unrelated failure — TestCheckPRBinaries_SmallBinaryPasses segfaults under -race; it shells out to build binaries and never touches experimental.Visible. Excluding it → package passes clean under -race.)

Why there's no race: every Visible-mutating test is non-parallel. Go runs non-parallel tests to completion (with t.Cleanup restore) in the sequential phase before any t.Parallel() test resumes. During the parallel phase, Visible is only ever read. Concurrent reads with no concurrent write = no data race, empirically confirmed.

Copilot's real point is valid only as fragility: the safety rests on an implicit invariant (mutators must never gain t.Parallel()). It's the same thing I flagged in my own review — a note, not a defect.

Recommendation

No code change is required — all three are non-issues. Optional hardening to quiet the bots and make the invariant explicit: move the test helper into the package as experimental.SetVisibleForTest(t, bool) with a comment stating it must only be used from non-parallel tests. It won't change behavior (a mutex can't make parallel mutators logically safe anyway, and Visible must stay a plain string for ldflags).

Want me to (a) add that optional helper+comment, and/or (b) reply on the two PR threads with these findings and resolve them?

b

2mo ago·1m

Done. All three bot threads replied to with the verdicts + evidence, and resolved:

  • Cursor (completions) → replied false-positive (dynamic shim scripts, runtime binary gates completion), resolved.
  • Copilot ×2 (data race) → replied not-a-bug (full cli package clean under -race; non-parallel mutators; Visible must stay a plain string for ldflags), resolved.

No code changes — all findings were non-issues on rigorous check. PR #1703 threads are now clear.