Skip to main content
A GitHub repository has dozens of settings: which merge buttons are allowed, whether the wiki is on, which checks must pass before merging, who has access, and more. They are usually clicked by hand, one repository at a time, and they drift apart. The settings feature writes them down instead. You describe the settings you want in the settings section, and on every scheduled run smartcloud brings the repository back in line. That gives you:
  • The same baseline everywhere. Put the settings in a preset and every repository that extends it gets them.
  • A record of every change. Settings live in a file, so a change is a reviewed pull request, not a click nobody remembers.
  • Self-healing settings. If someone changes a setting by hand, the next run puts it back.
Only what you write is changed. A section or key you leave out is never touched, so you can start with one setting and add more later.
Changing repository settings needs a token with administration access to the repository, such as a GitHub App token. The workflow token cannot do it. A run with only the workflow token, or from a fork or Dependabot, skips settings and says why in the job summary.

Turn it on

1

Create a GitHub App (recommended) or a token

A GitHub App gives smartcloud short-lived tokens that reach only the repositories you choose, and commits it makes are signed by GitHub.
  1. In your organisation, open Settings > Developer settings > GitHub Apps > New GitHub App. Give it a name, set any homepage URL, and untick Webhook > Active: smartcloud runs from Actions and needs no webhook.
  2. Under Repository permissions, grant what the sections you use need. For every smartcloud feature together that is: Administration (read and write), Contents (read and write), Issues (read and write), Pull requests (read and write), Checks (read and write), Commit statuses (read), Workflows (read and write, for sync), Webhooks (read and write, for settings.webhooks), Pages (read and write, for settings.pages), Environments (read and write, for settings.environments) and Variables (read, for settings.variables). For settings.teams, also grant the organisation permission Members (read).
  3. Create the app, note its App ID, and generate a private key.
  4. Install the app on the repositories it should manage (and on the repository that holds your presets, if it is private).
  5. In the repository or organisation, add the App ID as an Actions variable (for example SMARTCLOUD_APP_ID) and the private key as an Actions secret (for example SMARTCLOUD_APP_PRIVATE_KEY).
A classic personal access token with the repo scope (and workflow for sync) can change settings too, but GitHub never lets a personal token create check runs, so every smartcloud check fails to publish. Use a GitHub App. Run smartcloud doctor to check a token’s scopes and access.
2

Pass the token to smartcloud

Mint a token in the workflow with actions/create-github-app-token and give it to smartcloud as GITHUB_TOKEN. Keep the fallback to github.token, so a run where no token can be minted, such as a pull request from a fork, runs restricted instead of failing.
.github/workflows/smartcloud.yml
Pin actions to a full commit SHA in a real workflow. The settings feature runs on schedule, workflow_dispatch and push events only.
3

Add a settings section

Start small. This turns off merge commits and deletes branches after merging:
.github/smartcloud.yml
4

Preview, then run

See what would change before anything is written with smartcloud plan settings, the MCP server’s plan_settings tool, or a run with the dryRun: true input. Then run the workflow from the Actions tab (Run workflow), or wait for the schedule.

Options

Every key is optional. A key left out is left as GitHub has it.

merging

smartcloud reads the repository’s current settings first and leaves out any value it already has, because GitHub refuses some writes even of an unchanged value (sign-off an organisation enforces, or a wiki toggle the token may not make). A repository that already matches gets no update.

features

security

Secret scanning is only changed on public repositories. On a private one it needs a paid Advanced Security licence, so smartcloud leaves it to the organisation and records a notice. Code scanning fails when the repository has no language CodeQL supports, and secret scanning can fail too; both are reported as warnings rather than errors.

ruleset

ruleset manages one ruleset on the default branch. A ruleset is GitHub’s modern branch protection: rules such as “no force pushes” or “these checks must pass” that apply to a branch. smartcloud finds its ruleset by name and updates it in place on every run.
The ruleset is written whole. A rule you leave out, or switch off, is not enforced, even if someone added it by hand.
Only list a code scanning tool under codeScanning if it uploads results for every pull request, or nothing can merge. Every workflow behind a required check must also run on the merge_group event when you use a merge queue. On a private repository, rulesets need a paid plan, so a ruleset failure there is a warning.

