overengineeringstudio / overengineeringstudio/effect-utils

Add `githubLabels` genie runtime helper

Open
#582 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

origin:agent type:agent-tooling type:feature
Dominant language
TypeScript
Stars
82
Forks
2
Avg merge
1d 8h
Merged PRs (30d)
121

Description

Proposal

Add a new runtime helper @overeng/genie/src/runtime/github-labels/ (parallel to the existing github-ruleset/) that emits a typed JSON manifest for a repo's labels, plus an applier task that syncs the manifest to GitHub via the gh label CLI.

The existing ruleset pattern is:

  • .genie.ts source → runtime helper → typed JSON artifact at .github/repo-settings.json
  • Applied via dt gh:apply-settings which shells gh api repos/.../rulesets/{id} --method PUT --input .github/repo-settings.json

This issue proposes the same shape for labels.

Motivation

Label taxonomies want to be version-controlled, diff-reviewable, and drift-checked — the same reasons branch rulesets already are. Currently labels drift silently across repos: a prefix-based taxonomy (type:*, state:*, origin:*, area:*) just got deployed across multiple repos via one-off gh label create commands, and there's no mechanism to keep them in sync or catch divergence.

Design

Runtime helper

New module packages/@overeng/genie/src/runtime/github-labels/mod.ts exporting:

export interface LabelSpec {
  name: string
  color: string        // hex, no leading '#'
  description?: string
}

export interface GithubLabelsArgs {
  labels: readonly LabelSpec[]
}

export const githubLabels: (args: GithubLabelsArgs) => GenieOutput

Emits .github/labels.json as a sorted array (deterministic output — sort by name for stable diffs).

.genie.ts usage
// .github/labels.json.genie.ts
import { githubLabels } from '../repos/effect-utils/genie/external.ts'
import { sharedLabels } from '../repos/effect-utils/genie/labels.ts'

export default githubLabels({
  labels: [
    ...sharedLabels,
    { name: 'area:ci', color: '...', description: 'CI-related' },
  ],
})

Shared labels (the type:* / state:* / origin:* axes) live in a shared module; per-repo .genie.ts files compose them with their own area:* entries.

Applier

New devenv task gh:apply-labels (or extend gh:apply-settings to cover both):

  • Fetch current labels: gh label list --json name,color,description --limit 500
  • Diff against .github/labels.json:
    • label in manifest but not in repo → create
    • label in both but color/description differ → update
    • label in repo but not in manifest → skip (additive default) or delete (with --prune)
  • Use gh label create --force for upsert (simpler than per-field PATCH via gh api)
Delete semantics

Destructive, so opt-in:

  • Default: additive. Manifest is a guaranteed subset; extras survive.
  • With --prune: strict. Manifest is authoritative; extras are deleted.

Rename handling is deferred — first version treats rename as destroy+create. A future rename: string field can be added to LabelSpec if needed.

Shared taxonomy module

Ship a repos/effect-utils/genie/labels.ts with the shared axes that downstream repos can import:

export const sharedLabels: LabelSpec[] = [
  { name: 'type:epic',     color: '1D76DB', description: 'Large tracking issue with child tasks' },
  { name: 'type:rca',      color: '5319E7', description: 'Root cause analysis tracking' },
  // ... etc for the 10 already-deployed labels
]

Acceptance criteria

  • New github-labels runtime helper under packages/@overeng/genie/src/runtime/github-labels/ with tests
  • Exported from @overeng/genie public surface + from repos/effect-utils/genie/external.ts
  • .github/labels.json.genie.ts in the effect-utils repo itself as the first consumer
  • dt gh:apply-labels devenv task (or extended gh:apply-settings) that:
    • Creates missing labels
    • Updates mismatched color/description
    • Leaves extras alone by default
    • Deletes extras with --prune
    • Is idempotent on repeat runs
  • Shared taxonomy module exportable to downstream consumers (schickling/dotfiles + schickling/megarepo-all will adopt after)
  • Works with the private-repo + public-repo variants both

Non-goals

  • GitHub issue templates (separate helper)
  • GitHub environment secrets (separate helper)
  • Label renames (deferred)

References

  • Existing pattern: packages/@overeng/genie/src/runtime/github-ruleset/mod.ts
  • Downstream consumer planned: schickling/dotfiles (has the 10-label taxonomy already deployed)
  • Label taxonomy doc in downstream repo: nixpkgs/ai/rules/workflow.md — "Label taxonomy" subsection

Posted by 🧬 cl1-helix on behalf of @schickling · 6cfe014f-38bd-46cf-90ac-18cbd4dc034f@mbp2025

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading packages/@overeng/genie/src/runtime/github-ruleset/mod.ts and the existing @overeng/genie public exports, then inspect the devenv task behind dt gh:apply-settings. Add the github-labels runtime helper, effect-utils consumer, shared taxonomy export, and applier behavior described in the acceptance criteria; verify creation, updates, additive defaults, --prune deletion, and idempotent repeat runs.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, typescript
Domain
devops, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.