skip to content

Across 200 GitHub repos in one org, how do you keep issue triage consistent?

level: principalimportance: nice to knowfreq 24%

answer

  1. Nothing inherits between repositories by default
  2. One specially named repository holds the defaults
  3. Cross-repo visibility has exactly one native home
  4. Labels need reconciling, not documenting
  5. The rotation matters more than the taxonomy

basics

~20 s

Accept that GitHub labels, milestones and templates are repository-scoped, then centralise what it offers: default issue templates in the org's .github repository, organisation-level Projects that span repos, and a scripted label taxonomy applied through the API.

solid answer

~50 s

Three levers, in order of leverage. **Intake**: a `.github` repository in the organisation can hold default community health files, including `.github/ISSUE_TEMPLATE/`, which any repository without its own inherits — one place to change the bug form for two hundred repos. **Aggregation**: labels and milestones stop at the repository edge, so cross-repo visibility has to come from **organisation-level Projects**, which hold items from any repository and add their own `Status`, `Priority` and iteration fields on the project item. **Normalisation**: there is no label inheritance, so a shared taxonomy is maintained by script against `POST /repos/{owner}/{repo}/labels` — treat it as configuration in a repository, applied on a schedule. Then keep the taxonomy small. The failure at this scale is never too few labels; it is fifty per repo that nobody filters by. Standardise the handful triage actually reads and let teams own the rest.

code

text · 9 lines
text
.github/                      <- repository literally named .github
  profile/README.md
  CONTRIBUTING.md
  SECURITY.md
  .github/
    ISSUE_TEMPLATE/
      bug_report.yml          <- inherited by repos with no template of their own
      feature_request.yml
      config.yml

go deeper

for a junior

Know that GitHub labels, milestones and issue templates belong to a single repository, and that an organisation-owned .github repository can supply default templates to repositories that lack their own.

for a middle

Explain each mechanism's scope: template inheritance from the .github repository, no inheritance for labels, and organisation-level Projects as the only native cross-repository view.

for a senior

Show the operational shape — reconcile a small shared label set through the labels API on a schedule, feed a triage project with auto-add filters, and know that deleting a label strips it from every issue that had it.

for a principal

Own the tradeoff between central consistency and team autonomy: standardise only the handful of labels reporting depends on, invest in a named triage rotation and a response-time commitment, and measure the queue rather than the taxonomy.

## The structural problem GitHub's issue primitives were designed for one repository. **Labels** are repository objects — two repos with a `bug` label have two unrelated labels that share a name and probably not a colour. **Milestones** are repository objects with no organisation-level counterpart. **Issue templates** are read from a repository's default branch. Nothing inherits by default. At two hundred repositories, that means two hundred independently drifting configurations unless something pushes against the drift. So the design question is not "which labels should we use" but "which of GitHub's few org-scoped mechanisms carry the weight, and what must be scripted". ## Lever one: the .github repository An organisation can own a repository literally named `.github`. Files placed there act as **defaults** for every repository in the organisation that does not define its own: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`, and — the one that matters here — `.github/ISSUE_TEMPLATE/` including `config.yml`. This is genuine inheritance rather than a copy: change the bug form once and every repository without a local override serves the new one. It shapes **intake**, which is where consistency is cheapest to buy. A form that requires a version and a severity dropdown produces comparable issues across two hundred repositories without any triager doing extra work. Repositories with genuinely different needs override locally, and that override is visible as a file in their tree. Caveat worth stating: defaults apply only where the repository has no file of its own, and the picker still reads from each repository's default branch. ## Lever two: organisation-level Projects A Project owned by the organisation can contain issues and pull requests from **any** repository in it, and the fields you define — `Status`, `Priority`, `Team`, iteration, target date — live on the project item. That makes an org Project the only native cross-repository view GitHub offers, and the only place a question like "what is every P0 across the platform group" has an answer. Two patterns work at scale. A **triage project** with an auto-add rule per repository, filtered to `is:issue is:open label:needs-triage`, gives one queue for the rotation to work down. A **per-programme project** aggregates the work for an initiative regardless of which repositories it touches. Both compose with the repositories' own labels, since `Labels`, `Milestone` and `Repository` are built-in read-through fields on the item. The limit is honest: auto-add rules are configured per project per repository, so wiring two hundred of them is itself a scripting job, and project field values are invisible to anyone reading the plain issue list. ## Lever three: scripted normalisation For labels there is no inheritance, so the taxonomy has to be *applied*. The durable pattern is to store the canonical set as a file in one repository and reconcile it with a scheduled job that calls the labels API — `POST /repos/{owner}/{repo}/labels` to create, `PATCH` to fix colour and description drift. Deletions want a human in the loop, because deleting a label silently strips it from every issue that carried it. Reconcile only the **shared** subset: the labels triage and reporting depend on. Every repository will grow local labels, and that is fine — the mistake is trying to own all of them centrally, which produces a taxonomy so large nobody can hold it in their head and therefore nobody applies it correctly. ## Newer surfaces, stated carefully GitHub has been adding organisation-scoped issue metadata — notably organisation-level **issue types**, which define a shared set of types (such as bug, feature, task) usable across the organisation's repositories rather than per-repo labels. This area is actively evolving, so treat any specific capability as something to verify against current documentation rather than to assert in an interview. The durable point stands regardless: prefer whatever GitHub scopes to the organisation over anything you must replicate two hundred times. ## What actually decides success Mechanism is the smaller half. At this scale the constraints are social: - **Ownership of the queue.** A triage rotation with a named owner per area beats any label scheme. Without it, a perfectly normalised backlog still ages. - **A response contract, not a resolution contract.** Commit to triaging within a window, not to fixing. It is keepable, and it is what reporters actually want. - **Small taxonomy, ruthlessly pruned.** If a label has not been filtered on in a quarter, it is decoration. - **Measure the queue, not the labels.** Time-to-first-triage and untriaged age tell you whether the system works; label counts tell you nothing. A candidate who reaches for the `.github` repository, org Projects and a reconciliation script — and then says the hard part is owning the rotation — has done this before.

  • Why can't you just define the label set once at the organisation level?
    Labels are repository objects; two repositories sharing a name share nothing else. GitHub seeds new repositories with a default set, but there is no live inheritance afterwards, so a shared taxonomy is maintained by reconciling each repository through the labels API. Keep that reconciled subset small — only what triage and reporting actually filter on.
  • What breaks if you delete a drifted label during reconciliation?
    Deleting a label removes it from every issue that carried it, silently and irreversibly, so historical filters and saved searches stop matching. Renaming preserves the association; deletion does not. Automate creation and colour or description fixes, and keep deletions behind a human review.
  • How do you give a stakeholder one view of an initiative spanning forty repositories?
    An organisation-level Project. It holds items from any repository in the organisation, adds `Status`, `Priority` and target-date fields on the project item, and renders them as a table, board or roadmap. Feed it with auto-add rules per repository or an action, since nothing aggregates repositories automatically.
  • What metric tells you the triage system is working?
    Time to first triage and the age distribution of the untriaged queue. Both measure whether a human looked at a report and routed it, which is the promise you can actually keep. Counting labels, or open issues in total, measures activity rather than responsiveness and improves when people simply stop filing.

saying these in an interview costs you the question

  • Assumes labels or milestones are shared across an organisation
  • Designs a fifty-label taxonomy nobody will apply
  • Believes an org project auto-includes every repository
  • Treats template defaults as overriding a repository's own files
  • Deletes drifted labels without noticing issues lose them

context