safe-settings — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited safe-settings (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Onboard github/safe-settings — a Probot GitHub App that reconciles repo settings, branch protection, rulesets, labels, teams, environments, and collaborators from YAML files in a single admin repo.
Use this skill when an org wants to manage repository policy declaratively at scale, instead of clicking through each repo's settings page or running gh api one-shot scripts.
| Situation | Tool |
|---|---|
| Single repo, one-time policy lockdown | /gh-bootstrap (gh CLI, imperative) |
| Many repos, central policy that must stay in sync, drift detection, dry-run on PR | safe-settings (this skill) |
| Per-task GitHub ops (PRs, issues, CI status) | /gh |
safe-settings is the right answer when policy is shared across repos and you want PRs + dry-run gating on policy changes themselves. It's overkill for a single repo.
oldname, exclusion patterns)include / exclude repo lists)The same YAML schema is layered org → suborg → repo, with repo-level files taking precedence.
safe-settings reads its config from a single admin repo in the org. Two common layouts:
| Admin repo | When |
|---|---|
<org>/.github | Quickest — the org already has this repo for community health files. Set ADMIN_REPO=.github. |
<org>/admin (dedicated) | Cleaner for large orgs where a dedicated policy team owns the repo. Set ADMIN_REPO=admin. |
Confirm with the user:
gh api user --jq '.login' if it's a user, gh api orgs/<org> to verify org).github is the common default)The standard layout under the admin repo:
<admin-repo>/
└── .github/
├── settings.yml # org-level baseline — applies to all repos
├── suborgs/ # optional — overrides for groups of repos
│ └── <suborg-name>.yml
└── repos/ # optional — per-repo overrides
└── <repo-name>.ymlFiles to copy from assets/:
assets/settings.yml → .github/settings.yml — minimal, opinionated org baseline (see below)assets/suborg.yml → .github/suborgs/example.yml — commented sub-org templateassets/repo.yml → .github/repos/example.yml — commented per-repo override templateThe org baseline in assets/settings.yml mirrors the gh-bootstrap defaults: squash-only merging, PR-title commit subjects, delete-on-merge, plus a default-branch ruleset with merge queue and required reviews. Read references/schema.md for the full key catalog and how the layering works.
#### GitHub Actions cron (recommended starting point)
npm run full-syncassets/full-sync.yml → <admin-repo>/.github/workflows/safe-settings.yml#### Hosted Probot app
.github/settings.yml, repo created, etc.)references/deploy.md for the deployment matrix and env-var referenceThe skill defaults to the GHA cron path. Only switch to hosted if the user asks.
Both deployment paths need a GitHub App installation. Walk the user through the manifest flow:
git clone https://github.com/github/safe-settingscp .env.example .env, set GH_ORG=<org>npm install && npm run devvars.SAFE_SETTINGS_APP_ID (repo or org variable).pem) → secrets.SAFE_SETTINGS_PRIVATE_KEY (paste the file contents)vars.SAFE_SETTINGS_GITHUB_CLIENT_IDsecrets.SAFE_SETTINGS_GITHUB_CLIENT_SECRETsecrets.SAFE_SETTINGS_WEBHOOK_SECRET (only needed for hosted Probot)The GitHub App needs admin access to the org's repos to manage settings. The manifest flow requests the right permissions automatically — don't hand-roll the permission list.
For the GHA path:
# Set the variables and secrets on the admin repo (or org-wide).
gh variable set SAFE_SETTINGS_GH_ORG --body "<org>" --repo "<org>/<admin-repo>"
gh variable set SAFE_SETTINGS_APP_ID --body "<app-id>" --repo "<org>/<admin-repo>"
gh variable set SAFE_SETTINGS_GITHUB_CLIENT_ID --body "<client-id>" --repo "<org>/<admin-repo>"
gh secret set SAFE_SETTINGS_PRIVATE_KEY --body "$(cat private-key.pem)" --repo "<org>/<admin-repo>"
gh secret set SAFE_SETTINGS_GITHUB_CLIENT_SECRET --body "<secret>" --repo "<org>/<admin-repo>"Trigger the first sync manually via workflow_dispatch:
gh workflow run safe-settings.yml --repo "<org>/<admin-repo>"
gh run watch --repo "<org>/<admin-repo>"Check the run output. The first sync logs every change it would apply; subsequent runs are quiet unless something has drifted.
safe-settings comes with two safety nets — make sure both are wired:
assets/settings.yml includes a validator.pattern for repo names. Customize it for the org's naming convention so safe-settings refuses to apply settings to mis-named repos.For a more rigorous setup, add enforcement: evaluate on new rulesets to test them in shadow mode before flipping to active. See references/schema.md.
safe-settings is reconciliation-shaped — running full-sync on an unchanged config is a no-op. The skill itself is also idempotent:
assets/ templates and ask before overwriting any existing filegh variable set and gh secret set are idempotent (last write wins); the skill should ask before overwriting an existing valueRe-running the skill on a partially-set-up admin repo should fill in only the missing pieces.
/gh-bootstrap/gh/commitgithub/settings app — safe-settings is the supported successor; the skill assumes you're starting fresh or already off github/settings.github/ in ADMIN_REPO; if you put it elsewhere, set CONFIG_PATH to the directory.full-sync via GHA touches every repo in the org on every run. For huge orgs (>1000 repos) the run can take an hour and burn Actions minutes — use the hosted Probot path or scope by suborg.branches at org level applies to every repo; at repo level it overrides only that repo. The merge order is deep — read references/schema.md before writing complex overrides.settings.yml, every repo gets the change on next sync. There is no "stage to a few repos first" toggle short of using enforcement: evaluate on rulesets.force_create: true in a repos/<name>.yml will create the repo if it doesn't exist. This is powerful and dangerous — use it deliberately.labels.exclude is required; to remove a collaborator, you typically delete the entry and run sync. Read the schema before assuming "remove from YAML" means "remove from GitHub".merge_queue rule inside a rulesets entry — not a top-level toggle. Same shape as /gh-bootstrap's ruleset payload, just expressed in YAML and applied org-wide.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.