Repository navigation
EPIC: Hierarchical team-prefix grouping (multi-level headings) #125
Description
Context
The original request in this issue proposes organizing --group-by-team-prefix results with a hierarchy logic instead of the current flat, single-level grouping:
- Hierarchical prefixes: a prefix chain like
gamme-/squad-should produce nested headings (## gamme-client/### squad-dashboard). - Grouping overlapping levels: when team names themselves overlap (e.g.
gamme-lead-clientandgamme-lead-client-p1), nest them automatically instead of listing them as unrelated siblings. - Advanced/consolidated rendering: collapse deep single-branch chains into one heading with a summary suffix (e.g.
gamme-lead-client (including p1, unset, etc.)).
This is a substantial change touching the grouping algorithm, both output formats (markdown/JSON), the interactive TUI, and the --pick-team feature. It is tracked as an EPIC and split into the 7 sub-issues below.
Update: after using it in practice, mechanism 3 (--group-by-team-prefix-consolidate) turned out not to match the actual functional need. It is being removed (#196) and replaced by an automatic pick-team resolution strategy, --pick-team-auto (#197), which resolves combined/ambiguous sections by common prefix instead of collapsing unambiguous single-branch chains.
Further update: real-world usage of --pick-team-auto surfaced 3 edge cases (see investigation tests added in #197):
- Auto-nesting of overlapping single-team labels (mechanism 2) combines with a
/-chain's own depth to produce more heading levels than the chain alone would suggest — confirmed as the intended interaction of two separate, already-documented mechanisms, not a bug. - A repo matching only a non-first prefix in a chain (e.g.
squad-ingamme-/squad-) with no match on the first prefix (gamme-) is invisible to that chain and falls through to a later independent chain instead — existing, documented "first chain to match wins" behavior. --pick-team-auto's common-prefix strategy correctly leaves combos unresolved when no single candidate is a literal prefix of every other candidate, even when several combos share some (but not all) team members — a more aggressive merge heuristic was considered and rejected as risking silent loss of team-membership information. Instead, a new--exclude-team-prefixesoption ([10/10] --exclude-team-prefixes: exclude noisy team-name prefixes from grouping #200) lets noisy team-name prefixes be excluded from grouping at the source, reducing ambiguous combos before--pick-team/--pick-team-autoeven need to resolve them.
2026-09-19 update: all 10 sub-issues are merged and closed. A dedicated code-review pass (PR #201) also caught and fixed an unsound assumption in the grouping algorithm (a team-name string prefix does not imply GitHub team membership — dropRedundantSubTeams was removed), and 2 additional dogfooding bugs were fixed: cross-combo --pick-team-auto clustering when no literal common prefix exists across combos, and a documented GitHub API limitation with path:*.ext glob wildcards.
Final update: v2.0.0 has been cut (PR #214), including the blog post and updated CHANGELOG.md. Closing this epic.
Solution
Implement all 3 mechanisms as a coherent hierarchical model:
- A tree-shaped grouping result (replacing the current flat
TeamSection[]) built from a CLI-declared prefix chain (/for depth,,for independent sibling hierarchies) plus automatic nesting of overlapping team names. - Depth-aware rendering in both markdown (
##/###/####) and JSON output. - Depth-aware TUI rendering and navigation.
--pick-teamextended to resolve a section at any depth, not just the leaf level.
This is a breaking change to the --group-by-team-prefix / --pick-team CLI surface and to the JSON output shape, and will ship as a major release per AGENTS.md.
Implementation overview
flowchart TD
CLI["github-code-search.ts<br/>--group-by-team-prefix chain grammar"] --> Parse["Parse chains #6<br/>e.g. gamme-/squad-,chapter-"]
Parse --> Fetch["fetchRepoTeams (api.ts)<br/>flattened prefix list, unchanged"]
Fetch --> Algo["groupByTeamHierarchy #1<br/>src/group.ts"]
Algo --> Tree["TeamSection tree<br/>{label, groups, level, children}"]
Tree --> Consolidate["Consolidation #2<br/>collapse single-branch chains"]
Consolidate --> Flatten["flatten/rebuild helpers<br/>RepoGroup.sectionLabel + level"]
Flatten --> MD["buildMarkdownOutput #3<br/>##/###/#### headings"]
Flatten --> JSON["buildJsonOutput #3<br/>nested sections"]
Flatten --> TUI["buildRows / render.ts #4<br/>nested header rows"]
Tree --> Pick["--pick-team path addressing #5<br/>applyTeamPick / moveRepoToSection"]
Pick --> Flatten
MD --> Docs["docs/usage/team-grouping.md #7"]
JSON --> Docs
TUI --> Docs
Sub-issues (in dependency order):
- [1/7] Data model & core hierarchical grouping algorithm #177 - [1/10] Data model & core hierarchical grouping algorithm
- [2/7] Advanced consolidated rendering #178 - [2/10] Advanced consolidated rendering
- [3/7] Markdown & JSON output for N-level headings #179 - [3/10] Markdown & JSON output for N-level headings
- [4/7] TUI rendering & navigation for N-level headers #180 - [4/10] TUI rendering & navigation for N-level headers
- [5/7] --pick-team / re-pick across all hierarchy levels #181 - [5/10] --pick-team / re-pick across all hierarchy levels
- [6/7] CLI wiring end-to-end #182 - [6/10] CLI wiring end-to-end
- [7/7] Documentation & changelog #183 - [7/10] Documentation & changelog
- [8/10] Remove --group-by-team-prefix-consolidate and consolidateTeamHierarchy #196 - [8/10] Remove --group-by-team-prefix-consolidate and consolidateTeamHierarchy
- [9/10] --pick-team-auto: auto-resolve combined sections by common prefix #197 - [9/10] --pick-team-auto: auto-resolve combined sections by common prefix
- [10/10] --exclude-team-prefixes: exclude noisy team-name prefixes from grouping #200 - [10/10] --exclude-team-prefixes: exclude noisy team-name prefixes from grouping
Acceptance Criteria
- All 10 sub-issues above are closed and linked as native GitHub sub-issues of this EPIC.
-
--group-by-team-prefix "gamme-/squad-"produces nested##/###markdown headings and a matching nested JSON structure. - Team names that overlap within one level (e.g.
gamme-lead-client,gamme-lead-client-p1) are automatically nested rather than shown as unrelated siblings. -
--group-by-team-prefix-consolidate/consolidateTeamHierarchyare fully removed ([8/10] Remove --group-by-team-prefix-consolidate and consolidateTeamHierarchy #196). -
--pick-team-autoauto-resolves combined sections whose team names share a common prefix, at any hierarchy depth ([9/10] --pick-team-auto: auto-resolve combined sections by common prefix #197). -
--exclude-team-prefixesfilters out noisy team-name prefixes from grouping before combos form ([10/10] --exclude-team-prefixes: exclude noisy team-name prefixes from grouping #200). -
--pick-team(CLI and interactivep/t) resolves and reassigns sections at any hierarchy depth. -
docs/usage/team-grouping.mdanddocs/reference/cli-options.mdreflect the new syntax end to end.
Definition of Done
- All sub-issue PRs merged into
main(merged directly via the stacked-PR chain rather than through an intermediatefeat/hierarchical-team-groupingbranch — same end result). - Full validation suite green on
main:bun test,bun run lint,bun run format:check,bun run knip,bun run build.ts. - Major release cut per
AGENTS.mdrelease process, including the required blog post — v2.0.0, blog post, PR v2.0.0 #214. -
CHANGELOG.mdupdated, no_pending_rows left.
Activity
[-]feat - organizing results with hierarchy logic[/-][+]EPIC: Hierarchical team-prefix grouping (multi-level headings)[/+]Document hierarchical team-prefix grouping and add CHANGELOG entry