---
title: Checklists
sidebar_label: Checklists
toc_max_heading_level: 3
doc_id: 3f8a1c92-7d4e-4b16-9c53-2e6f8a41d7b0
description: >-
  Create your organization's guardrails as checklists: requirements that
  evaluate themselves, human sign-offs, and external validations that must pass
  before a deployment, a secret read, or a scope change goes through.
keywords:
  - checklists
  - checklist specifications
  - approvals
  - guardrails
  - governance
  - deployments
  - compliance
  - nullplatform
---

import LearningPath, { LearningPathRow } from '@site/src/components/LearningPath';

# Checklists <span className="heading-release-pill">New</span>

:::info 🚀 Early release

Checklists are in early release and may not be enabled in your organization yet. If you'd like to try them or want to know more, [reach out to us](https://docs.nullplatform.com/docs/support) and we'll get you set up.

:::

A **checklist** is the list of requirements that must pass before a protected action goes through: a deployment, a secret read, a scope change. 
- Some items check facts automatically, 
- some wait for a person to sign off, and 
- some hand the check to one of your own systems. 

Every item shows its own status, so the developer who triggered the action sees what passed, what's still running, and who owes a signature.

That list is where your organization's guardrails live. Instead of a runbook nobody reads, the rules that govern an action are declared once, applied on every request, and recorded item by item for the audit.

## Checklists vs policies

:::warning Upcoming deprecation

Policies will be deprecated in favor of checklists. Start any new guardrail as a checklist. If you want to migrate policies to checklists, [reach out to the nullplatform team](/docs/support).

:::

Both guard the same actions from the same Approvals area. The difference is the shape of the answer.

- A [**policy**](/docs/approvals/policies) answers one question: do these conditions hold, yes or no? All its conditions resolve to a single verdict.

- A **checklist** turns that single verdict into the list of requirements behind it, each with its own status, owner, and result. A policy gives you the answer; a checklist shows the requirements that produced it, so the developer waiting knows which one is missing and the person signing off knows what they're signing.

### Migrate policies into checklists

If you're already running on policies, you don't have to rebuild anything. A policy that grew past a single condition is usually a checklist waiting to happen, and checklists use the same condition language and the same field paths, so your predicates carry over unchanged.

If you want to move an action from policies to a checklist, [reach out to the nullplatform team](/docs/support).

## What a checklist is made of

Three pieces carry the feature:

- A **checklist specification**, spec for short, is the versioned definition of the requirements: authored once, reused on every request. The nullplatform UI lists them under **Platform settings > Approvals > Checklists**, where **+ New specification** creates one. Specs and their lifecycle live in [Specs and actions](/docs/approvals/checklist-specs).
- **Items** are the requirements inside a spec. There are four item types and one list can mix them, so a single checklist can check facts automatically, wait for a person, hand a check to one of your systems, and group related requirements together.
- A **run** is one instantiation of the spec against one request: the thing developers actually see and auditors actually read.

Here's a complete spec, the same two-item gate you'll build in [your first checklist](/docs/approvals/your-first-checklist):

```json
{
  "name": "first-gate",
  "definition": {
    "items": [
      {
        "id": "coverage_gate",
        "type": "condition",
        "behavior": "gate",
        "title": "Build coverage above 80%",
        "query": { "build.metadata.coverage.lines.percent": { "$gte": 80 } }
      },
      {
        "id": "release_signoff",
        "type": "manual",
        "behavior": "gate",
        "title": "Release owner sign-off"
      }
    ]
  }
}
```

In that spec, the `condition` item type resolves on its own the moment a run is created, and the `manual` item type waits for a person. Those are two of the four types:

| Item type | What it does |
|---|---|
| `condition` | Evaluates a query against the request context, like coverage or environment |
| `manual` | Waits for a person to sign off, with their identity recorded |
| `external` | Hands the check to one of your systems, typically a workflow, and waits for the result |
| `group` | Nests other items to organize the list |

Each item also declares a **behavior**, which decides what its result does to the action: a `gate` item stops the action when it fails, an `informational` item reports without ever blocking, and an `override` lets an authorized person send the action through even though a `gate` item failed. The [items reference](/docs/approvals/checklist-items) covers every type, behavior, and status in detail.

