---
title: Access rules
description: Grant readers access to paths and apply the rules during retrieval.
doc_version: 0.1.0-preview
last_updated: 2026-09-14
---

# Access rules

Create an enforced collection, grant readers access to paths, and pass trusted principals on Search and Query. Handle rule changes that require asynchronous work.

## Create an enforced collection

Use a cluster key or a namespace key with `write`. The example uses a separate collection named `people-docs`, so the quickstart collection can keep access control off.

**POST https://engine.example.com/namespaces/acme/collections**

```http
POST /namespaces/acme/collections HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json
Idempotency-Key: acme-people-docs-collection

{
  "name": "people-docs",
  "access_control": "enforced"
}
```

The response is a collection with `access_control: "enforced"`. Its initial root rule has `readers: []`. No content is retrievable until you grant readers access.

*Illustration: A trusted application sends user and group principals. The closest rule, or highest sealed ancestor, decides which content is allowed into Search and Query.*

## Grant access to a prefix

Grant HR readers access to `/hr/`. A folder target must end with `/`. Send exactly one of `folder` or `file`.

**POST https://engine.example.com/namespaces/acme/collections/people-docs/access-rules**

```http
POST /namespaces/acme/collections/people-docs/access-rules HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json

{
  "folder": "/hr/",
  "readers": [
    "group:hr",
    "user:u_8812"
  ],
  "sealed": false
}
```

**201 Created · when no existing files change governing rule**

```json
{
  "id": "acr_01J8Z3K4N5P6Q7R8S9T0V1W2X3",
  "folder": "/hr/",
  "readers": [
    "group:hr",
    "user:u_8812"
  ],
  "sealed": false,
  "created_at": "2026-10-06T12:00:00Z",
  "updated_at": "2026-10-06T12:00:00Z"
}
```

If existing files must move under this rule, the response is `202` with `{ "rule": ..., "job": ... }`. That notation describes the response fields, not literal JSON. Wait for the job’s success event. Affected files remain hidden from retrieval until it completes.

A rule can precede its files. Add `/hr/handbook.pdf` using [Add file](/engine/guides/add-a-file), then wait for processing. To grant collection-wide access, create or update the root folder target `/`.

## Send trusted principals

Your application authenticates the person and resolves every relevant group. Send those exact strings to Engine. Engine does not expand groups or authenticate the supplied names.

**POST https://engine.example.com/namespaces/acme/collections/people-docs:search**

```http
POST /namespaces/acme/collections/people-docs:search HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json

{
  "query": "annual leave",
  "principals": [
    "user:u_8812",
    "group:hr"
  ],
  "mode": "semantic"
}
```

Use the same `principals` field on Query. Missing principals on an enforced collection return `400 invalid_request`. An empty list allows no content. Sending principals to a collection with access control off also returns `400 invalid_request`.

> **Keep the principal list trusted**
>
> Compute principals in your backend. An untrusted browser must not select the user or groups that Engine should treat as authorized. A cluster key does not bypass these rules.

## Understand inheritance and sealing

| Rule | Effect |
| --- | --- |
| Folder /hr/ allows group:hr | HR can retrieve files below /hr/. |
| Folder /hr/comp/ allows group:hr-leads | Only HR leads can retrieve that subtree. Readers replace the parent list. |
| File /hr/handbook.pdf allows group:all-staff | The file rule overrides the unsealed HR folder rule. |
| Folder /hr/ sealed for group:hr | This rule governs every descendant. Deeper rules have no effect. |

The highest sealed ancestor governs when more than one sealed folder covers a file. Otherwise, the closest rule governs. A file rule cannot be sealed. Paths are case-sensitive: `/HR/` and `/hr/` are different targets.

## Change readers and rules

To change some readers without replacing the whole list, use `add_readers` and `remove_readers`. A principal cannot appear in both lists. Do not combine either list with `readers`.

**PATCH https://engine.example.com/namespaces/acme/collections/people-docs/access-rules/acr_01J8Z3K4N5P6Q7R8S9T0V1W2X3**

```http
PATCH /namespaces/acme/collections/people-docs/access-rules/acr_01J8Z3K4N5P6Q7R8S9T0V1W2X3 HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json

{
  "add_readers": [
    "user:u_9001"
  ],
  "remove_readers": [
    "user:u_8812"
  ]
}
```

Reader-only changes return `200` and apply on the next request. Creating, deleting, or sealing rules can change which rule governs files. Those changes can return an `apply_access_rule` job. The root rule cannot be deleted.

Use [Batch access rules](/engine/reference/batch-access-rules) when several changes must succeed together. The batch requires an idempotency key. An invalid operation fails the whole batch. A conflicting running rule job returns `409 operation_in_progress`.

## Keep writes and filters separate

Access rules control retrieval. They do not authorize human file changes. Your application checks a person’s write permissions before it uses an API key with `write`.

Metadata filters select relevant data. They do not secure it, because the API caller can omit them. Engine applies access rules before a file contributes evidence or answer content.

See [Create access rule](/engine/reference/create-access-rule), [Update access rule](/engine/reference/update-access-rule), and [Principals and access rules](/engine/concepts/access) for the detailed contract.
## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
