Query-Scoped Permissions

Any grant in a role’s permission matrix can be narrowed with a query predicate — a condition the resource must satisfy for the grant to apply. This turns coarse permissions like Items: Edit into precise rules like “may edit items, but only safety-critical ones” or “may edit items, but only their own drafts”.

Query-scoped grants show as 🔍 in the permission matrix. Click a ✓ cell to convert it, or right-click a cell to open the predicate editor directly.

The syntax is the item search syntax

Predicates use the same query language as the item search input — if an expression works as a search filter, it works as a permission predicate. For example:

custom.safety_critical = true
status = "draft" AND created_by = $user.id
custom.asil IN ("C", "D")

Referring to the current user

Predicates can reference the acting user with $user variables, which makes one rule serve every user:

VariableResolves to
$user.idThe user’s ID, e.g. alice
$user.emailThe user’s email address
$user.display_nameThe user’s display name

created_by = $user.id is the classic example: every holder of the role may edit exactly the items they created themselves.

Referring to custom fields

Prefix custom fields with custom. to distinguish them from built-in fields: custom.safety_critical = true, custom.asil IN ("D", "C").

Worked examples

GoalGrant
Authors may edit only their own draftsItems: Edit where created_by = $user.id AND status = "draft"
Safety engineers may edit and approve only safety-critical itemsItems: Edit and Items: Approve where custom.safety_critical = true
A supplier sees only items assigned to themItems: View where assignee = $user.id

How predicates are evaluated

Three rules cover almost everything you will observe:

  1. An unconditional grant wins. If the user holds an unconditional ✓ for the same permission from any role, query-scoped grants for that permission are irrelevant — the action is allowed everywhere. You cannot use a predicate to restrict a permission another role already grants unconditionally; permissions are additive only.
  2. Any matching predicate allows. If all of a user’s grants for a permission are query-scoped, the action is allowed when at least one predicate matches the resource.
  3. Lists are filtered. Predicates don’t just gate single actions — a query-scoped Items: View filters item lists and search results, so the user only ever sees the items their predicate allows.

Note: A predicate that references an unset attribute matches nothing. For instance, assignee = $user.email for a user with no email simply never matches — it does not error, and it does not fall back to allowing everything.

Authoring tips

  • Prefer exact comparisons (custom.team = "safety") over contains-matches (custom.tag ~ "safety") — they are faster and easier to reason about.
  • Validate before rollout: use the Effective Permissions inspector with a concrete resource ID to confirm a predicate matches (or doesn’t) exactly as intended.
  • Reuse via inheritance: if many grants need the same predicate, put them on one parent role and let other roles inherit it.