Skip to main content

Match approval friction to deploy risk

🎯 Goal: three prompts to your coding assistant, and every gated deploy is analyzed and routed by a risk matrix. Rollbacks and low-risk changes go out in seconds with nobody involved, a medium-risk change to a critical application waits for a peer, a high-risk change to a mission-critical one waits for ops, and the run tells the developer what was decided and who can unblock them.

Introduction

Approval rules that treat every deploy the same fail in one of two ways. Require a sign-off on every deploy and the approvals stop meaning anything, because nobody reads the tenth one of the day. Require none and a database migration in your payments service goes out with the same scrutiny as a copy change.

What is missing is proportionality, and that is what this tutorial builds:

  • One prompt creates the analyzer: a workflow that diffs the deployed release against the candidate, scores the change from measurable signals plus an AI read of the diff, and saves the result
  • One prompt creates the matrix reader: a small workflow that turns that result into checklist answers
  • One prompt creates the checklist that puts both in front of every deploy of the application

The routing itself is a matrix your organization can read at a glance:

Change riskMission criticalCriticalImportantStandard / internal
Low✅ auto✅ auto✅ auto✅ auto
Medium👥 peer👥 peer✅ auto✅ auto
High🛡️ ops👥 peer👥 peer✅ auto

Two rules sit outside the table. A release that already ran in this scope is a rollback, so it is approved directly whatever its original risk. And some changes have a minimum risk the AI cannot lower: database migrations, auth changes and first deploys are at least medium risk however harmless the diff looks.

What you'll set up

  • A checklist on deployment:create with three external items and one human group:
    • Change analysis (informational): a full description of what this deploy changes, with the risk, the categories, and a summary per pull request on the item card
    • Risk matrix approval (blocking): passes on auto and fastpath, fails naming the required approver otherwise
    • Already deployed (informational): flags rollback candidates
    • Human approvals (override group): pair approval with a four-eyes validation, or admin approval with a role validation; a single approval from the group unblocks the deploy
  • Two workflows coupled through deployment metadata: the analyzer writes one change document per deploy, the reader resolves gates from it
  • Application criticality as metadata, so the same gate protects every app at its own level

💡 Want the machinery first? Jump to What you just built, then come back.

Prerequisites

  • Checklists enabled in your organization (early release)
  • The np-workflow and np-checklist skills, part of the nullplatform AI plugins for your coding assistant. See Set up the AI plugins to install them
  • A GitHub token with read access to the application repositories the analyzer will diff

Step 1: Create the workflow that scores the change

Open a session of your coding assistant and describe the scoring side. The prompt covers the whole sequence: gather the change, score it, apply the matrix, explain the result, and save it.

/np-workflow create a workflow that resolves checklist items of kind
"deploy-change-analysis":

Compare the release being deployed against the one currently running in
the scope: pull the commits, the pull requests and who took part from
GitHub, measure how large the change is, and flag whether it touches
migrations, auth, infrastructure or dependencies.

Have an AI agent read the diff and score the risk as low, medium or high.
Skip it for rollbacks and empty diffs, fall back to the raw signals if it
fails, and never let it score below medium for a migration, an auth change
or a first deploy.

Cross that risk with the application's criticality, read from its
governance metadata and treated as critical when missing, to decide whether
the deploy is auto-approved or needs a peer or an ops approval. Resolve the
item with a summary of what changed and who has to approve, and save the
analysis under the deployment's "change" metadata.

Publish it but don't activate anything yet.

The skill builds the definition, validates it, and publishes it. The workflow reads two configuration entries; ask the skill to set them in the same conversation, or set them later from the editor's configuration panel:

EntryTypeWhat it is
NP_API_KEYSecretAPI key the trigger uses to subscribe to gate dispatches, and the analyzer to read releases and write metadata
GITHUB_TOKENSecretToken the analyzer diffs repositories with

✅ Checkpoint

The skill reports the workflow as published, activation skipped. Nothing answers gates yet: the reader and the checklist itself come next.

Step 2: Create the workflow that answers the checklist

The second workflow is deliberately small. It never recomputes anything: it reads the decision the analyzer saved and answers the checklist items.

/np-workflow create a workflow that resolves checklist items of kind
"deploy-gate-check":

The item's inputs say which check this execution answers, already_deployed
or risk_matrix. Read the deployment's "change" metadata, retrying for up to
a minute, since the analyzer writes it while this workflow waits.