The merge queue method must fit the ruleset

A merge queue lines pull requests up and merges them one group at a time, using mergeQueue.method. Two other rules limit which methods can work, and a queue whose method breaks either of them can never merge anything:
  • linearHistory: true rules out merge. Linear history means the branch has no merge commits, and the merge method makes one for every pull request. GitHub would refuse every merge the queue tries.
  • pullRequest.mergeMethods must include the queue’s method. That list says which ways a pull request may be merged. A queue told to rebase while pull requests may only be squashed is asking for something the same ruleset forbids.
smartcloud checks both once your config and its presets are merged, because the conflict often comes from two places: the house preset turns on linear history, and your own config asks the queue to merge. What you will see:
  • smartcloud validate (and the MCP validate_config tool) fails and names the key, for example ["mergeQueue"]["method"]: the merge queue cannot use merge while linearHistory is on, because a merge commit breaks linear history; use squash or rebase, or the merge queue method rebase is not one of pullRequest.mergeMethods (squash); add it there or use one of them.
  • A run never breaks for it. It ignores the method, uses one that fits instead (squash, or the first of rebase and merge that the ruleset allows), and reports a config.ignored warning on the smartcloud / config check, naming the file and settings.ruleset.mergeQueue.method.
  • smartcloud plan settings (and the MCP plan_settings tool) shows the ruleset with the method it will really use, and lists the ignored method under “Ignored, so not applied”.
To fix it, pick a method that fits, or leave method out and let smartcloud pick one:

environments

Environments that ship to users deploy only from the default branch and from release tags matching v*. smartcloud sets them to use custom deployment branch policies and creates a branch policy for the default branch and a tag policy for v* when they are missing; policies you added yourself are kept. It does not rely on GitHub’s “protected branches” option, because that counts only classic branch protection, and with none (this feature writes a ruleset instead) every branch could deploy. Staging, development, dev, preview and any name ending in “Beta” accept any branch.

actions

GitHub needs enabled whenever allowedActions or shaPinningRequired is sent, so setting either alone keeps Actions on. selectedActions is ignored unless allowedActions is selected, because GitHub rejects it otherwise. The access level only exists for private and internal repositories: any repository can already use the actions of a public one. On a public repository it is left alone and a notice says so. Keep it at organization on a private repository whose reusable workflows the others call, such as a private .github repository; at none, every workflow that calls them fails before it starts. Set workflowPermissions: read only when every workflow declares the permissions it needs. A workflow that relies on the default write access breaks.

collaborators and teams

Only the logins and teams you list are changed; everyone else keeps their access. Teams can only be given access, not removed: remove one by hand.

webhooks

webhooks maps a name of your choosing to a webhook. smartcloud finds the webhook on GitHub by its url. smartcloud never sets or changes a webhook secret: add one by hand in the webhook’s settings, and later runs keep it. Plans and reports name only the URL’s host, but the config itself is readable by everyone who can read the repository, so keep tokens out of the URL on a public repository.

pages

A missing site is created (built from a workflow unless a branch, path or legacy build type is set), then updated with the custom domain and HTTPS setting. An existing site is updated with what the config sets.

variables

variables maps each Actions variable the repository must have to a sentence saying what it is for. smartcloud only checks that the names exist. Values are never read, written or kept in the config. A missing variable is a warning that names it and its purpose, so a maintainer can add it by hand under Settings > Secrets and variables > Actions > Variables. Names compare ignoring case, since GitHub stores them in upper case, and names starting with GITHUB_ are reserved by GitHub and rejected by the schema.

Complete example

.github/smartcloud.yml

How it works

  1. The feature runs on schedule, workflow_dispatch and push events. Other events never change settings.
  2. smartcloud reads the repository, then plans one step per configured part, in a fixed order: merging, features, security, the ruleset, environments (each followed by its deployment policies), Actions, collaborators, teams, webhooks, Pages, then the variables check.
  3. Each step is applied on its own. A failed step is reported and the others still run.
  4. Some steps are expected to fail on some repositories, so their failure is a warning rather than an error: code scanning (no supported language), secret scanning, the ruleset on a private repository (rulesets need a paid plan there), and missing Actions variables.