## How a run works

A run starts when a developer triggers one of the operations the checklist governs: creating a deployment, reading a secret, changing a scope. Which operations those are is decided by the [approval action](/docs/approvals/actions) the spec is attached to, so the same checklist can guard deploys in one account and secret reads in another.

From there, nullplatform creates an approval request, instantiates the spec into a run, and starts resolving it: conditions evaluate immediately, external items are dispatched, and everything else waits for humans or callbacks.

```mermaid
flowchart TD;
    A["Developer triggers a governed operation"] --> B["Run instantiated from the spec"];
    B --> C["Conditions evaluated, external items dispatched"];
    C --> D["Humans sign off, systems call back"];
    D --> E["Outcome computed: approve, override, or fail"];
    E --> F["Action proceeds or stays blocked"];

    classDef np fill:#e6faf4,stroke:#00b894,color:#1a1a1a;
    classDef infra fill:#eef3fb,stroke:#274a86,color:#1a1a1a;
    class B,C,E np;
    class A,D,F infra;
    linkStyle default stroke:#9aa5b1,stroke-width:1.5px;
```

When the run is created, nullplatform snapshots both the spec and the request context into it. Those snapshots are immutable, which has two consequences worth knowing before you author anything:

- **Conditions are evaluated once**, at the moment the request is created. They don't re-evaluate while the approval sits open, so a checklist judges the request as it was submitted.
- **Editing a spec never rewrites history.** In-flight runs keep evaluating the version they started with, and the audit trail shows exactly what was checked.

## What your developers see

Once a checklist is live, the developer who triggers the action gets the list instead of a verdict. Items that evaluate automatically already show their result, external checks report as they call back, and anything waiting on a person says so.

<img src="/img/approvals/checklist-run.png" alt="A checklist run on a deploy: two conditions already passed with the values they read, a Jira external item in progress after creating a ticket, a security sign-off waiting on a person, and the deploy button disabled while two of four blocking items are done" width="100%" className="helper-image" />

Manual items collect a decision and a comment from a named person, and the run keeps that on record: who signed off, what they said, and when.

An override never turns a failed item into a passing one. The item stays failed and the run resolves as `approve_with_override`, so the record shows that the action went through despite the failure, and who decided it should.

A failing item doesn't end the request either. By default it stays open and resumable: the developer reads which item failed, fixes the cause, and redeploys, or asks for a manual review when the call needs a human. How failures route is [configurable per action](/docs/approvals/checklist-specs#choose-what-a-failed-run-does).

Every transition lands in an event trail per run, and external items keep their own logs, which is what makes a checklist answerable to an auditor: not just what was decided, but what was checked, when, and by whom.

## Learning path

<LearningPathRow>
  <LearningPath
    title="From a first checklist to autonomous compliance"
    steps={[
      {
        label: "Your first checklist",
        href: "/docs/approvals/your-first-checklist",
        note: "Describe a two-item gate to your coding assistant, dry-run it, and watch it govern a real deploy.",
        time: "10 min",
      },
      {
        label: "Gate deploys on a Jira ticket",
        href: "/docs/tutorials/jira-approval-gate",
        note: "A person decides, Jira mediates: approvals in the tool your team already uses.",
        time: "20 min",
      },
      {
        label: "Match friction to deploy risk",
        href: "/docs/tutorials/deploy-risk-matrix",
        note: "A risk matrix scores every deploy and routes it to exactly the approval it deserves.",
        time: "25 min",
      },
      {
        label: "AI architecture compliance",
        href: "/docs/tutorials/ai-architecture-compliance",
        note: "An agent audits every deploy against your architecture rules, one execution per rule.",
        time: "25 min",
      },
    ]}
  />
</LearningPathRow>

:::tip Want the full contract?
The [items reference](/docs/approvals/checklist-items) covers every item type, behavior, status, and validation rule, and [Specs and actions](/docs/approvals/checklist-specs) covers the API, failure routing, and roles.
:::