For already_deployed, pass if the release was recently deployed to this
scope. For risk_matrix, pass when the decision is auto or fastpath and
explain why on the card; when it requires a person, fail the item with a
card naming which approval unblocks the deploy. If the analysis never
arrives, fail closed and say that a manual approval is now required.

Publish it but don't activate anything yet.

Splitting the analyzer from the reader is what keeps the expensive work to a single run: the analysis happens once per deploy, both items read the same saved result, and anything else in your organization, such as reports or weekly summaries, can read it too, long after the run resolved.

💡 Tip: a failed risk_matrix item is not an error. It is how the deploy gets routed to the human approvals group, with the card explaining who has to approve and why.

✅ Checkpoint

Both workflows show as published. The reader's trigger lists deploy-gate-check as its kind.

Step 3: Record how critical each application is

The matrix needs to know how much each application matters. That is one metadata field, and applications without it are treated as critical, so forgetting one means more scrutiny rather than less:

/np-api create a "governance" metadata specification for applications with
a criticality field (mission_critical, critical, important, standard,
internal) if it doesn't exist, then set criticality for my applications:
payments-api is mission_critical, admin-dashboard is important, and the
rest are standard.

✅ Checkpoint

Reading any application's metadata shows its governance.criticality, and the ones you didn't classify simply don't have the key yet (the analyzer treats them as critical).

Step 4: Create the checklist that uses both

Now the checklist that puts both workflows in front of the deploy. One more prompt:

/np-checklist create a checklist for deployments of this application:

- An informational external item "Change analysis" of kind
"deploy-change-analysis", dispatched automatically when the run starts,
sending the deployment, release, scope, and application ids, with a
10-minute timeout.
- A blocking external item "Risk matrix approval" of kind
"deploy-gate-check", same inputs plus gate: risk_matrix.
- An informational external item "Already deployed (rollback fastpath)" of
kind "deploy-gate-check", same inputs plus gate: already_deployed.
- An override group "Human approvals" where a single approval unblocks:
- A manual item "Pair approval" requiring a comment, with a validation
that the approver is someone other than the requester.
- A manual item "Admin approval" requiring a comment, with a validation
that the approver holds the admin, ops, or secops role.