The push limit (Settings > General > Pushes) has no API, so every run records a notice to set it by hand. Webhook secrets and Actions variable values are also set by hand.

What you will see on GitHub

  • A smartcloud / settings check run on the commit. It fails when a required step failed (for example a token without administration access), is neutral when only optional steps failed, and passes otherwise. Every run carries the settings.push-limit notice.
  • In the job summary, one change per step that was applied, such as Ruleset "house: default branch" or Collaborator @hubot as write (invited if not yet a collaborator), and each failure with GitHub’s message, under a rule id like settings.ruleset or settings.collaborator:octocat.
  • On GitHub itself: the ruleset under Settings > Rules > Rulesets, named house: default branch unless you set ruleset.name, environments under Settings > Environments, and invitations for new collaborators.

Forks and restricted runs

Settings only ever runs with a token that can administer the repository. In a restricted run, which is any run with only the workflow token, a pull request from a fork, or Dependabot’s runs and pull requests, the feature is skipped and the job summary says “repository settings need an admin token”. Scheduled and manually dispatched runs never come from a fork, so they get your app token whenever it can be minted.

In the house preset

The Resnovas house preset sets a full baseline: squash and rebase merges only, auto-merge, branch deletion and web sign-off on, squash commits titled from the pull request with every commit message kept; wiki off, discussions and sponsorships on; immutable releases, private vulnerability reporting, Dependabot alerts and security updates and secret scanning on, and CodeQL default setup off (the house runs CodeQL as advanced setup); a house: default branch ruleset with deletion and force-push blocked, linear history, a squash merge queue with allGreen, signed commits, one approval with stale reviews dismissed and conversations resolved, the smartcloud check required with strict, CodeQL at high_or_higher/errors, code quality at errors, coverage limits of 80 and 5 (off until enabled), provider secret alerts, Copilot review and admin bypass; and read-only workflow tokens that may open pull requests, with organisation access. A repository extending it may still add what the preset leaves unset: settings.environments, ruleset.requiredDeployments, extra ruleset.statusChecks.checks, ruleset.codeScanning.ESLint, ruleset.codeCoverage.enabled, collaborators, teams, webhooks, pages and variables. It cannot change a value the preset sets; see Add, never change.

Troubleshooting

The run had only the workflow token, or came from a fork or Dependabot. Mint a GitHub App token as GITHUB_TOKEN, as in Turn it on, and run the workflow on a schedule or by hand. smartcloud doctor shows whether your token can administer the repository.
The token has no administration write access to this repository. For a GitHub App, add Administration: read and write and accept the new permissions on the installation. For a classic token, add the repo scope. For a fine-grained token, add Administration (write).
Code scanning default setup needs a language CodeQL supports. Secret scanning on a private repository needs Advanced Security, so smartcloud does not change it there and records a notice instead. Both are warnings, so the check does not fail.
ruleset.pullRequest.requiredApprovals and ruleset.requiredChecks only bind once two or more distinct logins are in roles.maintainers, so a sole maintainer is never locked out. Add a second maintainer.
A codeScanning tool or codeCoverage.enabled: true blocks merging until results are uploaded for every pull request. Upload them (CodeQL workflow, actions/upload-code-coverage) or remove the rule. With a merge queue, every workflow behind a required check must also run on merge_group.
The merge queue’s method conflicts with the rest of the ruleset: it is merge while linearHistory is on, or it is not in pullRequest.mergeMethods. The run used a method that fits instead. Change mergeQueue.method to one that fits, or leave it out; see The merge queue method must fit the ruleset. If a preset sets both values, fix the preset.
settings.variables lists a name that is not set. Add it by hand under Settings > Secrets and variables > Actions > Variables; smartcloud never writes values.
Your config gives a different value for a setting your preset already sets. Presets are locked: remove the value from your config, or change the preset. See Presets.
Last modified on September 28, 2026