Organization-wide defaults for repositories in the havit-internal organization.
GitHub treats a repo named exactly .github in an org specially: any repo that
does not define its own version of these files falls back to what lives here.
That gives the whole org consistent issue templates, PR templates, community
health files, and a canonical label set with zero per-repo work.
.github/
├── ISSUE_TEMPLATE/
│ ├── feature.yml ← Outcome-level container; rolls up Stories
│ ├── bug_report.yml ← "Something broken" — Environment + Details required
│ ├── user_story.yml ← "As a … so that …" with acceptance criteria
│ ├── task.yml ← Implementation slice with definition-of-done
│ └── config.yml ← Disables blank issues
├── pull_request_template.md ← Issues / Refs — see QA convention below
├── labels.yml ← Source of truth for sev:*/status:*/meta labels (work type is an Issue Type, not a label)
└── workflows/
└── qa-routing.yml ← Reusable workflow — see "PR convention" below. Label sync / CI still planned.
plugins/
└── gh-issue-templates/ ← Claude Code plugin — see "Claude Code plugin" below
| Repo | Role |
|---|---|
havit-internal/.github |
Fallback files: issue templates, PR template, labels.yml. Reusable workflows also live here, under .github/workflows/ (qa-routing.yml built; label sync and CI still planned). |
havit-internal/002.HFW-NewProjectTemplate-Blazor |
GitHub template repo for new Blazor projects. Not org-wide — covers the Blazor stack specifically, not every repo type. |
Templates from this repo are inherited by every repo in the org that does
not define its own. Workflow files are not inherited — a reusable workflow
defined here still has to be called explicitly from a thin wrapper in each
consuming repo (uses: havit-internal/.github/.github/workflows/<name>.yml@main).
No separate workflows repo is needed for this — reusable workflows can be
called from any repo, including this one. If workflow versioning or ownership
ever needs to diverge from the templates/labels here, split them out then;
until that's a real need, keeping everything in one repo is simpler.
Fallback is all-or-nothing per repo. As soon as a repo defines any issue template of its own (even one), the org defaults stop applying to that repo entirely — they do not merge with local templates.
Prefer keeping repos with zero local templates so they inherit the full set defined here.
- Feature — outcome-level container. Not implemented directly; holds Stories.
- Story — a vertical, user-facing slice of a Feature. The unit that gets planned and delivered.
- Task — an implementation-level piece of a Story.
- Bug — unplanned work; can reference a parent Story or Feature via "Related work" but doesn't require one.
Each template's "parent" field is manual (plain issue number, not GitHub's native sub-issue linking) — link them explicitly and use sub-issues where it helps navigation.
Work type (feature / story / task / bug) is not a label — it's set via
GitHub's native org-level Issue Types (org Settings → Issue types),
which sync to every repo automatically with no workflow needed. Task,
Bug, and Feature are already configured on the org; Story still needs
to be added there to match user_story.yml, which already sets type: story.
The issue templates set their Issue Type via the top-level type: key in
each .github/ISSUE_TEMPLATE/*.yml file (not the labels: key). labels.yml
below is only for things Issue Types don't cover: severity, workflow status,
and triage/meta labels.
labels.yml is the canonical list for severity (sev:*), status (status:*),
and meta labels (needs-triage, blocked, etc.) — everything that isn't a
work type. Planned: a scheduled label-sync workflow, living in this
repo's own .github/workflows/, will apply it to every repo in the org. That
workflow does not exist yet, so today this file is documentation only —
labels must be applied to each repo manually until it's built. Do not create
ad-hoc labels in individual repos — edit this file and open a PR.
The qa-routing workflow (see below) piggybacks on GitHub's own closing
keywords instead of inventing a separate one. Use Closes #N, Fixes #N,
or Resolves #N — anywhere in the PR description, one or several
comma-separated (Fixes #10, #11) — for every issue this PR fixes. GitHub
auto-closes those issues on merge, and the workflow, in the same run,
relabels them status:ready-for-qa and assigns everyone in
.github/QAOWNERS, so the issue doesn't just quietly close — it still gets
a QA pass.
Closes #N/Fixes #N/Resolves #N— This PR fixes issue N. Closed by GitHub and routed to QA on merge.Refs #N— Related issue, no action. Cross-link only, not auto-closed, not routed to QA.
The keyword has to sit immediately next to the issue number(s), same as
GitHub's own matching — prose like "this fixes a bug, see #123" (keyword not
adjacent to the #N) or a bare #123 doesn't trigger either the auto-close
or the QA routing.
.github/workflows/qa-routing.yml is a reusable workflow. It does not run on its own —
each consuming repo needs a thin wrapper that triggers it on merge:
# .github/workflows/qa-routing.yml (in the consuming repo)
name: QA routing
on:
pull_request:
types: [closed]
jobs:
route-to-qa:
if: github.event.pull_request.merged == true
permissions:
issues: write
contents: read
uses: havit-internal/.github/.github/workflows/qa-routing.yml@main
with:
runner: '["ubuntu-latest"]' # optional — defaults to this. JSON array
# of runner labels, e.g. '["self-hosted","on-prem"]'What it does on merge:
- Scans the PR body for
Closes/Fixes/Resolves #Nreferences. No matches → no-op. - For each linked issue, strips any existing
status:*label and addsstatus:ready-for-qa(handles the qa-rejected → refix → re-verify loop cleanly, since the old status is always replaced, not stacked). - Assigns everyone listed in that repo's
.github/QAOWNERS— see below. - Leaves a comment on the issue linking back to the merged PR.
.github/QAOWNERS format (lives in each consuming repo, not here):
one GitHub username per line, @ optional, # for comments, blank lines
ignored:
# QA owners for this repo — all are assigned on every merge
@alice
@bob
If a repo has no QAOWNERS file, the workflow still relabels the issue
status:ready-for-qa but leaves it unassigned (logged as a warning in the
workflow run) — so repos can adopt this incrementally rather than needing
QAOWNERS set up before merges work at all.
This repo doubles as a Claude Code plugin marketplace (.claude-plugin/marketplace.json).
It currently ships one plugin, gh-issue-templates, with a skill that creates
GitHub issues matching the actual template a target repo renders (including
the all-or-nothing inheritance gotcha above) — field order, labels, and
native Issue Type — instead of a freeform title/body.
Install once, works in any repo:
/plugin marketplace add havit-internal/.github
/plugin install gh-issue-templates
Everything in this repo affects every repo in the org. Open a PR, get review from at least one other maintainer, and merge. Changes take effect immediately for any repo that doesn't override.