> For the complete documentation index, see [llms.txt](https://docs.aviator.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.aviator.co/verify/setting-up-org-invariants.md).

# Setting up org invariants

Invariants are rules that apply to every matching change. Instead of asking the agent to assert "requires authentication" on every submission, you encode it once. Every matching review is then checked automatically.

In this tutorial, you'll create a security invariant by hand, watch the selector pick it up, and learn how it appears in a real verification run.

**Time:** \~10 minutes

**Prerequisites:**

* At least one repository connected to Verify.
* Familiar with [How Verify works](/verify/how-it-works.md) and [Concepts: Invariants](/verify/concepts/invariants.md).

### Step 1: Open the invariant editor

Go to **Verify → Invariants** and open the **Library** tab.

You'll see the invariant catalog — every active entry your account has, grouped by category. AI-drafted entries (from PR-comment mining or docs extraction) wait on the **Review** tab until they're [approved](/verify/concepts/invariants.md#owner-teams).

For this tutorial, you'll create a manual entry.

### Step 2: Create a new invariant

Click **New invariant** and give it:

* **Title:** `auth-required-on-handlers`
* **Category:** `security`
* **Source:** `manual` (set automatically when you create from the UI)

Pick a title you'll be okay with seeing in the audit trail — every verdict references it.

### Step 3: Write the body

The body is the assertion the verifier will check. Keep it specific about the assertion, vague about the implementation:

```
All HTTP handlers must call an authentication middleware before any
business logic. Endpoints that intentionally accept anonymous traffic
must declare themselves as exceptions (see Conditions below).
```

A few rules (covered in depth in [Invariants — Writing a good invariant](/verify/concepts/invariants.md#writing-a-good-invariant)):

* Don't name specific functions or modules — the rule should survive renames.
* Don't write the *fix* — the verifier will explain what's wrong.
* If you need "do X *except* when Y," use conditions or accept that the selector will pass on Y-shaped changes.

### Step 4: Add conditions (optional)

Conditions gate when the invariant is *eligible* to apply. Most invariants don't need them — leave them empty and the invariant is eligible for every review.

For this security rule, add a condition if you want to scope by language:

* **Condition type:** `file_path_glob`
* **Pattern:** `src/**/*.go`

This makes the invariant eligible only when a review touches Go files under `src/`. See [Invariant conditions](/verify/reference/invariant-conditions.md) for glob syntax, language tags, and how conditions combine.

Eligibility doesn't mean the invariant applies — the selector still decides per review whether it's a defensible match. Conditions are useful for hard exclusions, not fine-grained scoping.

### Step 5: Save

Click **Save**. Manual invariants are active as soon as you save.

From this point on, the selector considers this invariant for every new review. When it picks the invariant for a review, it materializes it as an acceptance criterion (tagged with `source: baseline_invariant`) and the criterion is verified through the standard pipeline.

### Step 6: Turn it off when you need to

To pause the invariant without deleting it, open its edit page and turn off the **Enabled** switch under **Status**. The selector skips disabled invariants until you turn it back on.

### Step 7: Watch it in a real review

Trigger a verification on a PR that touches Go files under `src/`. Open the review document.

If the selector picked your invariant for this change, you'll see a criterion in the criterion list tagged as an invariant. It runs alongside the user-supplied criteria. Verdict + evidence are produced the same way.

If the selector *didn't* pick it, that's fine — the LLM judged it didn't apply to this change. Look at the review's spec and scope: does the rule actually apply here? If yes and the selector missed it, the rule body may be too vague.

### Step 8: See a violation

Push a change that intentionally violates the rule — for example, a handler that skips the middleware:

```go
func (h *Handler) PublicEndpoint(w http.ResponseWriter, r *http.Request) {
    // No auth middleware called
    w.Write([]byte("hello"))
}
```

The next verification run shows the invariant criterion as failed:

```
✗ auth-required-on-handlers (invariant)
  Handler PublicEndpoint at src/handlers/public.go:23 does not call an
  authentication middleware before responding.
```

The verdict explains the failure but doesn't prescribe the fix — that's deliberate.

### Step 9: Waive when appropriate

If a verdict is wrong or doesn't apply, the reviewer can waive it with a categorized reason: `false_positive`, `doesnt_apply`, `accepted_risk`, or `fix_in_followup`. Waive from the review document, from the [Verify tab on the pull request](/verify/how-to-guides/verify-on-github.md), or with [`aviator dismiss`](/verify/reference/cli.md#aviator-dismiss). Every waiver is recorded in the audit trail.

If you find yourself waiving the same invariant repeatedly, the rule is wrong. See [Concepts: Invariants — Waivers](/verify/concepts/invariants.md#waivers).

### What you just did

* Created a manual invariant in the account catalog.
* Wrote a rule body that's specific about the assertion but doesn't prescribe implementation.
* Added a glob condition to scope eligibility by language.
* Saved it, at which point the selector started considering it.
* Saw it materialize as a criterion in a real review and produce a verdict.

### Next steps

* [Concepts: Invariants](/verify/concepts/invariants.md) — sources (including AI-from-PR-comments), conditions, categories, waivers.
* [Verification layers](/verify/concepts/verification-layers.md) — how invariants compose with user criteria.
* [Understanding verification results](/verify/how-to-guides/understanding-verification-results.md) — what reviewers do when an invariant verdict goes red.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.aviator.co/verify/setting-up-org-invariants.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
