Governance
How Eigenoid manages repository naming, lifecycle, configuration, and merge strategy across the organization.
For full decision rationale, see ADR-0007 (lifecycle) and ADR-0011 (naming).
Repository naming convention
Every repository follows a prefix-based naming scheme:
<category>-<descriptive-name>
Names must be kebab-case with a concise descriptive part (2--3 words max).
| Prefix | Description | Example |
|---|---|---|
app- | Deployable applications | app-studio, app-block-page |
svc- | Microservices | svc-access |
iac- | Infrastructure as Code (Terraform) | iac-foundation, iac-platform |
platform- | Internal org tooling | platform-settings, platform-actions |
docs- | Documentation sites | docs-internal, docs-external |
tpl- | Template repositories | tpl-iac, tpl-app |
Exceptions: .github (GitHub convention) and published packages that use the package name as the repo name (e.g., eigenoid for the pip package).
The repo creation issue template enforces the convention automatically -- the user selects a category and provides only the descriptive part. The workflow validates format, allowed characters, and duplicates before proceeding.
Suborgs
Each category with two or more repos has a safe-settings suborg file (.github/suborgs/<category>.yml) with shared configuration (labels, properties). Repos are matched by glob pattern:
# .github/suborgs/app.yml
suborgrepos:
- "app-*"
Repository lifecycle
Repo creation and deletion are fully managed through issue templates and GitHub Actions in platform-settings. Direct creation by org members is disabled at the org level.
Creation
- A member opens an issue using the "Request new repository" template.
- The
new-repo.ymlworkflow generates a PR with the repo's YAML configuration for safe-settings, usingforce_create: true. - The PR is authored by
eigenoid-settings-bot[bot], includes a summary table and review checklist, and auto-closes the issue on merge. - A reviewer approves and merges the PR.
- safe-settings detects the merge and creates the repo with full configuration (labels, rulesets, teams, settings) in a single step.
The repo is born fully governed, with a complete audit trail from issue to PR to merge to creation.
Archival (soft-delete)
- A member opens an issue using the "Request repo deletion" template. The
notify-lifecycle-approvers.ymlworkflow notifies@eigenoid/platform-lifecycle-approvers. - A team member applies the
approved-deletionlabel. Thearchive-repo.ymlworkflow verifies team membership before proceeding. - The workflow archives the repo on GitHub and records an entry in
archived-repos.jsonwith a timestamp, the requester, and the issue reference.
The repo becomes read-only but recoverable. The entry in archived-repos.json starts a 30-day countdown.
Permanent deletion
- The
delete-archived-repos.ymlworkflow runs daily via CRON. - It reads
archived-repos.jsonand permanently deletes repos archived for more than 30 days. - It removes the registry entry and notifies the original requester.
Lifecycle ruleset
An org-level ruleset restricts lifecycle operations (creation, deletion, transfer, visibility changes). Only OrganizationAdmin and the eigenoid-settings-bot GitHub App can bypass it. The admin repo (platform-settings) has its own repo-level rulesets to prevent lockout.
safe-settings
safe-settings is the source of truth for GitHub configuration across the org. It runs as a container on Cloud Run and reacts to pushes to the admin repo.
What it manages:
- Org-level settings: default repo configuration, org rulesets.
- Per-repo settings: visibility, merge strategy, features (wiki, issues, etc.), labels, team access.
- Rulesets and branch protection: declared in YAML, enforced on every push. Manual changes are automatically reverted (drift prevention).
- Suborgs: shared configuration for groups of repos matched by glob pattern.
Configuration lives in platform-settings/.github/ under settings.yml (org-wide), repos/<name>.yml (per-repo), and suborgs/<category>.yml (per-category).
For the operational guide, see safe-settings operations.
For bot details, see the Settings Bot page.
Branch protection and rulesets
All repositories use squash merge as the only allowed merge strategy. This keeps the main branch history clean and linear.
Commits must follow Conventional Commits format (feat:, fix:, docs:, ci:, etc.). PR titles are validated by a dedicated workflow (pr-title.yml) in each repo.
Branch protection is enforced via org-level rulesets in safe-settings:
| Ruleset | Target | Rules |
|---|---|---|
main-protection | All repos (except github-org-settings) | No deletion, no force-push, linear history required |
require-pr | All repos (except github-org-settings) | 1 approval, stale review dismissal, thread resolution |
code-dev-protection | svc-*, app-* repos | Protect dev branch: no deletion, no force-push, 0 approvals |
code-qa-protection | svc-*, app-* repos | Protect qa branch: no deletion, no force-push, 1 approval, thread resolution |
exception-dev-protection | Repos with branch_strategy: dev-qa-main property | Same as code-dev, for repos outside svc-/app- naming |
exception-qa-protection | Repos with branch_strategy: dev-qa-main property | Same as code-qa, for repos outside svc-/app- naming |
repo-lifecycle-governance | Org-level | Restricts repo creation, deletion, transfer, visibility changes |
All rulesets allow OrganizationAdmin bypass. Code and exception rulesets also allow the eigenoid-settings-bot Integration as a bypass actor.
Changes to rulesets made manually through the GitHub UI are automatically reverted by safe-settings on the next sync cycle.