Docs

Configuring Release Approval

Configure release approval for a Facets project using the no-code Builder or a custom pre-release hook script.

Overview

Release approval gates a release behind a manual decision. You define the rule once per project, and Facets evaluates it on every release to that project's environments.

The rule lives on a dedicated settings page, at Project settings > Release Approval. It offers two authoring modes: the Builder tab assembles the rule from guided selections, and the Script tab lets you write the gating logic yourself in Python or Shell. Both produce the same thing, one pre-release hook committed to your blueprint.

This page covers configuration. Acting on a gated release happens in the environment's release history, covered in Approving and Rejecting Releases.


Set up release approval

  1. Go to Project settings > Release Approval.
  2. Select Set up Release Approval.
  3. The drawer opens on the Builder tab. Build the rule from guided selections, or switch to Script and write it yourself.

Builder mode

The Builder tab assembles the rule from three criteria lists, each populated from the project's own environments and resources.

  1. Select the Environments you want to gate.
  2. Choose AND or OR in the connector below.
  3. Select the Resources you want to gate, each listed as resourceType/resourceName.
  4. Choose AND or OR in the connector below.
  5. Select the Release Streams you want to gate.
  6. Select Create, or Save when editing an existing rule.

How the connectors combine

The three categories fold together from left to right. The first connector joins Environments to Resources, and the second joins that result to Release Streams. A category with no selections drops out of the rule, and so does the connector immediately to its left.

CategorySelectionConnector below it
EnvironmentsprodAND
Resourcesservice/checkoutOR
Release StreamsPRODnone

Facets reads that as: approval is required when the release targets prod and touches service/checkout, or when the release runs on the PROD release stream. Clear Resources and the rule collapses to prod or the PROD stream, because the AND connector drops out with it.


Script mode

Script mode replaces the guided selections with logic you write yourself. Use it when your gating condition depends on something the three criteria lists cannot express.

  1. In the drawer, select the Script tab.
  2. Choose Python or Shell in the language toggle. A new hook defaults to Python, and once a hook is installed the toggle locks: to switch languages, remove the configuration and set it up again.
  3. Write your script in the in-browser code editor.
  4. Select the confirm button to install it.

Facets stores the script verbatim and does not interpret it. At release time it runs the script and reads its process exit code.

🚧

Exit code 2 requires manual approval. Exit code 0 lets the release proceed. Exit 0 or 2 explicitly on every path, including error paths. See the Pre-Release Hook Script Reference for the full contract, the release context JSON, and working samples.


Generate the script with Praxis

The Script tab can hand the drafting off to Praxis. The button reads Generate in Python with Praxis or Generate in Shell with Praxis, switching with the language toggle.

Selecting it opens Praxis in a new tab, pre-seeded with the project name and whatever criteria you have already selected in Builder. Praxis drafts the gating script from that context, dry-run validates it, and shows you the script before installing.

The button sits behind an AI-assistant feature flag. If it does not appear in your installation, the feature is not enabled there.


If you already have a hook

A hook authored before the Builder existed, or written by hand outside the drawer, carries no Builder configuration block. Facets shows it as a Custom script card instead of the guided summary, and Edit script opens the drawer straight into the Script tab. The hook keeps working exactly as before; the detection changes only how Facets presents it.

🚧

Switching a custom script to Builder starts over with guided selections, and saving from Builder replaces your hand-written script with a generated one. Copy the existing script somewhere safe first if you want to keep it.


Review, edit, or remove the rule

Once a Builder rule is installed, the settings page shows an Approval required card listing the gated environments, resources and release streams as tag groups with the connectors rendered between them. Read it left to right, the same way the connectors fold. That card is the fastest way to confirm what your project actually gates.

Select Edit on that card, or Edit script on a Custom script card, to reopen the drawer with the current configuration loaded. Select Remove to delete the rule, and confirm in the dialog.

🚧

Removing the configuration deletes the pre-release hook from your blueprint. Releases stop being gated immediately, and the next release to a previously gated environment proceeds without asking anyone. You cannot undo this from the UI, you rebuild the rule from scratch.


Permissions

Everything on this page is blueprint-scoped: STACK_WRITE to set up, edit or edit the script, and STACK_DELETE to remove. Approving a gated release is a separate, environment-scoped permission. See the full permission matrix.

Users without the required permission see "You do not have permission to modify release approval." or "You do not have permission to remove release approval."


Troubleshooting

MessageWhat it meansWhat to do
"Select at least one environment, resource or release stream."Builder mode has no criteria selected. A rule with nothing selected gates nothing.Select at least one item in any of the three lists.
"The script cannot be empty."Script mode was saved with an empty editor.Write a script, or switch to Builder.
"Failed to load options" with "Environments and resources could not be loaded, the builder lists may be incomplete."Facets could not fetch the environment and resource lists.Reload the page. The drawer reports this failure explicitly, so an empty list without this message means no options exist rather than a failed fetch.
"Failed to load release approval"Facets could not read the project's current hook.Reload the page. If it persists, confirm the blueprint repository is reachable.
"Failed to save release approval."The commit to the blueprint repository did not complete.Retry the save. Confirm you hold STACK_WRITE on the project.
"Failed to remove release approval."Deleting the hook file did not complete.Retry. Confirm you hold STACK_DELETE on the project.
The confirm button stays disabledThe form matches what is already installed.Change a criterion or the script. The button enables once the form differs.
The language toggle is disabledA hook is already installed, and its language cannot change in place.Remove the configuration, then set it up again in the other language.

Where the configuration is stored

Facets stores the rule as a pre-release hook committed into the project's blueprint Git repository, not as database rows. Saving writes a commit, removing deletes the file, and every install and delete is written to the audit log.

Because saving is a Git write, the settings screen can take a moment to reflect a change made outside the UI. Reload the page if a hook you committed directly to the repository has not appeared yet.


From the CLI

raptor installs, reads, and removes the pre-release hook, so you can keep the rule in version control and apply it from a pipeline.

raptor apply hook --type pre-release -p PROJECT --script-file ./pre_release_hook.py
raptor get hook --type pre-release -p PROJECT
raptor delete hook --type pre-release -p PROJECT --yes

The language is inferred from the file extension (.sh means Shell, anything else means Python), or set it explicitly with --language when you use --script or a file whose extension is neither .py nor .sh. An explicit --language that contradicts a recognized .py or .sh extension is rejected rather than applied. Use --script instead of --script-file to pass the body inline. delete hook prompts for confirmation unless you pass --yes, and removing the hook removes the gate, so releases that were previously held proceed without approval.