diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..76758ef --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,96 @@ +# AGENTS.md — devantler-tech/.github (GitHub-as-code) + +Conventions for AI agents and human contributors working in this repo. This is the **canonical** +instructions file (plain Markdown, read natively by GitHub Copilot — including **Copilot code +review** — Cursor, Codex, … and by Claude Code). It defers to the monorepo's root +[`AGENTS.md`](https://github.com/devantler-tech/monorepo/blob/main/AGENTS.md) for the **shared +engineering contract** (PR/commit conventions, trust gate, guardrails, draft-PR discipline); the +rules below are what's **specific to this repo**. + +## What this repo is + +Two unrelated things share one repo, by GitHub convention: + +1. **The org's public profile** — `profile/README.md` (rendered on the org page), plus the org-wide + community health files in [`.github/`](.github/) (`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, + `SECURITY.md`, issue/PR templates) and the shared [`workflow-templates/`](workflow-templates/). +2. **The org's declarative GitHub configuration** — [`deploy/`](deploy/), the **source of truth for + the devantler-tech org's GitHub state**, expressed as [Crossplane](https://crossplane.io) managed + resources via + [provider-upjet-github](https://github.com/crossplane-contrib/provider-upjet-github). + +On every `v*` tag, [`cd.yaml`](.github/workflows/cd.yaml) publishes `deploy/` as a **cosign-signed +OCI artifact** to `ghcr.io/devantler-tech/github-config/manifests`. The +[platform](https://github.com/devantler-tech/platform) cluster onboards it as the **`github-config` +tenant**, which verifies the signature and then has Flux + Crossplane **reconcile the live GitHub org +to match these manifests — including reverting out-of-band changes made in the GitHub UI or via +`gh api`**. See platform's +[`docs/github-management.md`](https://github.com/devantler-tech/platform/blob/main/docs/github-management.md) +for the architecture, the GitHub App credential setup, and the Observe-first adoption flow. + +## Golden rules (repo-specific) + +- **Manage GitHub declaratively — never imperatively.** Org / repo / team / label configuration is + changed **only** by editing `deploy/` and shipping a PR. Do **not** use `gh api` writes or the + GitHub UI to change managed config: the `github-config` tenant reverts out-of-band drift, so an + imperative change is at best a no-op and at worst churns against the reconciler. (Reading via + `gh api` is fine; *writing* managed config is not.) Applying an **existing** label to an issue is + triage (content, allowed); creating or editing a label **definition** is config (declarative-only). +- **Ownership goes to a team, not an individual.** The canonical owner across the suite is the + `maintainers` team — model access on `Team`/`TeamRepository`, never on individual logins. +- **Observe-first when adopting an existing resource.** A new `Repository`/`IssueLabels`/team CR for + an already-live object must adopt it without risk of recreate/delete: set the + `crossplane.io/external-name` annotation to the live name and use a management policy that + **excludes `Delete`** (observe/late-initialize), per platform's `docs/github-management.md`. Verify + the provider kind/field schema against the authoritative source + ([crossplane-contrib/provider-upjet-github `package/crds/`](https://github.com/crossplane-contrib/provider-upjet-github) + + `examples-generated/namespaced/`) — the CRs cannot be schema-validated locally (no cluster; CI + only runs `kubectl kustomize`). +- **`IssueLabels` is authoritative** (Terraform `github_issue_labels`): it declares a repo's + **complete** label set and **removes** any undeclared label. Before applying it to a repo with live + labels, enumerate that repo's existing labels (including Dependabot's `dependencies` / + `github_actions`, Renovate extras) so the declared set is a superset — or you will delete labels in + use. The canonical taxonomy lives once in [`deploy/labels/kustomization.yaml`](deploy/labels/) + (a shared patch appended to every repo); each `deploy/labels/.yaml` adds **only** that repo's + ecosystem extras. + +## `deploy/` layout + +| Path | Contents | +|---|---| +| `deploy/repositories/.yaml` | one `Repository` per managed repo (settings, merge/signoff, metadata) | +| `deploy/teams/` | the `maintainers` team and its `TeamRepository` → repo access bindings | +| `deploy/labels/.yaml` | one `IssueLabels` per repo; canonical taxonomy in `labels/kustomization.yaml` | +| `deploy/provider-config.yaml` | the provider-upjet-github `ProviderConfig` (App credentials) | +| `deploy/external-secret.yaml` | the `ExternalSecret` sourcing the GitHub App credentials | +| `deploy/kustomization.yaml` | top-level kustomization wiring the above + the shared repo-settings patch | + +## Maintenance + +The **roadmap of record** is GitHub Issues — epic [#56](https://github.com/devantler-tech/.github/issues/56) +("declarative GitHub-org-as-code") with `roadmap`-labelled children. Triage incoming issues into that +structure; implementing PRs use `Fixes #N`. + +**Validate before every PR** (the sole required check, `CI - Required Checks`, gates on this): + +```sh +kubectl kustomize deploy/ > /dev/null # must build clean; this is exactly what ci.yaml runs +``` + +`kubectl` (with built-in kustomize) is preinstalled on CI runners. A clean build proves the manifests +are well-formed; the Crossplane CRDs themselves are applied/validated **on-cluster** (the +`github-config` tenant), not in CI — so a green build is necessary but not sufficient, and any new CR +must be schema-checked against the provider's published CRDs (above). + +Repo-specific watch-list for the daily engineer: + +- **Drift / coverage.** New repos in the org, or org/repo/team settings changed in the UI, mean + `deploy/` is now behind reality. Bringing them under management (Observe-first) is `roadmap`/ + `enhancement` work — never a UI fix. +- **`cd.yaml` is the publish path**, triggered on `v*` tags only; `ci.yaml` produces the PR-time + required check. A red `cd.yaml` means the org-config OCI artifact didn't republish — investigate + before assuming the live org is in sync. +- **Agent-file freshness.** Keep this `AGENTS.md` in sync with the actual `deploy/` layout and the + shared contract. This repo does **not** carry a separate `.github/copilot-instructions.md` — Copilot + reads `AGENTS.md` directly, so a parallel review-only file would be redundant (per the root contract, + if one ever appears, delete it and fold anything unique here).