Environment Rulesets
Keep one GitHub repository ruleset in ActionsManager and apply it across a project’s repositories, instead of recreating the same branch protection by hand in each one.
What a ruleset is here
Section titled “What a ruleset is here”A ruleset in ActionsManager is a stored copy of a GitHub repository ruleset — the JSON GitHub itself accepts, held once and applied to many repositories.
ActionsManager stores the definition and applies it. It does not edit rules, validate them against GitHub’s schema, or keep a repository’s copy in step automatically. What it adds is the fan-out: one definition, applied to every repository in a project, and a way to see which repositories have it.
Rulesets are not workflows. They have no drift lifecycle, no pull request delivery, and no campaign — see Drift Detection and PR Campaigns for the features that do.
Rulesets live under 🛡️ Environment Rulesets on the project page.
Adding a ruleset
Section titled “Adding a ruleset”Rulesets are added by uploading a JSON file. The file must end in .json and contain a JSON object. Its name and description fields become the ruleset’s name and description; without a name, the filename is used. The name must be non-blank text of at most 255 characters and the description text of at most 500. Anything else is rejected and nothing is stored, as is a file that is not valid JSON. Files saved as UTF-16, or as UTF-8 with a byte-order mark, are read like any other.
There is no form for pasting JSON in. The API also accepts a ruleset as JSON in the request body, with a name and optional description alongside it (POST /api/rulesets/create), but nothing in the interface calls it.
The easiest way to get a valid file is to export an existing ruleset from a repository that already has the rules you want, through GitHub’s own ruleset UI or API.
A ruleset uploaded from a project page is associated with that project. That association is what later decides which repositories a GitHub-side removal reaches, so it matters more than it looks — see Which repositories a removal reaches.
It is associated with the project it was uploaded to, whoever owns that project: a workspace admin, or a member with editor access, uploading to someone else’s project associates the ruleset there. If the project name does not resolve to a project you can edit, nothing is stored and the upload fails.
A ruleset ends up with no project in two ways: it was created through the API without a project_name, or the project it belonged to was deleted. Deleting a project removes its association with each ruleset but keeps the rulesets themselves.
Applying a ruleset
Section titled “Applying a ruleset”🚀 Apply sends the stored JSON to every repository currently ticked in Repositories & Branches, one POST per repository.
Select the repositories first. Apply acts on the current selection in Repositories & Branches, not on a saved list.
The result reports how many repositories succeeded and how many failed. A failure on one repository does not stop the others — applying to five repositories where two fail applies to three and tells you about the two.
Apply always creates; it never updates a copy already on the repository. Re-applying a ruleset a repository already has is therefore either a second copy or a validation error from GitHub, which ActionsManager counts as a failure for that repository. Check the sync panel below before re-applying.
Permissions
Section titled “Permissions”Who added a ruleset does not matter once it belongs to a project. Anyone who can edit the project can apply, sync and remove it, and anyone else who can see the project can check its sync status. Read Only users are the exception: the check is sent as a write request, which their role does not allow. A ruleset attached to no project can only be used by the account that added it.
On GitHub’s side, a ruleset is repository administration, so your GitHub token needs admin access to each repository you apply to, read or remove from. Without it GitHub returns 403 and ActionsManager reports that repository as failed rather than failing the whole operation. Rulesets need the Administration: Read and write permission — see GitHub Permissions for the full table and GitHub PAT Setup for creating the token.
Apply reports a failed repository without saying why — the reason GitHub gave (permission denied, repository not found, validation error) is written to the backend log. Check there when a repository fails and the cause is not obvious. The sync panel does distinguish the cases, so it is often the quicker answer.
Checking which repositories have it
Section titled “Checking which repositories have it”The sync panel reads each selected repository’s rulesets from GitHub and matches on the ruleset’s name — the name inside the stored JSON, which can differ from the name shown in ActionsManager if the JSON was edited after import.
When the JSON has no name (or an empty one), the name shown in ActionsManager is used instead. Apply and removal use the same name, so all three find the same copy on GitHub.
Earlier versions applied a nameless ruleset as “Imported Ruleset”. ActionsManager does not look for copies by that name, so the sync panel cannot see them and removing the ruleset from GitHub leaves them enforced. If you applied a ruleset without a
namebefore this changed, delete any “Imported Ruleset” on those repositories in GitHub’s own ruleset settings.
Each repository comes back as one of:
| Status | Meaning |
|---|---|
exists |
A ruleset with that name is on the repository |
not_found |
No ruleset with that name; the repository is reported as missing it |
permission_denied |
Your token lacks admin access, so it could not be checked — counted as missing, because it cannot be confirmed either way |
repo_not_found |
The repository could not be read at all |
error |
The check itself failed — a network error, or anything GitHub returned other than the three above — also counted as missing |
When any repository is missing it, the panel shows ⚠️ Missing in N repositories with a 🔄 Sync button.
🔄 Sync is an apply narrowed to the repositories the panel has confirmed are missing it. Repositories that could not be checked are skipped rather than guessed at, and the message says how many were skipped. If nothing is confirmed missing, Sync applies nothing and says so.
Removing a ruleset
Section titled “Removing a ruleset”Deleting asks which copies to destroy, because the ActionsManager record and the GitHub policy are separate things and removing the wrong one has very different consequences.
| Option | ActionsManager record | GitHub policy |
|---|---|---|
| 🏠 Remove from ActionsManager only | Deleted | Left in place and still enforced |
| ☁️ Remove from GitHub only | Kept | Deleted |
| 💥 Delete from ActionsManager and GitHub | Deleted | Deleted |
🏠 Remove from ActionsManager only is the default, and it is the one to reach for if you only want to stop managing a ruleset here. Branch protection the ruleset enforces keeps applying to the repositories; ActionsManager simply stops tracking it, so it no longer checks whether those repositories still have it.
☁️ Remove from GitHub only lifts the policy but keeps the definition, so you can apply it again later without re-importing the JSON. This is the option for temporarily relaxing a rule.
💥 Delete from ActionsManager and GitHub does both, and is not reversible from ActionsManager — the definition is gone, so re-applying means finding the JSON again.
Removing from GitHub stops the branch protection those rules enforce. Merges the ruleset was blocking become possible immediately, on every repository it is removed from.
Which repositories a removal reaches
Section titled “Which repositories a removal reaches”A GitHub-side removal does not ask you which repositories to touch. It resolves them from the saved repositories of the projects the ruleset is associated with, and deletes any ruleset matching the stored name from each.
Two consequences worth knowing:
- A repository that was never saved to the project — ticked in Repositories & Branches but not saved — is not reached, even if Apply reached it. This is a known gap, tracked in issue #2054: Apply trusts the current selection while removal resolves saved rows, so the two can disagree and leave a ruleset enforced with nothing in ActionsManager tracking it. Save your repository selection before applying a ruleset you may later want to remove.
- A ruleset associated with no project — created through the API without a
project_name, or left behind by a deleted project — resolves no repositories at all. Rather than reporting a removal that touched nothing, ActionsManager says the ruleset was not applied to any of the project’s repositories.
A repository that has no ruleset by that name is not an error — it was never applied, or was already removed by hand, and that is an acceptable end state.
When part of a removal fails
Section titled “When part of a removal fails”If GitHub rejects the removal on any repository, the whole operation returns an error naming the repositories that failed, and the ActionsManager records are kept. Dropping them would leave a ruleset enforcing branch protection with nothing here still pointing at it, which is the exact leftover the GitHub-side option exists to prevent.
The removal is not atomic across repositories: the ones that succeeded before the failure have already had their ruleset deleted. The sync panel is re-read after a failed removal so it reflects what actually happened rather than what was attempted.
Limitations
Section titled “Limitations”Stated plainly, because each one is a thing the feature does not do:
- No rule editing. ActionsManager stores and applies the JSON. Changing a rule means editing the JSON and applying it again.
- No automatic sync. Nothing re-applies a ruleset when a repository is added to a project, and nothing notices a ruleset changed or deleted on GitHub until you check the sync panel.
- Matching is by name. A ruleset renamed on GitHub reads as missing, and re-applying adds a second copy rather than reconciling.
- Apply and removal can disagree on targets. See Which repositories a removal reaches.
© 2026 ActionsManager. All rights reserved.