Associate it with the deployment:create approval action for this
application (create the action if it doesn't exist).

Three parts of that spec do the important work. The coupling to the workflows happens entirely through the two kinds, which is what lets the same pair of workflows serve every application you point at them. The override group with any-of aggregation means one human, not a committee, rescues a blocked deploy. And the validations make the rescue trustworthy: the four-eyes rule rejects self-approval at submit time, and the role rule keeps the admin path to people who actually hold the role.

✅ Checkpoint

The skill reports the checklist spec created and linked to the action. A dry run against a sample context shows the three external items pending and the human group idle.

Step 5: Review both workflows and activate them

In the nullplatform UI, open Platform Settings → Workflow Editor. The canvas shows both workflows: the analyzer's long sequence with its AI branch and its fallback branch, and the reader, which fits in three nodes.

On Gate Dispatch
Heartbeat: Analyzing
Gather the Diff
Resolve: Analysis Failed
Heartbeat: Diff Ready
Needs an AI Read?
AI Risk Read
Floors + Matrix
Resolve: Tell the Story
Persist the Decision
Deterministic Score
Resolve (Heuristic)
Persist (Heuristic)
Workflow
Deploy Change Analysis
Description

Resolves checklist items of kind deploy-change-analysis: diffs the deployed release against the candidate, scores the risk (signals + AI with hard floors), decides the approval mode with the risk matrix, and writes everything to deployment metadata.

Outputs (2)
risk
decision_mode
Triggers (1)
np-checklist-triggertrigger
Graph

13 steps

Click a node to see the step it runs.

Two things to notice:

  • The AI is one input, not the decision. Follow the analyzer's graph: the agent's score enters the same matrix step the fallback branch uses, and the minimum-risk rules can raise it but never lower it. Rollbacks and empty diffs never reach the agent at all.
  • The workflows never message each other. The reader polls the deployment's metadata and decides from that saved document. If the analyzer never writes it, the reader fails the item closed.

Activate both workflows when you are done reviewing them: ACTIVATE, next to RUN in the toolbar. Until then, the checklist would dispatch its items and never get an answer.

✅ Checkpoint

Both workflows show as active, each listing its kind on the trigger.

Step 6: Deploy and see the routing

Trigger a deployment of the gated application in your staging environment. What happens next depends on what you shipped:

  • A rollback or a small, safe change. The run resolves in seconds: the analysis card summarizes the change, the matrix item explains the auto-approval ("risk low × criticality critical"), and the deploy proceeds without notifying anyone. This is what happens to most deploys.
  • A medium change to a critical application. The matrix item fails with a card explaining what changed, why it is medium risk, and that any Pair approval unblocks it. A teammate opens the run, reads the analysis, and approves with a comment. The four-eyes validation would have rejected the requester approving their own deploy.
  • A migration, an auth change, or a large accumulation on a mission-critical application. The same flow, but the card names Admin approval, and only admin, ops or secops can give it.

In every case the run's event trail keeps the record: the diff stats, the risk and the reason for it, who approved and what they said. The change metadata saved on each deployment is also available to query for reporting.

✅ Checkpoint

A no-op redeploy of the same release resolves as a fastpath in under a minute; the matrix card says the release already ran in this scope.

Make it yours

  • Change the matrix, not the workflows. The routing table is a few lines in the analyzer's decision step: require a peer for important applications on medium risk, or let standard ones through on high risk, without touching the checklist spec.
  • Add the minimums your auditors care about. Anything the gather step can detect can raise the floor: changes under payments/, major dependency bumps, or a hotfix flag in the PR title.
  • Apply it only to the environments that need it. Set the approval action's dimensions, or an applies_when on the items, so production runs the matrix while development deploys skip it.
  • Report on the metadata. The analyzer already records change categories, participants, and the share of AI-authored commits per pull request. A weekly workflow can turn those into per-application summaries, and dashboards can read them from the lake.
  • Reuse the analysis in other checklists. The saved result is not reserved for the matrix: a second checklist spec on another action can read the same document through the same reader.

What you just built

How the pieces fit together

You have three pieces. The checklist spec declares what a deploy must satisfy. The analyzer workflow produces one verdict per deploy. The reader workflow turns that verdict into checklist answers.

The decision is short enough to read in full. The minimum-risk rules come first, then the matrix crosses risk with the criticality rank (1 = mission critical, 5 = internal):

if (sensitive.db_migrations) floors.push("db_migration");
if (sensitive.auth) floors.push("auth_change");
if (!from_release) floors.push("first_deploy");
const risk = max(scored, floors.length ? "medium" : "low");

if (previously_deployed) mode = "fastpath";
else if (risk === "low") mode = "auto";
else if (risk === "medium") mode = rank <= 2 ? "peer" : "auto";
else mode = rank === 1 ? "ops" : rank <= 3 ? "peer" : "auto";

The human side lives entirely in the checklist spec. The group's override behavior makes it the way to unblock a failed matrix item, aggregation: any means one approval is enough, and the validations decide whose approval counts:

{
"id": "human_approvals",
"type": "group",
"behavior": "override",
"aggregation": "any",
"children": [
{
"id": "pair_review",
"type": "manual",
"behavior": "gate",
"require_comment": true,
"validations": [
{
"id": "four_eyes",
"rule": { "actor.user_id": { "$ne": "$approval.requested_by" } },
"message": "Someone other than the requester must approve this deploy"
}
]
},
{
"id": "admin_review",
"type": "manual",
"behavior": "gate",
"require_comment": true,
"validations": [
{
"id": "admin_role",
"rule": { "actor.effective_roles": { "$in": ["admin", "ops", "secops"] } },
"message": "Requires admin, ops or secops role on this scope"
}
]
}
]
}

The important part is that the handoff happens through metadata. The workflows never talk to each other: the analyzer writes one document per deployment, and the reader polls for it and fails closed if it never appears. That split keeps the expensive analysis to a single run however many items read it, survives either workflow being redeployed mid-run, and leaves a queryable record on every deployment.

Building blocks used

BlockRole in this suite
Triggersnp-checklist-trigger subscribes each workflow to gate dispatches by kind
Nodescode-exec gathers the diff and runs the matrix; conditional skips the AI for rollbacks; np-checklist-item-progress and np-checklist-item-resolve talk back to the run
AI nodesclaude-code-agent reads the diff and returns a structured verdict, constrained by an output schema
Secrets and variablesThe GitHub token and the API key live as secrets, never in the definition
Runs and versionsEach deploy is one analyzer execution plus one reader execution per gate, with per-step logs feeding the audit trail

What's next