Golden repo

The reference git repository: a gathering place for the rules a well-run repo follows, distilled from the projects that work (repository-blueprint, the digital garden, ocli, oncall). Each section states the rule and where it’s proven; gaps are explicitly open — this note grows as rules are gathered.

Structure

  • Context-system directories (from repository-blueprint/, the scaffold all new projects start from): _specs/ (implementation specs, NNNN-slug), _questions/ (active.md + answered.md), _decisions/ (ADR-style, YYYY-MM-DD-topic), _learnings/, _research/ — plus user-facing docs/.
  • Quick orientation in AGENTS.md — read order for session start (specs → questions → decisions → learnings), out-of-default-context files listed separately.
  • Python projects: uv toolchain — uv tool install over pipx/apt, .venv/bin/python for services, uv.lock committed.
  • (open: canonical layout for src/tests separation, name-length limits, monorepo vs multi-repo rule)

AI-assisted coding structure

  • AGENTS.md is the contract — context system + workflow rules in the repo root, loaded by the agent at session start.
  • Spec completion gate: a spec is not done until frontmatter status: done + _specs/README.md index matches + git status clean. Mismatched state wastes tokens rediscovering finished work.
  • No tautological tests — expected values from a spec, real fixture, or hand-computed result; never the code’s own output.
  • Scratch/working dirs (e.g. _scratch/) gitignored so agent experiments never pollute the tree.
  • (open: progressive-disclosure docs for agent skills? task/plan file conventions? review gates before merge?)

Git flow

  • Short-lived feature branches → main; trunk-based for solo projects.
  • Commit meaningful chunks — finished work (docs, specs, code, tests) is committed immediately, never left dirty in the tree (spec gate depends on it).
  • (open: when a PR is required vs direct-to-main; branch naming; merge vs rebase)

Conventional commits and semver

  • Conventional commits (feat:, fix:, docs:…) where the team follows them — CMT repos use them with ticket prefixes (CM-/CMT-); COT ps-ansible deliberately does not (legacy repo, not worth the churn).
  • Changelog/version tooling (candidates):
    • git-cliff (OSS) — Rust changelog generator from conventional commits (+ regex custom parsers for non-CC repos), Tera templates, and a version-bump mode (semver from commit history — covers part of the semver policy below). The conventionalcommits.org-listed reference.
    • Alternatives to evaluate: conventional-changelog (JS ecosystem, what semantic-release uses), semantic-release (full auto-release: CI publishes + versions + changelog from commits), Commitizen (interactive CC commits), git-changelog-command-line (Java), release-please (Google, PR-based releases), git-sumi (Rust, CC linting — pairs with git-cliff).
    • Workflow insight from git-cliff users: squash-merge keeps noise out of main; the decision of what appears in the changelog moves from release time to commit time; auto-generated changelog is a draft, release notes remain human.
    • changesets (OSS) — a different school, not a git-cliff alternative: instead of deriving the changelog from commit history, contributors add a small markdown “changeset” file per PR declaring the bump type (patch/minor/major) + release note; consuming them bumps versions, writes CHANGELOG.md and publishes. Monorepo-first (dependent packages bumped in lockstep, grouped releases), but the concept works for single-package repos too. No conventional-commits requirement at all.
    • The axis between them: where does the release decision live — commit messages (git-cliff/semantic-release school: zero workflow overhead, any language, requires CC discipline) vs PR-time intent files (changesets/release-please school: explicit, reviewable in the PR, monorepo-aware, but an extra file per PR). Monorepo or polyglot-registry publishing → changesets wins; single-package any-language repo with CC discipline → git-cliff is lighter.
  • (open: semver policy — when does minor bump vs patch; pre-release handling; which of the tools above, if any)

Tags

  • (open: tag on release vs on merge; annotated vs lightweight; do tags drive the CI release job or follow it)

Pre-commit hooks

Full landscape lives in Git hooks (the dedicated note: distribution mechanisms, manager comparison, design rules). The golden-repo-relevant rules:

  • Real-world pattern (digital garden): a project script (frontmatter.py check) wired via .git/hooks/ symlink — validates what the project actually cares about (YAML blocks, key contracts), not generic hygiene.
  • The hook may fix (insert missing keys, bump updated) on staged files — but only one frontmatter-writer per pass.
  • Tool landscape (candidates, not yet chosen):
    • prek (OSS) — Rust, drop-in pre-commit replacement: same .pre-commit-config.yaml + hook registry, parallel, millisecond startup, built-in in-place fixes. The registry + isolation without Python.
    • pre-commit (Yelp) — the incumbent: largest hook ecosystem, isolated envs per hook, autoupdate; cost = Python required + slow first run.
    • Husky — the JS standard: hooks as plain shell scripts in .husky/, wired by npm prepare (clone + npm install = hooks live); no parallelism or staged-filtering without lint-staged.
    • Lefthook — Go single binary: lefthook.yml, native parallel execution, built-in {staged_files} glob filtering, local overrides file. The polyglot performance option.
    • Hand-written core.hooksPath + bootstrap script — zero deps, transparent shell scripts; underrated for simple needs.
    • Git ≥2.54 native config hooks ([hook "x"] in gitconfig) — new (2026-04); solves personal/global hooks, not team distribution (.git/config not versioned).
    • Supply-chain angle: every manager adds an install-time execution surface; pre-commit’s per-hook repos add the most (moving tags) — --freeze (immutable SHAs) mitigates.
    • Measured (third-party benchmarks, 500+ files): lefthook warm <1s; husky+lint-staged 2-3s; pre-commit 4-6s (venv overhead). prek claims pre-commit parity at lefthook-class speed.
  • hk (OSS) — the jdx (mise author) entry, 1.2k★ Rust: linters/formatters run in parallel under read/write file locks (independent tools concurrent, same-file tools take turns), and — the differentiator — the same steps run in git hooks, from the terminal, and in CI. One config, three contexts: kills the “hooks pass locally but CI checks something else” drift that plague per-context configs.
  • (open: pick per project type — prek for pre-commit config reuse, hk for hooks=CI unification with lock-based parallelism, lefthook for pure speed? decision pending hands-on: prek vs hk — details and design rules in Git hooks)

CI/CD

  • (open: lint+test on PR, deploy on tag? self-hosted Gitea runners vs Forgejo actions vs external CI; artifact/version publication flow)
  • Supply-chain hardening reference (Cilium’s CI/CD security writeup, captured 2026-09-27) — the layer-by-layer checklist any serious CI should be measured against:
    • Who triggers builds: allow-list (their in-house Ariane bot: only org members, enumerated workflows, /test dispatch)
    • Trusted vs untrusted code: two-phase checkouts for pull_request_target — load actions/scripts/signing from the reviewed base branch, PR head is build context only, never executed; untrusted data flows into exactly one validating action; only CI-scope credentials on the runner
    • Who reviews CI changes: CODEOWNERS — .github/ owned by a security-focused team; nobody silently changes the pipeline
    • Dependencies: every uses: pinned to a 40-char SHA, images by @sha256: digest, Renovate keeps pins fresh with a 5-day minimum-release-age cooldown (attack window for yanked releases); Go deps vendored + reviewed as diffs
    • Static analysis: CodeQL enforces explicit permissions: per workflow, actionlint for unsafe patterns, expression-injection detection in run: blocks
    • Credentials: CI pushes to -ci tags only; production creds behind a protected release environment requiring maintainer approval
    • Consumers: cosign keyless OIDC signing + SBOM attestations on every image/chart
    • Deliberate non-choice worth copying: they don’t fork third-party actions (stale forks are their own vulnerability; SHA pinning already gives mutability-free immutability); and “a little copying is better than a little dependency” — shrink the tree, review gets easier, benefits compound
  • The agentic-CI bottleneck (2026-09 arc, Depot’s synthesis captured) — Anthropic (test-impact-analysis couldn’t keep up with job volume), Linear (12-layer optimization stack: tsgo, oxlint, blobless checkouts, filtered installs over cache, schema snapshots vs migration replay, balanced shards), Lindy (stratospheric CI spend) all conclude: agents made code volume cheap and CI the logjam. “A five-person team can generate the code of a 500-person team” — but validation didn’t scale with it. Death by a thousand papercuts, not one big fix. The reframe worth keeping: CI exists to build trust, and validation is moving to where code is generated — agents running real CI (API/CLI-driven, ad-hoc workflows, selective steps) before commit; then: skip post-commit CI for already-validated changes, dynamic test selection from source, prod outcomes fed back into the trust loop. Pairs with Self-hosted CI-CD (the infrastructure question) and Agent tests (the validation question).
  • The local-CI counterpoint: gh-signoff (OSS) (Basecamp, 2.1k★, MIT, shell) — “bring CI back in-house”: run tests on your own machine, gh signoff posts the green (or gh signoff fail red) GitHub commit status. “Dev laptops are fast, chronically underutilized, and already owned; cloud CI is slow, expensive, and rented.” Same diagnosis as Depot (CI cost/ceremony ballooned past what most apps need), opposite resolution: not smarter remote CI but no rented CI at all — trust the team’s discipline, keep branch protection via required signoff statuses. The trust question again, answered with human attestation instead of pipelines. Fits between the Depot piece and pre-commit hooks on the validation-spectrum: hooks (free, local, skippable) → signoff (local, attested, branch-gating) → remote CI (repeatable, parallel, rented) → agent-driven CI (Depot’s bet).

Tests

  • No tautological tests (see above) — the one hard rule already enforced vault-wide.
  • Agent tests: for agent-written code, E2E-first with a verifiable repeatable artifact; failure-mode-list-first for isolation tests; never write unit tests after the code.
  • (open: coverage expectations; test pyramid for CLI/TUI projects; fixture strategy)

Linting

  • Markdown notes: no hard line-wrap, one paragraph one line (rendering reason: mid-paragraph newlines become breaks).
  • Python: linter on save where it exists (obsidian-linter pattern); syntax check after every scripted edit.
  • (open: ruff config, shellcheck, yamllint, formatters vs linters policy)

Docs directory

  • User-facing docs in docs/ (Diátaxis + Blume style), separate from the _-machinery context system which is for agents/contributors, not users.
  • README.md = project index, short; details live in docs/.
  • (open: docs-as-code builds, when a docs site graduates from repo docs)

Open questions

  • Which rules are universal vs per-project (the golden repo is a reference, not a straitjacket — ps-ansible’s no-conventional-commits is a legitimate local override)?
  • Does the golden repo become a real golden template repo (repository-blueprint v2 with CI/lint/hooks pre-wired), or stays a checklist?