Thanks for taking a look. This template's harness is the product, so the contribution flow is opinionated — every change goes through the same gates as a feature.
main ◄── release PR ◄── develop ◄── feat/123-short-name
◄── fix/124-bug-name
◄── chore/125-config-change
mainis the release line. Protected: 21 required status checks, code-owner approval, no force pushes. (One additional non-required check,Draft next releasefrom release-drafter, runs informationally on PRs tomainand shows up in the rollup but is not gated.)developis the integration branch. Same 21 gates, less strict (PRs don't need rebases).- Feature branches are short-lived and named
<type>/<issue-number>-<kebab-title>. Open one issue per branch so the project board stays usable.
Seven prefixes (enforced in three places — [tool.commitizen] in pyproject.toml, pr-title.yml, check_commit_types.py):
| Prefix | When |
|---|---|
feat: |
New capability |
fix: |
Bug fix |
docs: |
Documentation only |
test: |
Tests / eval harness |
refactor: |
Internal change with no behaviour delta |
chore: |
Tooling, deps, infra |
release: |
develop → main release PRs only |
The subject is lowercase after the colon. Title Case prose (Add the thing) is rejected; all-caps initialisms (CI failure, SDK upgrade) are fine.
- Open the issue first. Use a feature/bug template; fill every section.
- Branch off
developwith the matching name. - If your team uses Beads, mirror or claim the linked issue in the local Beads queue after the issue exists. Beads track local ready/blocked execution only; GitHub Issues remain canonical for scope, discussion, PR linkage, and closure.
- Land one logical change per PR. Stack PRs if the work is naturally split.
- The PR template asks five things — answer each (
Noneis valid where applicable):- What & why (1–3 lines)
- Test plan (checkbox list; CI covers most of it)
- Invariants affected — cite numbered rules from
docs/INVARIANTS.md - New deps / actions / external surface (anchor for supply-chain review)
- Screenshots (UI changes only)
- Wait for green CI + a code-owner review before merging.
Transitional — only while this repo has a single code owner. Standard practice is a code-owner review on every PR. The flow below exists because GitHub forbids self-approval, so a single-owner repo cannot satisfy the "1 code-owner review" gate any other way. The exemption is removed the moment a second collaborator with merge rights joins.
This repo currently runs with a single code owner (* @constk in CODEOWNERS). While in this state, the intended merge command is:
gh pr merge <N> --admin --squash --delete-branch…for feat: / fix: / chore: PRs, and --admin --merge (preserves history) for release: PRs. The enforce_admins: false line in .github/branch-protection/{develop,main}.json is the documented escape hatch — admin merge here is the documented single-owner workaround, not bypass of the gates (every required status check still has to pass).
When the exemption ends. As soon as a second collaborator with merge rights is onboarded:
- Drop the
--adminflag from the merge command and adopt standard PR review. - Remove this entire subsection.
- Update
CODEOWNERSto add the new collaborator. - Flip
enforce_adminstotruein the branch-protection JSON for both branches. Leaving itfalsewould keep the admin-bypass door open even after the single-owner workaround is no longer needed — defeats the point of removing the workaround.
All four changes land in a single PR.
This repo enforces LF line endings via .gitattributes (* text=auto eol=lf)
and the pre-commit hygiene hook. If you cloned on Windows with
core.autocrlf=true, the first checkout after pulling the .gitattributes
change can leave the working tree out of sync with the index. Renormalise
once:
git add --renormalize .
git commit -m "chore: renormalise line endings"After that, day-to-day work is unaffected.
This repo enforces LF line endings via .gitattributes (* text=auto eol=lf)
and the pre-commit hygiene hook. If you cloned on Windows with
core.autocrlf=true, the first checkout after pulling the .gitattributes
change can leave the working tree out of sync with the index. Renormalise
once:
git add --renormalize .
git commit -m "chore: renormalise line endings"After that, day-to-day work is unaffected.
just check # ruff + mypy + import-linter + pytest
cd frontend && npm run lint && npm run format:check && npm run check && npm run test && npm run build
uv run pre-commit run --all-filesA green pre-push run is a high-confidence predictor of a green CI run. The just check gate is intentionally a subset of CI — fast feedback over coverage.
When the harness grows a new gate:
- Add the workflow job in
.github/workflows/. - If it's a required gate, add the job's display name to the
contextsarrays in.github/branch-protection/{develop,main}.json. - If it's NOT required (scheduled / dispatch-only / push-to-main-only), add the workflow filename to
EXEMPT_WORKFLOWSin.github/scripts/check_required_contexts.py. - Update
docs/HARNESS.mdanddocs/SECURITY.md(if security-relevant). - Land in one PR — the meta-gate
Branch-protection contexts syncwill fail if you skip step 2 or 3.
Be kind. Disagree on substance, not on people. If review feedback gets sharp, take it offline and come back when both sides are ready.
If you find a vulnerability that affects users of the template, do not open a public issue. Email the maintainer (see commit history for contact). Include:
- Repro steps
- Affected version / commit SHA
- Severity assessment (informational / low / medium / high / critical)
- Suggested fix if you have one
We'll acknowledge within 72 hours.