Contributing
Conventions for adding workflows, scripts, config entries, and vendor components.
Adding a workflow
-
Create the workflow file in
.github/workflows/ -
Register in priority tiers — add an entry to
config/workflow-priority-tiers.ymlusing the workflow'sname:field (not the filename):- name: "My New Workflow" tier: 3 # MEDIUM — adjust based on criticalityTier guide: 1=CRITICAL (never cancelled), 2=HIGH (mirror chain), 3=MEDIUM (default), 4=LOW (cancelled first under quota pressure)
-
Register in workflow-sync — add to
config/workflow-sync.yml:- Under
github_onlyif it has no GitLab CI counterpart (most workflows) - Under
pairedif it has a matching GitLab CI job
- Under
-
Add a concurrency group if triggered by
scheduleorworkflow_run:concurrency: group: my-workflow-name cancel-in-progress: true -
Add a quota pre-flight if the workflow makes API calls and runs frequently:
- name: Check quota id: quota run: | remaining=$(curl -sf -H "Authorization: token $GH_TOKEN" \ "https://api.github.com/rate_limit" | jq '.resources.core.remaining') echo "remaining=$remaining" >> "$GITHUB_OUTPUT" [[ "$remaining" -lt 500 ]] && echo "skip=true" >> "$GITHUB_OUTPUT" || echo "skip=false" >> "$GITHUB_OUTPUT" -
Validate:
python3 scripts/validate-workflow-guards.py python3 scripts/validate-priority-tiers.py config/workflow-priority-tiers.yml
Adding a script
Scripts live in scripts/. All logging must go to stderr — never stdout —
because many functions are called inside $(...) captures where stdout becomes
the captured value.
info() { echo "[my-script] $*" >&2; }
warn() { echo "[warn] $*" >&2; }
If the script sources includes/budget.sh or includes/gh-api.sh, add the
shellcheck directive:
# shellcheck source=includes/budget.sh
source "$(dirname "${BASH_SOURCE[0]}")/includes/budget.sh"
Run ShellCheck before committing:
shellcheck --severity=warning scripts/my-script.sh
Adding a config entry
New repo to GitLab mirror chain
Add to config/gitlab-subgroups.yml under the appropriate subgroup:
rust-systems_deving:
repos:
- my-new-repo
Then validate:
python3 scripts/validate-gitlab-subgroups.py config/gitlab-subgroups.yml
New repo to upstream sync
Add to registered-imports.json:
{
"source_url": "https://github.com/upstream-org/repo-name",
"target_name": "repo-name",
"platform": "github",
"added": "2026-06-07T00:00:00Z"
}
Then validate:
python3 scripts/validate-registered-imports.py registered-imports.json
New workflow priority tier entry
See "Adding a workflow" above — step 2.
Adding a vendor component
vendor/ is for third-party components that fork-sync-all hosts or deploys.
It is not for first-party scripts or config.
Before adding:
- Confirm the component is genuinely third-party (not a script you wrote)
- Confirm it will be deployed or served by fork-sync-all (not just referenced)
When adding:
- Place under
vendor/<component-name>/ - Strip all distro-specific or org-specific hardcoded defaults — see the agnostic rule below
- Add a
README.mdwith a "Before the first deploy" section covering all required CI variables - Run the agnostic check:
bash scripts/check-vendor-agnostic.sh vendor/<component-name>
Agnostic rule
No deployment-identity values may appear as hardcoded fallback defaults in vendored components. This includes:
- Public URLs:
${VITE_ENDPOINT_URL:-https://api.myorg.com}❌ - Org/repo slugs:
${MIRRORLIST_REPO:-MyOrg/my-repo}❌ - Arch/repo paths:
${MIRROR_REPO_PATHS:-x86_64/core}❌ - Distro names:
${DISTRO:-cachyos}❌
Allowed:
- Localhost dev URLs:
${API_URL:-http://localhost:5862}✅ - Generic paths:
${MIRRORLIST_PATH:-mirrorlist/mirrorlist}✅ - Single-word tokens:
${LOG_LEVEL:-info}✅ - UI strings:
${APP_NAME:-Infra Dashboard}✅
To suppress a specific line that is intentionally non-agnostic:
SOME_VAR="${SOME_VAR:-value}" # check-vendor-agnostic: ignore
enforce-agnostic-vendor.yml runs automatically on every push/PR touching vendor/.
Commit conventions
Follow the existing commit message style:
scope: short description
Longer explanation if needed. Focus on why, not what.
Common scopes: fix, feat, config, docs, vendor, scripts, ci.
Before opening a PR
# Config validators
python3 scripts/validate-gitlab-subgroups.py config/gitlab-subgroups.yml
python3 scripts/validate-registered-imports.py registered-imports.json
python3 scripts/validate-cost-profiles.py config/workflow-cost-profiles.yml
python3 scripts/validate-priority-tiers.py config/workflow-priority-tiers.yml
python3 scripts/validate-template-config.py
python3 scripts/validate-workflow-guards.py
# Test suites
python3 -m pytest tests/ -v --tb=short
bash scripts/tests/test-check-readme-render-mobile.sh
# ShellCheck (for any .sh files changed)
git diff --name-only HEAD -- 'scripts/*.sh' | xargs shellcheck --severity=warning
# Vendor check (if vendor/ was touched)
bash scripts/check-vendor-agnostic.sh vendor
# README render check
bash scripts/check-readme-render.sh README.md
All must pass before the PR is ready for merge.