Files
hips/HIPs/hip-0517-branch-naming.md
zooqueenandzeekay fdba791a43 Stop YAML reading HIP numbers as octal, and point the links at real files
HIP-0065 rendered as "HIP-53" on the site. YAML 1.1 reads a
leading-zero integer as octal, so `hip: 0065` parsed as 0o65 — decimal
53. 130 of the 140 HIPs are written with leading zeros, so most of the
corpus was displaying a number nobody assigned it. The numbers are
quoted now: an identifier is written 0065 and read 0065.

Every "Edit on GitHub" and "View Raw" link 404'd — all 140. They were
built as `HIPs/hip-${hip}.md`, but the files carry a slug
(hip-0065-backup-disaster-recovery-standard.md) which cannot be derived
from the number. The real filename is carried through from the loader
and used instead.

"Requires: HIP-HIP-0027" came from prefixing values that already
carried the prefix. The renderer adds it only when it is missing, and
splits a comma-separated string rather than printing it whole.

(cherry picked from commit 6f9fd22d249000aa2ab35255b2ab1fa2056c45b7)
2026-09-03 23:40:14 -07:00

4.0 KiB

hip, title, author, type, category, status, created
hip title author type category status created
0517 Branch Naming — main is the Trunk, Everywhere Hanzo AI Team Process Meta Living 2026-07-27

HIP-0517: Branch Naming — main is the Trunk, Everywhere

Preamble

A branch name is not a preference. It is an address that automation resolves: CI triggers on it, GitOps Applications pin targetRevision to it, release gates check it, mirrors sync it, and every README that says "clone and go" assumes it. When the address varies per repo, every one of those systems needs a per-repo exception, and the exception is invisible until the day it silently does nothing.

This HIP fixes the address. Across Hanzo, Lux, and Zoo the trunk is main.

The state this was written from

A survey of 1,190 non-archived repositories across hanzoai, hanzo-apps, hanzo-templates, luxfi, lux-apps, zooai, zoo-apps, zenlm, luxcpp and hanzo-js:

default branch repos
main 1066
master 108
develop / dev 8
a leftover feature or CI branch 5
none (empty repo) 2

The tail is the part that matters. Five repositories have a transient branch as their default — luxfi/pqclean on fix-sphincs-duplicate-consistency, zenlm/zen-private on fix-ci-1782365623, luxcpp/papers on fix-ci-1782355258, luxfi/cggmp21.rs on m, luxfi/verkle on account-leaf. A throwaway branch became the thing every clone, every CI run and every dependency resolution reads first. Nobody chose that; it is what happens when the trunk has no name the tooling can assume.

Specification

1. The trunk is main

Every repository in every Hanzo, Lux, and Zoo organization has a default branch named main. Not master, not develop, not trunk, and never a feature or CI branch.

This applies to repositories we own. Upstream forks keep whatever the upstream uses on the branches that track upstream — but our own default branch is still main, because that is the branch our tooling reads.

2. dev is the only other long-lived branch, and it is optional

A repository that needs an integration branch uses exactly one, named dev. develop is not a synonym; pick one spelling or the tooling needs two.

Most repositories should not have one. Feature branches integrate into main rapidly; a long-lived dev that drifts is a merge debt that compounds, and the hanzoai/templates case below shows what the end state looks like.

3. Feature branches are <kind>/<subject>

feat/, fix/, chore/, docs/. No dates in branch names — a date in a branch name is a comment that cannot be updated and is wrong by the second commit.

4. A feature branch may never become a default branch

If a default branch is ever observed pointing at a fix/*, feat/* or a CI- generated name, that is an incident, not a preference: it means a force-push or a branch deletion took the trunk with it.

5. Renaming is a rename, not a re-push

Use the rename operation, which moves open pull requests and installs a redirect:

gh api -X POST repos/<org>/<repo>/branches/master/rename -f new_name=main

Do NOT create main as a fresh branch beside master and switch the default. That produces two branches with unrelated histories in one repository, and every later merge fails with refusing to merge unrelated histories. This is not hypothetical — see below.

The failure this prevents

hanzoai/templates carries both. master held 30 commits main lacked; main held 7 commits master lacked; the two shared no common ancestor. master is the submodule-based catalog with 68 .gitmodules entries. main is a flattened rewrite with no .gitmodules at all and a flatten-apps.sh explaining the intent.

Both are real work. Neither is stale. The repository cannot merge them, and no tool can tell which one a reader should trust — git will happily serve either. That is the cost of creating main alongside master instead of renaming, and it is unrecoverable without a human deciding which history is canonical.