Skip to content

framework: generalize area grouping into dynamic classification families #1005

@amrmelsayed

Description

@amrmelsayed

Umbrella issue. Generalize the area/* mechanism so any key:value label becomes a first-class classification family, discovered dynamically. Codev migrates from area/ to area: as part of this work; the framework adopts : as its sole delimiter and remains neutral on which keys a team picks.

Context

Today Codev privileges area/* as the single classification axis baked into framework code. Views group by it (Backlog, Builders, dashboard), parsers treat the area/ prefix as load-bearing, and the assignment rules (exactly one area/* per issue, area/cross-cutting alone, etc) are coded into both the AGENTS/CLAUDE.md guidance and the parser/UI logic. This is fine for Codev itself but bakes in a stylistic call (slash convention, single-axis taxonomy) that other teams adopting Codev may not share.

A side-by-side with anthropics/claude-code surfaced the relevant alternative pattern: four parallel keyed families (area:, platform:, api:, perf:) on the colon convention, plus a flat backbone of priority/type/triage labels. The keyed families are notionally orthogonal axes — an issue can be area:auth + platform:windows + api:bedrock + bug + high-priority, each label capturing an independent fact.

The takeaway isn't that Codev should copy that scheme. The takeaway is that the structural mechanism — discover classification families from label prefixes, treat them as first-class slicing dimensions — is general, and Codev's framework code can support it without imposing any particular taxonomy. Whatever a team's labels happen to be becomes their taxonomy, with zero framework code privileging any specific axis name.

What changes

Codev stops hardcoding area as the primary classification axis. The framework scans the repo's labels (at startup and on label changes), recognizes any label of shape <key>:<value> as a member of family <key>, and registers <key> as a discovered family. The set of families = whatever the team's labels define.

Concretely:

  • A project using area:* + platform:* + complexity:* gets three independent axes for free.
  • A project using a custom module:* + team:* scheme gets those families.
  • A flat-label project (no prefixes) sees the group-by-family toggle simply not appear.

Codev itself migrates from area/ to area: (manual relabel, since the convention has only been used locally so far). The slash form is dropped — no compat layer, no dual-delimiter parsing — because the dual support would carry permanent complexity for a one-time migration that's a few gh label edit calls away.

Three consumers

The discovered family registry feeds three surfaces:

  1. Group-axis toggle in Backlog and Builders views. Currently a binary areastage toggle; it becomes "any discovered family, plus stage". Default axis configurable per workspace; falls back to first-registered family when unset.

  2. Multi-axis filter in views that list issues or builders. Rows can be filtered by any combination of family=value predicates (e.g. area=vscode AND complexity=high AND platform=macos). One filter per family at most for v1; ranges / negation deferred.

  3. Routing-time family lookup. Protocols, spawn logic, and .codev/config.json can consult specific families without naming them in code. The first concrete consumer is codev: per-task complexity / per-protocol effort with cross-agent translation (complexity/* labels + harness flag emission) #998's complexity-to-effort routing: per-protocol config names which family it reads, what defaults to apply when the value is absent, and what value→behavior mapping to use.

Policy changes that fall out

Current Codev-specific area policies in CLAUDE.md / AGENTS.md become per-family configurable with sensible defaults:

  • Exactly-one-value-per-issue becomes per-family singleValued flag, default false. Codev's own area: family can keep singleValued: true if desired; other families opt in/out independently.
  • area/cross-cutting semantics dissolve. Cross-cutting issues either tag multiple values (where singleValued: false) or use a configured escape-hatch value (where singleValued: true). The literal value cross-cutting is no longer special to the framework.
  • The labels reference memory and the slash-convention rule become per-project documentation rather than framework-level constraints.

Relationship to #998

#998 (per-task complexity, per-protocol effort) depends on this mechanism for parsing complexity labels, but its design surface is unchanged. The bulk of #998 — which complexity values exist, per-protocol effort defaults, cross-agent effort translation (Claude --effort low|medium|high|xhigh|max vs Codex/Gemini/OpenCode equivalents), override grammar in .codev/config.json vs per-task — stays exactly as scoped. What moves into this issue is the parsing layer: read complexity:high off an issue, register complexity as a discovered family, expose its values to the routing-time lookup that #998 implements. #998's spec should reference this issue once it lands.

Out of scope (for this issue)

  • A codev migrate-labels command. Codev's own migration is manual.
  • Per-family icons / color schemes / rendering polish. This is structural; visual treatments can land separately if they prove useful.
  • Persisting per-user filter state across sessions. Out for v1; can layer on later.
  • Hierarchical families (area:vscode:sidebar). Out for v1; revisit if real cases emerge.

Why PIR (not SPIR)

Structurally a small generalization: swap a hardcoded family name for a dynamic registry. The mechanism itself is one regex plus a per-family policy schema. The footprint is wide (overview parser, Backlog view, Builders view, dashboard grouping, spawn routing hooks, CLAUDE/AGENTS docs, the area-labels memory), but each touch site is mechanical.

The plan-gate's value is in nailing the discovery semantics and policy schema before coding starts:

  • When is a family registered? On any label of matching shape? Open-issue labels only, or all labels including closed?
  • Cache invalidation when labels change?
  • Per-family policy fields: singleValued, defaultValue (when absent), escapeHatchValue (the cross-cutting equivalent), singleValuedExceptions?
  • Codev's own family policy: area: keeps singleValued: true with escapeHatchValue: cross-cutting? Or drop both and allow multi-area?
  • Migration sequencing: relabel Codev's repo first (area/* → area:*), then ship the framework change, or ship the framework first and relabel after.

These are decisions the plan phase should make explicit; the code follows.

Metadata

Metadata

Assignees

Labels

area/cross-cuttingTouches multiple areas — needs coordinated handling

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions