From 5d64e8f83d4b01e547db2bc2ffc12685ec05048f Mon Sep 17 00:00:00 2001 From: Christopher Jon Pitzi Date: Sat, 3 Oct 2026 22:12:48 -0400 Subject: [PATCH] The fleet's central CodeRabbit configuration, with a schema check Co-Authored-By: Claude Fable 5.1 --- .coderabbit.yaml | 157 ++++++++++++++++++ .github/CODEOWNERS | 1 - .github/dependabot.yml | 22 --- .github/workflows/claude-code-review.yml | 40 ----- .github/workflows/claude.yml | 33 ---- .github/workflows/validate.yml | 21 +++ CLAUDE.md | 33 ---- README.md | 106 ++++-------- SETUP.md | 102 ------------ assets/banner.svg | 105 ------------ ci/validate.py | 39 +++++ docs/adr/0001-template-as-file-scaffold.md | 61 ------- .../0002-governance-baked-in-structurally.md | 77 --------- docs/adr/README.md | 56 ------- 14 files changed, 251 insertions(+), 602 deletions(-) create mode 100644 .coderabbit.yaml delete mode 100644 .github/CODEOWNERS delete mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/claude-code-review.yml delete mode 100644 .github/workflows/claude.yml create mode 100644 .github/workflows/validate.yml delete mode 100644 CLAUDE.md delete mode 100644 SETUP.md delete mode 100644 assets/banner.svg create mode 100644 ci/validate.py delete mode 100644 docs/adr/0001-template-as-file-scaffold.md delete mode 100644 docs/adr/0002-governance-baked-in-structurally.md delete mode 100644 docs/adr/README.md diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..0a8b362 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,157 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +# +# Lentago Labs — CodeRabbit central configuration. +# +# This file lives in lentago/coderabbit and is inherited by every repository in +# the org that does not carry its own .coderabbit.yaml. Repo-level files win +# outright (configuration sources do not merge), so a repo that needs something +# different copies this file and edits it, rather than adding a one-line override. +# +# The intent: CodeRabbit is a second reviewer, not a gate. It never blocks a +# merge, it never rewrites a PR description (the fleet's PR body becomes the +# squash commit message and stays the author's), and it reads the fleet's own +# rules so its comments agree with them. + +language: en-US + +tone_instructions: >- + Specific and brief: file and line, the defect or risk in one sentence, the fix + when short. No praise, no restating the diff, no style nits unless they hide + a bug. Judge reader-facing Markdown by the Lentago voice guide. + +reviews: + profile: chill + request_changes_workflow: false + + # The summary goes in the walkthrough comment, never into the PR description. + high_level_summary: true + high_level_summary_in_walkthrough: true + collapse_walkthrough: true + changed_files_summary: true + sequence_diagrams: false + poem: false + estimate_code_review_effort: true + assess_linked_issues: true + related_issues: true + related_prs: true + suggested_labels: true + auto_apply_labels: false + suggested_reviewers: false + auto_assign_reviewers: false + + auto_review: + enabled: true + drafts: false + # Dependabot's bumps are reviewed by the required checks, not by prose. + ignore_usernames: + - "dependabot[bot]" + + # Generated or harvested trees: reviewing them is noise, and a hand-edit to + # them already fails CI in the owning repo. + path_filters: + - "!**/brand/generated/**" + - "!**/demo/generated/**" + - "!**/fleet-reports/fleet-report.md" + - "!**/fleet-reports/incidents.md" + - "!**/metrics/language-census.md" + - "!**/package-lock.json" + - "!**/*.lock" + - "!**/.terraform.lock.hcl" + - "!**/node_modules/**" + - "!**/dist/**" + - "!**/build/**" + + path_instructions: + - path: "**/*.tf" + instructions: >- + Infrastructure as code for the lentago estate and for kits that run in a + client's own accounts. Flag: any IAM Allow with "*" resources where the + service supports ARNs; any role that can modify its own permissions, + policy, or permissions boundary; secrets or keys in variables, locals, + state, or environment blocks; a new repository or role created without + the fleet's rails (prevent_destroy, archive_on_destroy, OIDC trust using + the immutable repo:@/@ subject for repos created after + mid-2026); anything that would change a live surface outside this + repository without being codified here. + - path: "**/.github/workflows/*.yml" + instructions: >- + Fleet rule: a workflow whose check is REQUIRED on main must not be + path-filtered at the on: level, or it deadlocks every non-matching PR; + filter inside the job instead. Flag: broad permissions blocks (prefer + the minimum per job), third-party actions not pinned to a major, secrets + echoed to logs, workflows that push or open PRs with GITHUB_TOKEN (the + org forbids Actions creating PRs by default), and any step that mutates + a Terraform-enforced surface outside its owning repo. + - path: "**/*.md" + instructions: >- + Reader-facing prose follows lentago/.github docs/voice.md: written for one + reader (a nonprofit's one tech person), second person, plain words, every + term of art defined in the sentence where it first appears, costs and + times stated plainly, every claim about the fleet linked to the repo, + file, or PR that proves it. Flag the retired words: "dogfooding", + "training ground", "curriculum", "trainee", "the lab", "colleagues", + "book a consult", "org membership". Records (ADRs, incident reports, + fleet reports) keep a neutral factual voice and are exempt from the + register, not from accuracy. + - path: "**/CLAUDE.md" + instructions: >- + Operating notes for the fleet's agents. They must NOT restate the + fleet-wide PR workflow, attribution, or live-state rules (canonical in + lentago/shared-workflows CLAUDE.md); flag restatements and anything that + contradicts the canonical text. + - path: "core/**/*.py" + instructions: >- + In lentago/uvularia this is code a client runs in CI: Python 3.12 + standard library only, readable by a non-programmer. Flag any new + import outside the standard library, any check that cannot fail (no + fixture proves it red), any path where missing data renders as success + rather than "no data", and any publish-time value derived from an + author's clock instead of the server-side receipt. + - path: "templates/**" + instructions: >- + Client-facing templates: nothing Lentago-specific may appear (no + hostnames, account ids, container ids, estate names). Everything must + work in a stranger's org with a free GitHub account; flag assumptions + about org settings, labels, secrets, or paid plans that a fresh repo + would not have. + + tools: + shellcheck: + enabled: true + actionlint: + enabled: true + yamllint: + enabled: true + markdownlint: + enabled: true + ruff: + enabled: true + gitleaks: + enabled: true + tflint: + enabled: true + hadolint: + enabled: true + + pre_merge_checks: + title: + mode: warning + requirements: >- + Imperative, specific, under 72 characters, and matching or refining the + issue title it closes. + description: + mode: warning + +chat: + auto_reply: true + +knowledge_base: + opt_out: false + learnings: + scope: global + code_guidelines: + enabled: true + filePatterns: + - "**/CLAUDE.md" + - "lentago/.github:docs/voice.md" + - "lentago/shared-workflows:CLAUDE.md" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index a96ed77..0000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @cpitzi diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 09247e7..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: 2 -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: weekly - open-pull-requests-limit: 5 - # Grouping collapses weekly churn into at most two PRs per ecosystem while - # keeping the risk split visible in the PR list itself: the "-routine" PR - # is reviewable on green checks, and the "-major" PR is where breaking - # changes land and gets read deliberately. One group for everything would - # hide a major bump inside a pile of patches; no grouping produces a - # flood of individual PRs (see lentago/.github#114). - groups: - actions-routine: - applies-to: version-updates - patterns: ["*"] - update-types: ["minor", "patch"] - actions-major: - applies-to: version-updates - patterns: ["*"] - update-types: ["major"] diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml deleted file mode 100644 index 2e25045..0000000 --- a/.github/workflows/claude-code-review.yml +++ /dev/null @@ -1,40 +0,0 @@ -# ============================================================================ -# Claude Code — Automated PR Review -# ============================================================================ -# Thin wrapper around lentago/shared-workflows/claude-review.yml. -# Pinned to Haiku. -# -# >>> CUSTOMIZE THE review_prompt BELOW FOR THIS REPO. <<< -# Do NOT ship the placeholder. A copy-pasted prompt that describes the wrong -# repo is worse than none — it points the reviewer at the wrong rubric. The -# good fleet examples (betula, drosera, -# reference-checker) each describe their OWN content. -# Also review `paths-ignore`: if markdown is this repo's product, do NOT -# ignore "*.md". -# ============================================================================ - -name: Claude Code Review - -# >>> DISABLED 2026-06-25: automated Claude PR review turned off fleet-wide. -# Trigger changed from `pull_request` to manual `workflow_dispatch` only, so it -# never auto-runs on PRs. The repo-specific review_prompt below is preserved. -# To re-enable, restore the `on: pull_request` trigger (see git history). -on: - workflow_dispatch: - -jobs: - claude-review: - permissions: - contents: read - pull-requests: write - issues: write - id-token: write - uses: lentago/shared-workflows/.github/workflows/claude-review.yml@v1.2.2 # v1.2.1 - secrets: inherit - with: - review_prompt: | - REPLACE THIS PLACEHOLDER. Describe what THIS repository is (one or two - sentences), then list the 4–6 dimensions the reviewer should focus on, - each as a bolded category with a short explanation. Tailor to the - repo's actual content (e.g. Terraform/AWS, HA YAML, bash scripts, - markdown prose, Python). See the fleet for working examples. diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml deleted file mode 100644 index 37d537a..0000000 --- a/.github/workflows/claude.yml +++ /dev/null @@ -1,33 +0,0 @@ -# ============================================================================ -# Claude Code — Interactive @claude Responder -# ============================================================================ -# Thin wrapper around lentago/shared-workflows/claude-responder.yml. -# Generic across the fleet — no per-repo customization needed. -# ============================================================================ - -name: Claude Code - -on: - issue_comment: - types: [created] - pull_request: - types: [opened, synchronize, labeled] - pull_request_review_comment: - types: [created] - pull_request_review: - types: [submitted] - issues: - types: [opened, edited, labeled, assigned] - -jobs: - claude: - permissions: - contents: write - pull-requests: write - issues: write - id-token: write - actions: read - uses: lentago/shared-workflows/.github/workflows/claude-responder.yml@v1.2.2 # v1.2.1 - secrets: inherit - with: - allowed_tools: '"Bash(git add:*)" "Bash(git commit:*)" "Bash(git checkout:*)" "Bash(git switch:*)" "Bash(git push:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git branch:*)" "Bash(gh pr create:*)" "Bash(gh pr merge:*)" "Bash(gh pr view:*)" "Read" "Edit" "Write"' diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..841051d --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,21 @@ +# validate — .coderabbit.yaml against CodeRabbit's published schema, on every PR. +# No on:-level path filter: this is the repo's required check (the fleet's +# required-check deadlock rule). +name: validate + +on: + pull_request: + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: pip install --quiet pyyaml jsonschema + - run: python3 ci/validate.py diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index ecc4978..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,33 +0,0 @@ -# CLAUDE.md — [repo name] - -> Read [README.md](README.md) for the full project pitch. This file is -> operational notes for Claude: what the artifacts are, where outputs land, and -> the conventions to respect. Fleet-wide rules (PR workflow, attribution) live -> in `~/repos/CLAUDE.md` and should NOT be restated here — call out only this -> repo's deviations. - -## Persona — introduce yourself - -When Claude initializes in this directory, open the first response with a brief -self-introduction as **[Repo] Claude** — [one-line role]. One sentence is -plenty; don't make a meal of it. - -## What this repo is - -[One short paragraph: the purpose, the "build system" (or "there is no build -step"), and the shape of the work.] - -## Artifacts / layout - -| Path | Purpose | -|---|---| -| `[path]` | [what it is] | - -## Conventions to respect - -- [Repo-specific convention.] -- [Repo-specific convention.] - -## When in doubt - -- [Where to look for X.] diff --git a/README.md b/README.md index 84c0f98..ebe091a 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,45 @@ - -repo-template — Fleet scaffold · README, CLAUDE.md, CI wrappers +# coderabbit — the fleet's CodeRabbit defaults -[![main](https://img.shields.io/github/check-runs/lentago/repo-template/main?style=flat-square&labelColor=0e2b1a&color=1b4b2e&label=main)](https://github.com/lentago/repo-template/actions) [![License](https://img.shields.io/github/license/lentago/repo-template?style=flat-square&labelColor=0e2b1a&color=1b4b2e)](https://github.com/lentago/repo-template/blob/main/LICENSE) [![Ask DeepWiki](https://img.shields.io/badge/Ask-DeepWiki-1b4b2e?style=flat-square&labelColor=0e2b1a&logo=readthedocs&logoColor=E0A81C)](https://deepwiki.com/lentago/repo-template) +This repository holds one file that matters: [`.coderabbit.yaml`](.coderabbit.yaml). +CodeRabbit reads it as the **central configuration** for the `lentago` organization: +every repository that does not carry its own `.coderabbit.yaml` inherits it +([how central configuration works](https://docs.coderabbit.ai/configuration/central-configuration)). -![Template](https://img.shields.io/badge/Template-1b4b2e?style=flat-square&labelColor=0e2b1a) ![MIT](https://img.shields.io/badge/MIT-1b4b2e?style=flat-square&labelColor=0e2b1a) +**What it sets, and why** -# [repo name] +- CodeRabbit is a second reviewer, **never a gate**: it does not block merges and is + not a required status check anywhere in the fleet. Required checks are the ones + that can fail deterministically; a slow external review in that set would stall + auto-merge. +- The high-level summary goes into the **walkthrough comment**, not the PR + description. In this fleet the PR body becomes the squash commit message and + stays the author's words. +- Generated trees are excluded (`brand/generated/`, `demo/generated/`, the harvested + fleet reports, lockfiles). A hand-edit to any of those already fails CI in the + owning repo. +- Path instructions carry the fleet's own rules so its comments agree with them: + least privilege and self-protecting boundaries in Terraform; the + required-check deadlock rule for workflows; the voice guide for reader-facing + Markdown; standard-library-only code in uvularia's core; nothing + Lentago-specific in client templates. +- The voice guide and the canonical PR-workflow text are read as code guidelines + from their source repos, so there is one copy of each. -[One-paragraph description of what this repo is and who it's for.] +**Overriding for one repository** -**Authorship:** [Adjust to fit, but keep a co-authorship disclosure at the -top.] The [code / prompts / documentation] in this repo are co-written with -[Claude](https://claude.ai) (Anthropic). I direct the work and review the -output; Claude writes the [code / prose]. I'm an infrastructure operator, not a -software engineer — please don't read this repo as a portfolio of coding -ability. +Configuration sources do not merge. A repository that needs different settings +copies this file in as its own `.coderabbit.yaml` and edits it; that file then +wins outright. -## 📚 Ask this codebase (DeepWiki) +**Checking what a PR actually resolved to** -Ask DeepWiki +Comment `@coderabbitai configuration` on any pull request. CodeRabbit replies with +the resolved YAML, annotated with the source of every value. -> [DeepWiki](https://deepwiki.com/lentago/repo-template) maintains an AI-generated wiki over this -> repository — architecture pages, diagrams, and a Q&A box grounded in the actual code. Every -> public Lentago Labs repo is indexed ([deepwiki.com/lentago](https://deepwiki.com/lentago)); -> it is the fastest way to orient before reading source. It is AI-generated: trust it to orient -> you, verify against the code before you act on it. +**Changing fleet-wide behaviour** -**Good first questions:** - -- What does creating a new repo from repo-template actually copy, and what do I still have to configure by hand afterward? -- Why is the docs-check workflow deliberately not path-filtered, and what would break if I added a paths filter to it? -- Why was the claude-code-review.yml automated PR review disabled, and how would I re-enable it? - -## 🧭 What this repo demonstrates - -The paved road: every Lentago Labs repo starts here and inherits these patterns on day one. - -| Pattern | How it shows up here | -|---|---| -| Required status check via thin reusable-workflow wrapper | [`.github/workflows/docs-check.yml`](.github/workflows/docs-check.yml) delegates to `lentago/shared-workflows/docs-check.yml@main`; the branch ruleset requires the `docs-check / docs-check` context — change the logic once upstream and all repos inherit it | -| Deliberately non-path-filtered required check | `docs-check.yml` header comment explains: a path-filtered required check that never fires is held "Expected" forever, deadlocking every non-matching PR — the hard lesson from [lentago/.github#57](https://github.com/lentago/.github/issues/57) | -| Branch ruleset: squash-only, PR required, no force-push/deletion | Per-repo ruleset `lentago/repo-template` — textbook PR-gated change control where the merged PR is the change record; settings-as-code branch protection operators can point to as a live example | -| `@claude` interactive responder wired via reusable workflow | [`.github/workflows/claude.yml`](.github/workflows/claude.yml) wires an AI agent into the PR/issue lifecycle as a callable teammate, not a one-off script | -| Automated review deliberately disabled with an auditable off-switch | [`.github/workflows/claude-code-review.yml`](.github/workflows/claude-code-review.yml) switched to `workflow_dispatch` only on 2026-06-25 — toggling automation off is itself a reviewable, git-tracked decision ([PR #2](https://github.com/lentago/repo-template/pull/2)) | -| Settings-as-code is external to the template | [`SETUP.md`](SETUP.md) step 2: branch protection, merge-button, and topics are applied by `dotgithub/fleet-ops/fleet-apply.sh` after creation — a GitHub template copies files, not settings | -| Generated brand header with a do-not-hand-edit contract | The HTML comment above the banner: regenerate from `lentago/.github → brand/generate.py`, never hand-edit — single source of truth upstream, consumers regenerate rather than drift | -| Mandatory co-authorship disclosure baked into the template | The `**Authorship:**` block above ensures every derived repo opens with an AI co-authorship disclosure — structural governance, not an optional per-repo choice | - -## 🛠️ Make a change yourself - -These systems are real, and nothing critical rides on them. That makes this a -safe place to try a change before you make the same kind of change in your own -shop. Pick one: - -**Spin up a new repo compliant on day one (the paved road)** - -Click "Use this template" on this repo to create a new lentago repo. The template copies `README.md`, `CLAUDE.md`, `SETUP.md`, the CI wrappers, `LICENSE`, and `assets/` verbatim — but not settings. Fill in the README/CLAUDE.md placeholders and replace the `review_prompt` placeholder in [`claude-code-review.yml`](.github/workflows/claude-code-review.yml) with a description of your repo's content. Then run `dotgithub/fleet-ops/fleet-apply.sh --apply --repo ` to inherit squash-only merge, branch protection, and org topics. Replace `assets/banner.svg` via `lentago/.github`'s `brand/generate.py`, add the repo to `~/repos/CLAUDE.md`'s fleet inventory, delete `SETUP.md`, and open a PR with those changes. No apply-on-merge automation runs against the template itself — compliance is enforced by the `docs-check` required status check plus the org's fleet-baseline ruleset. Org membership is required to push branches; the fleet-apply script requires access to `dotgithub/fleet-ops/`. - -**Proof this works:** -- [PR #9 — Adopt the shared docs-check workflow](https://github.com/lentago/repo-template/pull/9) — wires the template into the required docs-check check pattern every new repo inherits -- [PR #3 — Repoint reusable-workflow refs to the lentago org](https://github.com/lentago/repo-template/pull/3) — shows the template's CI wrappers being repointed after an org rename, evolving the shared base every new repo starts from -- [PR #1 — Update SETUP.md fleet-ops paths to dotgithub/fleet-ops/](https://github.com/lentago/repo-template/pull/1) — keeps the settings-application step accurate for every repo created from the template - -## What's here - -- [Key file / directory] — [purpose] -- [Key file / directory] — [purpose] -- [Architecture decisions](docs/adr/) — ADR log; two seed records reconstructed from repo history - -## [How it works / Usage] - -[Fill in.] +Open a pull request here. The file is validated against CodeRabbit's published +schema in CI before it can merge. --- @@ -79,10 +47,4 @@ Click "Use this template" on this repo to create a new lentago repo. The templat > run on volunteers, donations, and one overworked tech person. Everything here > is free to take, and we practice what we publish: our own estate runs this > way, in the open. Start at the [org profile](https://github.com/lentago), and -> read this repo on [DeepWiki](https://deepwiki.com/lentago/repo-template). - - +> read this repo on [DeepWiki](https://deepwiki.com/lentago/coderabbit). diff --git a/SETUP.md b/SETUP.md deleted file mode 100644 index 13f9a56..0000000 --- a/SETUP.md +++ /dev/null @@ -1,102 +0,0 @@ -# Post-create setup (delete this file when done) - -A GitHub template copies **files, not settings**. After creating a repo from -`repo-template`, the file skeleton is in place but the repo is on GitHub -defaults. Apply fleet settings, then delete this file. - -## 0. Write the repo description - -Every Lentago Labs repo description follows a tiered template. The invariant -across all tiers: **the repo's function appears in the first five words after -the name, and no quality adjectives** ("robust", "modern", "clean", etc.). - -| Tier | Template | -|---|---| -| **Platform products** | ` — the Lentago Labs : . .` | -| **Sites** | `Site content for — ; on the solidago AWS stack (OIDC → ECR/ECS/ALB).` | -| **Tools & config** | `. .` | -| **Kit templates** | `Template: kit — runs entirely in your org's own accounts; .` | - -Set the description in the repo's About panel (or via `gh repo edit -lentago/ --description "..."`) before your first PR. - -## 1. Fill in the skeleton - -- `README.md` — name, description, keep the Claude co-authorship disclosure at - the top. -- `CLAUDE.md` — persona, what-this-repo-is, conventions. -- `.github/workflows/claude-code-review.yml` — **replace the placeholder - `review_prompt`** with one written for THIS repo. Do not ship the boilerplate. - -The skeleton also ships these files that are ready to use as-is: - -- `.github/dependabot.yml` — weekly Dependabot updates for GitHub Actions - (github-actions ecosystem only; add npm/pip blocks if the repo gains manifests). - Third-party action pins in workflows will be auto-PRed when new versions drop. - -## 2. Apply fleet settings - -If the **org-level `fleet-baseline` ruleset** exists (see -`dotgithub/fleet-ops/`), branch protection is already inherited automatically — -skip the per-repo ruleset. Otherwise, and for the merge-button/topics that -rulesets don't cover, run the fleet script from `~/repos`: - -```bash -dotgithub/fleet-ops/fleet-apply.sh --apply --repo -``` - -That sets squash-only merge + auto-merge + delete-branch-on-merge and ensures -the `lentago` + `claude` spine topics. Add this repo's signature topics by -hand: - -```bash -gh repo edit lentago/ --add-topic ... -``` - -## 3. Replace the brand banner - -`assets/banner.svg` is the repo-template banner copied from `lentago/.github`. Replace it with one generated for your repo: add the new repo name to `brand/fleet.json` in `lentago/.github`, run `python3 brand/generate.py --repo `, and copy the resulting `brand/generated//banner.svg` into `assets/`. - -## 4. Add the repo to the fleet inventory - -Add the new repo name to the Lentago Labs org list in `~/repos/CLAUDE.md`. - -## 5. Know the canonical locations - -For any content you add to a new repo, use these paths — they're where the -fleet expects to find things: - -| Content | Canonical path | Notes | -|---|---|---| -| Architecture decision records | `docs/adr/` | Nygard style, numbered (`0001-title.md`). | -| Agent instructions | `CLAUDE.md` | One file at the repo root. | - -Some existing repos use other paths for historical reasons. Those are not being -churned — these locations are the convention for **new repos** only. - -## 6. Keep the skeleton current (anti-drift) - -Whatever the fleet standardizes — pinned action SHAs, a grouped -`dependabot.yml`, security headers for site repos, required status checks — -must land in this skeleton in the **same wave** as the sweep that introduces -it. Template drift silently un-standardizes every future repo: a new repo -created the day after a fleet sweep will miss whatever didn't make it into the -skeleton. - -The skeleton currently carries: - -- `.github/dependabot.yml` — weekly GitHub Actions updates, grouped into - `actions-routine` (minor/patch) and `actions-major` (major) to make breaking - bumps reviewable at a glance. -- CI wrappers that delegate to `lentago/shared-workflows@main` — no - third-party action references to pin at this layer; pinning lives inside the - shared workflows. - -When you run a fleet-wide sweep, open a follow-up PR against this repo in the -same sprint. - -## 7. Delete this file - -```bash -git rm SETUP.md && git commit -m "Remove template setup notes" && git push -``` diff --git a/assets/banner.svg b/assets/banner.svg deleted file mode 100644 index ff0fd98..0000000 --- a/assets/banner.svg +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ◆ LENTAGO LABS · FLEET - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - repo-template - FLEET SCAFFOLD · README, CLAUDE.MD, CI WRAPPERS - - - ▲ lentago gh repo create --template · files, not settings - - - - diff --git a/ci/validate.py b/ci/validate.py new file mode 100644 index 0000000..86c38f8 --- /dev/null +++ b/ci/validate.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Validate .coderabbit.yaml against CodeRabbit's published schema. + +The schema is fetched at run time (https://coderabbit.ai/integrations/schema.v2.json) +so the check tracks CodeRabbit's current options; a network failure is reported +as such rather than passed. Exit 0 on valid, 1 on invalid or unreachable. +""" +import json +import sys +import urllib.request + +try: + import yaml + import jsonschema +except ImportError as exc: # pragma: no cover + print(f"missing dependency: {exc.name} (pip install pyyaml jsonschema)", file=sys.stderr) + sys.exit(1) + +SCHEMA_URL = "https://coderabbit.ai/integrations/schema.v2.json" + +def main() -> int: + try: + with urllib.request.urlopen(SCHEMA_URL, timeout=30) as r: + schema = json.load(r) + except Exception as exc: + print(f"could not fetch the CodeRabbit schema: {exc}", file=sys.stderr) + return 1 + with open(".coderabbit.yaml", encoding="utf-8") as fh: + cfg = yaml.safe_load(fh) + errors = sorted(jsonschema.Draft202012Validator(schema).iter_errors(cfg), key=lambda e: list(e.path)) + for e in errors: + print(f"INVALID at {'/'.join(str(p) for p in e.path) or '$'}: {e.message}") + if errors: + return 1 + print(".coderabbit.yaml is valid against the current CodeRabbit schema") + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/docs/adr/0001-template-as-file-scaffold.md b/docs/adr/0001-template-as-file-scaffold.md deleted file mode 100644 index 4757389..0000000 --- a/docs/adr/0001-template-as-file-scaffold.md +++ /dev/null @@ -1,61 +0,0 @@ -# ADR-0001: Template repo carries files; org settings are applied externally - -**Status:** Accepted (2026-06-14; reconstructed 2026-08-13) - -## Context - -GitHub's "Use this template" creates a new repository by copying the template's files verbatim. -It does not copy repository settings — branch protection, squash-only merge button, topics, and -related configuration are not part of what GitHub transfers. Without an explicit post-create step -every derived repo starts on GitHub defaults, which fall short of fleet requirements. - -The fleet needed a repeatable way to apply consistent settings to every new repo without per-repo -manual drift. - -## Decision - -Split the scaffold into two halves: - -1. **File half** — `repo-template` ships the file skeleton: `README.md`, `CLAUDE.md`, `SETUP.md`, - CI workflow wrappers, `LICENSE`, and `assets/`. These are inherited automatically on - "Use this template." - -2. **Settings half** — applied externally after creation by running - `dotgithub/fleet-ops/fleet-apply.sh --apply --repo `, which sets squash-only merge, - auto-merge, delete-branch-on-merge, and org topics. `SETUP.md` documents this step and is - deleted from each derived repo once setup is complete. - -Evidence (verified against current repo): - -- `SETUP.md` line 3: "A GitHub template copies **files, not settings**." -- `SETUP.md` step 2: the `fleet-apply.sh` invocation. -- `README.md` patterns table: "Settings-as-code is external to the template — SETUP.md step 2." -- PR #1 (merged 2026-06-20) confirms the two-part design pre-dates that PR; #1 only corrected - a stale path in SETUP.md (`~/repos/fleet-ops/` → `dotgithub/fleet-ops/`) without changing the - design. - -## Alternatives - -**GitHub Actions `repository` creation trigger** *(retrospective — not considered at the time)* — -Fire `fleet-apply.sh` automatically when a new repo is created from the template. Removes the -manual step, but requires a long-lived org-level token with admin write access and a persistent -actor to run the workflow. *Worse*: standing admin credentials to save one documented manual -step — and the fleet's later settings-as-code Terraform path closed the same gap without them. - -**Cookiecutter / Copier** *(retrospective — not considered at the time)* — Both tools support -parametrized scaffolding (named slots, interactive prompts, conditional sections) and can run -post-generate hooks. They require the CLI installed on the operator's machine and are off the -GitHub-native "Use this template" creation path. Copier additionally supports template upgrades -post-creation. *Lateral*: better parametrization and upgrade story, but neither tool eliminates -the settings gap — GitHub repository settings are not managed by copier/cookiecutter without a -custom post-hook, so the two-half problem remains. Loses the zero-install, browser-accessible -creation flow. - -## Consequences - -- Every new repo requires a manual post-create step before it is fully fleet-compliant. `SETUP.md` - is the reminder; it is deleted once setup is done. -- `SETUP.md` must stay accurate as fleet-ops paths evolve. PR #1 is a recorded instance of that - maintenance cost. -- The template itself is always compliant by definition. `fleet-apply.sh` is the single - enforcement point for settings-as-code. diff --git a/docs/adr/0002-governance-baked-in-structurally.md b/docs/adr/0002-governance-baked-in-structurally.md deleted file mode 100644 index c677d3d..0000000 --- a/docs/adr/0002-governance-baked-in-structurally.md +++ /dev/null @@ -1,77 +0,0 @@ -# ADR-0002: Template ships governance as structure, not convention - -**Status:** Accepted (2026-06-14, reinforced 2026-06-25; reconstructed 2026-08-13) - -## Context - -Every repo derived from this template is co-authored with Claude (Anthropic). The fleet needed -three guarantees without relying on per-repo discipline: - -1. AI co-authorship is disclosed in every derived repo. -2. Automated CI behaviour that touches pull requests is an explicit, reviewable decision — not a - default that silently runs on every PR. -3. The template's boilerplate `review_prompt` in `claude-code-review.yml` must be replaced before - the automated review runs. A prompt written to describe the template repo will review every - derived repo on the wrong rubric; the file comment documents this as the known failure mode. - -## Decision - -Bake governance into the template's file structure rather than document it as a convention: - -1. **Authorship disclosure** — The `**Authorship:**` block is included in `README.md` with - fill-in instructions. Omitting it requires a deliberate deletion, not merely skipping a - checkbox. (Present at initial commit, 2026-06-14.) - -2. **Auditable CI off-switch** — `claude-code-review.yml` was switched from `pull_request` to - `workflow_dispatch` trigger via PR #2 (merged 2026-06-25). The decision is git-tracked with a - dated comment directly in the workflow file: `>>> DISABLED 2026-06-25`. Re-enabling automated - review requires a deliberate PR restoring the trigger — the off-state is not silent default, - it is a visible, reviewable fact. - -3. **Do-not-ship-boilerplate guard** — `claude-code-review.yml` is prominently headed with - `>>> CUSTOMIZE THE review_prompt BELOW FOR THIS REPO. <<<`, and `SETUP.md` step 1 explicitly - calls out: "Do not ship the boilerplate." The workflow comment states: "A copy-pasted prompt - that describes the wrong repo is worse than none — it points the reviewer at the wrong rubric." - -Evidence (verified against current repo): - -- `README.md` lines 13–18: the `**Authorship:**` block with fill-in instructions. -- `.github/workflows/claude-code-review.yml` lines 7–13: boilerplate warning; - line 18: `DISABLED 2026-06-25` comment; line 23: `workflow_dispatch` trigger. -- PR #2 (merged 2026-06-25): "Disable automated Claude PR review (manual-only trigger)" — - confirmed merged; PR body records this as part of a fleet-wide change. - -## Alternatives - -**CONTRIBUTING.md convention** *(retrospective — not considered at the time)* — A conventions -document listing the authorship disclosure requirement and review configuration steps. *Worse*: -easy to miss; provides no structural enforcement — the exact failure mode shipping the structure -avoids. - -**CI lint check** *(retrospective — not considered at the time)* — A workflow that asserts the -authorship block is present and detects the boilerplate `review_prompt`. *Lateral*: stronger -than a comment, but adds CI complexity and requires maintaining detection heuristics as the -boilerplate text changes. (`fleet-apply.sh` later grew a boilerplate-prompt scan, covering part -of this from the settings side.) - -**Leave automated review enabled by default** *(the recorded prior state — replaced by PR #2)* — -Keeps the automated review running on every PR so issues are surfaced without manual invocation. -The specific problem: if the `review_prompt` is still the placeholder when a derived repo opens -its first PR, review runs against the wrong rubric. Enabling review-by-default without solving -the boilerplate problem first amplifies the failure mode rather than discouraging it. *Worse* -for the stated goal of ensuring review is useful before it runs. - -**New-repo issue template as setup checklist** *(retrospective — not considered at the time)* — -A GitHub issue template pre-opened on repo creation that lists customisation steps including -updating the `review_prompt`, closed when complete. More visible than a comment in a workflow -file; still optional since nothing prevents closing the issue without completing all steps. -*Lateral*: adds a task-management surface for the setup checklist without providing structural -enforcement of any individual step. - -## Consequences - -- New repo authors encounter the authorship block and the boilerplate warning in the first files - they open; neither can be missed silently. -- Automated review is off by default; re-enabling is a deliberate PR, not an accidental trigger. -- The auditable off-switch pattern (a dated disable comment + `workflow_dispatch` trigger) is - itself now a fleet pattern, documented in this repo's README as a live example. diff --git a/docs/adr/README.md b/docs/adr/README.md deleted file mode 100644 index 735f91a..0000000 --- a/docs/adr/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Architecture decision records - -The decisions below were reconstructed on 2026-08-13 from **this template repository's own** -commit history, merged pull requests, and CLAUDE.md contents. Dates in each record reflect the -original decision date, not the reconstruction date. Evidence anchors (PR numbers, file lines) -have been verified against the current repo state; anything that could not be confirmed is marked -uncertain. - -> **Scaffolding note — for repos created from this template:** ADRs 0001/0002 and their index -> rows document the template repo itself, not your new repo. On setup (see `SETUP.md`), delete -> those two records and their rows, keep this file as your repo's ADR log, and use the format -> guide below for your own decisions. - -## Index - -| ADR | Title | Status | Date | -|---|---|---|---| -| [0001](0001-template-as-file-scaffold.md) | Template repo carries files; org settings are applied externally | Accepted | 2026-06-14 | -| [0002](0002-governance-baked-in-structurally.md) | Template ships governance as structure, not convention | Accepted | 2026-06-14 | - ---- - -## How to add an ADR to this repo - -Create `docs/adr/NNNN-.md` and add a row to the index above. Use this structure: - -```markdown -# ADR-NNNN: - -**Status:** Accepted (<date>) - -## Context - -Why was a decision needed? What constraints and forces were in play? - -## Decision - -What was decided, and how does it address the context? - -## Alternatives - -List the options that were actually weighed, then add one or two marked -*"retrospective — not considered at the time"* with an honest assessment -(worse / better / lateral) and a short reason. - -## Consequences - -What does this decision make easier or harder going forward? What are the -known trade-offs or scars? -``` - -**Recorded vs. retrospective alternatives:** Alternatives that were actually weighed at decision -time go in the list without special marking. Options added later for completeness must be -explicitly labelled *"retrospective — not considered at the time"* so future readers know they -were not part of the original deliberation. Honest assessment (worse / better / lateral) is -required — do not present retrospective options as neutral.