Cobra CLI Command Grouping and Gating

check if cobra golang cli tooling allows any kind of command grouping without being under same parent command
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 childGroupID. AddGroupon parent before adding grouped children, else cobra panics at help render.- Built-in
help/completiongroups: set withSetHelpCommandGroupID/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
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:
- Explore project context — check files, docs, recent commits
- 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.
- Ask clarifying questions — one at a time, understand purpose/constraints/success criteria
- Propose 2-3 approaches — with trade-offs and your recommendation
- Present design — in sections scaled to their complexity, get user approval after each section
- Write design doc — save to
docs/superpowers/specs/YYYY-MM-DD-<topic>-design.mdand commit - Spec self-review — quick inline check for placeholders, contradictions, ambiguity, scope (see below)
- User reviews written spec — ask user to review the spec file before proceeding
- 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:
- Placeholder scan: Any "TBD", "TODO", incomplete sections, or vague requirements? Fix them.
- Internal consistency: Do any sections contradict each other? Does the architecture match the feature descriptions?
- Scope check: Is this focused enough for a single implementation plan, or does it need decomposition?
- 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
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:
| Command | File | Note |
|---|---|---|
experts | experts_cmd.go | has --tui |
search | search_cmd.go | top-level, no hint |
tokens / tokens profile | tokens_profile.go | already under labs |
investigate | investigate/cmd.go | explicitly "hidden while maturing" |
review | review/cmd.go | explicitly "hidden while maturing" |
import | import_cmd.go | |
blame / why | attribution.go | attribution subtree |
runner | runner_group.go | |
checkpoint policy | checkpoint_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)
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
experimentalpkg,var State="true", goreleaser stampsState=false. Mirrorsversioninfo. experimental.Register(parent, child)— setsHidden=!Enabled(),GroupID, adds group. Non-invasive (overrides constructorHidden, no edits toreview/investigatepkgs).- 10 gated:
tokens,import,review,investigate,blame,why,search,experts,runner(root) +checkpoint policy. - Both goreleaser configs stamped
State=false. Plus amise buildtask. - 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
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?
Done. Branch experimental-command-gating, commit 8622db28a.
Built:
- New pkg
cmd/entire/cli/experimental—Visiblevar (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.yamlstampedVisible=false. nonprod builds onlygit-remote-entire→ no stamp needed.mise run buildtask 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:
-
Your env
mise run lintis broken independent of this change — stalegolangci-lint v1.64.8(in~/.local/share/mise/installs/go/1.26.4/bin) shadows mise's pinnedv2on 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. -
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).
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
- Run
git diff --statandgit diffto understand what changed - Run
git statusto see untracked files - Run
git log --oneline -3to match the repo's commit message style
Step 2: Commit
- Stage only the relevant changed/untracked files by name (never
git add -Aorgit add .) - 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
- Commit. If hooks fail, diagnose and fix — do NOT use
--no-verify
Step 3: Push
- Check if the branch tracks a remote:
git rev-parse --abbrev-ref --symbolic-full-name @{u} - If not tracking, push with
-u origin <branch> - If tracking, just
git push - If push is rejected (remote has new commits), pull with rebase first then push
Step 4: Update PR
- Find the open PR for the current branch:
gh pr view --json number,body,title - If no PR exists, skip this step and inform the user
- 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
- When updating the PR body, preserve the overall structure but refresh the summary bullets and test plan
- When adding a comment, keep it concise — bullet points of what changed and why
- 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
Shipped as draft. 🚀
PR #1703 (draft): https://github.com/entireio/cli/pull/1703
- Branch
experimental-command-gatingpushed, trackingorigin. - 3 commits (design doc + rename + feature).
- Draft PR opened against
mainwith full summary + test plan.
Ready for review when you flip it out of draft.
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 ]
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?
PR description updated. Draft PR #1703 now reflects the final shape:
| Build | experimental |
|---|---|
| Local | visible |
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.
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):
gh pr view 1703 --json title,body,author,baseRefName,headRefName,state,additions,deletions,changedFiles,labelsfor contextgh pr diff 1703for 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.
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;
.Prereleasetemplate verified viagoreleaser check+ snapshot build. RegisteroverridingHiddenis the right call — non-invasive, no edits to thereview/investigatepackages, 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
GroupIDreferences an unregistered group. entirebinary is gitignored ✓ —mise run build -o entirecan't be accidentally committed.
Things to flag
-
⚠️
agent-helpsurface is now build-dependent (worth documenting, not a blocker).agent_help_cmd.go:199advertises a command when!HiddenOR it hasagentHelpAnnotation. So dev builds now exposeinvestigate/review/experts/search/tokens/etc. throughentire agent-help; release builds don't (same as before — they were alwaysHidden). 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 setsagentHelpAnnotation, 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
searchtop-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 omitt.Parallel(), and rely on Go running non-parallel tests (with cleanup-restore) before parallel ones resume — so parallel tests likeTestCheckpointPolicyCommandIsExperimentalalways see the restored default. Works, but a futuret.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
versioninfoprecedent the repo already uses. - Comment density and file naming consistent with surrounding code.
- Test coverage is thorough: truth table,
Registervisible/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
ContainsGroupcheck 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?
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/Registerwork. Corrected the stale "unconditionally hidden" lines fortokensand top-levelsearch. (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 addingt.Parallel(). No code change would improve on that without over-engineering.
PR #1703 up to date at 46dc6572b.
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?
PR #1703 up to date at e9ccb98a2. Two now-stale lines remain in the PR description I should fix:
- Notes:
Design doc: docs/superpowers/specs/...→ the file was deleted. Remove the line. - 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?
Done. PR #1703 description cleaned:
- Removed the deleted design-doc line.
- Dropped the false "Added a
mise run buildtask" clause (kept the accurate build table +.Prereleaseldflags 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.
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:
grepfor experimental command names incompletions/entire.{bash,fish}→ 0 hits.- They delegate to
entire __completeat 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?
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
clipackage clean under-race; non-parallel mutators;Visiblemust stay a plain string for ldflags), resolved.
No code changes — all findings were non-issues on rigorous check. PR #1703 threads are now clear.