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 for the shared
engineering contract (PR/commit conventions, trust gate, guardrails, draft-PR discipline); the
rules below are what's specific to this repo.
Two unrelated things share one repo, by GitHub convention:
- The org's public profile —
profile/README.md(rendered on the org page), plus the org-wide community health files in.github/(CONTRIBUTING.md,CODE_OF_CONDUCT.md,SECURITY.md, issue/PR templates) and the sharedworkflow-templates/. - The org's declarative GitHub configuration —
deploy/, the source of truth for the devantler-tech org's GitHub state, expressed as Crossplane managed resources via provider-upjet-github.
On every v* tag, cd.yaml publishes deploy/ as a cosign-signed
OCI artifact to ghcr.io/devantler-tech/github-config/manifests. The
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
for the architecture, the GitHub App credential setup, and the Observe-first adoption flow.
- Manage GitHub declaratively — never imperatively. Org / repo / team / label configuration is
changed only by editing
deploy/and shipping a PR. Do not usegh apiwrites or the GitHub UI to change managed config: thegithub-configtenant reverts out-of-band drift, so an imperative change is at best a no-op and at worst churns against the reconciler. (Reading viagh apiis 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
maintainersteam — model access onTeam/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 thecrossplane.io/external-nameannotation to the live name and use a management policy that excludesDelete(observe/late-initialize), per platform'sdocs/github-management.md. Verify the provider kind/field schema against the authoritative source (crossplane-contrib/provider-upjet-githubpackage/crds/examples-generated/namespaced/) — the CRs cannot be schema-validated locally (no cluster; CI only runskubectl kustomize).
IssueLabelsis authoritative (Terraformgithub_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'sdependencies/github_actions, Renovate extras) so the declared set is a superset — or you will delete labels in use. The canonical taxonomy lives once indeploy/labels/kustomization.yaml(a shared patch appended to every repo); eachdeploy/labels/<repo>.yamladds only that repo's ecosystem extras.
| Path | Contents |
|---|---|
deploy/repositories/<repo>.yaml |
one Repository per managed repo (settings, merge/signoff, metadata) |
deploy/teams/ |
the maintainers team and its TeamRepository → repo access bindings |
deploy/labels/<repo>.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 |
The roadmap of record is GitHub Issues — epic #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):
kubectl kustomize deploy/ > /dev/null # must build clean; this is exactly what ci.yaml runskubectl (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) isroadmap/enhancementwork — never a UI fix. cd.yamlis the publish path, triggered onv*tags only;ci.yamlproduces the PR-time required check. A redcd.yamlmeans the org-config OCI artifact didn't republish — investigate before assuming the live org is in sync.- Agent-file freshness. Keep this
AGENTS.mdin sync with the actualdeploy/layout and the shared contract. This repo does not carry a separate.github/copilot-instructions.md— Copilot readsAGENTS.mddirectly, so a parallel review-only file would be redundant (per the root contract, if one ever appears, delete it and fold anything unique here).