---
id: scope-context
title: 'Scope Context and Filtering'
description: 'The scope context - how Agility narrows the Scope hierarchy for filtering, and how Rooms embody it'
sidebar_label: 'Scope Context'
sidebar_position: 7
tags: ['guides', 'scope', 'filtering']
---

Much of the Agility application is looking at work **through a subset of
the Scope tree** — a *scope context*. Understanding it explains a lot of
filtering behaviour, and gives you the same idioms the product uses.

First, a naming note: the `Scope` asset type has worn two display names —
**Project** originally, and mostly **Planning Level** in current versions.
All three words mean the same asset type.

## What a Scope Context Is

A scope context is the set of scopes defined by:

1. a **root scope** — the context includes it and its subtree, and
2. optional narrowing by **`Schedule`** and **`ScopeLabels`** — keeping
   only subtree scopes on a given sprint schedule, or carrying a given
   label. (`ScopeLabel` is displayed in the UI as **Program** — another
   naming split worth knowing.)

## The One-Query Idiom

The subtree-membership filter from [Relations](/concepts/relations) takes
the narrowing inside its bracket filter — and `with` variables keep the
values out of the expression:

```json
{
  "from": "Story",
  "filter": ["Scope.ParentMeAndUp[Schedule=$Sched;ScopeLabels=$Label]=$Scope"],
  "select": ["Number", "Name", "Scope.Name"],
  "with": {
    "$Sched": "Schedule:1064",
    "$Label": "ScopeLabel:2001",
    "$Scope": "Scope:1308"
  },
  "page": { "size": 50, "start": 0 }
}
```

Read it as: *the story's scope has, among its ancestors-or-self that are on
`$Sched` and carry `$Label`, the root `$Scope`* — i.e. the story is in the
narrowed subtree. Drop either bracket term if you are not narrowing by it.

## The Precompute Pattern for Large Hierarchies

When the scope tree is large, evaluating the traversal per asset gets
expensive. It is often more efficient to **build the scope context once**,
then filter assets against the set — and `with` variables accept **arrays**,
which the filter treats as an in-list match:

```json
{
  "from": "Scope",
  "filter": ["ParentMeAndUp=$Root", "Schedule=$Sched"],
  "select": ["Name"],
  "with": { "$Root": "Scope:1308", "$Sched": "Schedule:1064" },
  "page": { "size": 200, "start": 0 }
}
```

```json
{
  "from": "Story",
  "filter": ["Scope=$Context"],
  "select": ["Number", "Name"],
  "with": { "$Context": ["Scope:1308", "Scope:1450", "Scope:1451"] },
  "page": { "size": 50, "start": 0 }
}
```

The same array-variable technique works on `query.v1` and the Bulk API's
query command.

## Rooms Are Scope Contexts

One of the most important things a Room — `TeamRoom` or `PlanningRoom` —
represents **is a scope context**: its `Scope` and `Schedule` define the
slice of the tree the room looks at.

Visibility follows from that in a way worth stating precisely:

- **Every member can view every room** — rooms themselves are not
  permission-gated.
- **What a member sees *inside* a room is gated by their scope access** —
  the room shows each viewer the intersection of its scope context with
  the scopes their [role grants them](/reference/roles-and-permissions).

Two members can open the same room and see different content; neither is
broken.

## Related Topics

- Product feature: [Planning level
  workspaces](https://docs.digital.ai/agility/docs/agility/planning-level-workspace) — what the scope tree this
  guide filters against means to users.

- [Relations](/concepts/relations) — `ParentMeAndUp` and the rollup relations
- [Scopes and projects](/concepts/scope-projects)
- [Rooms & panels](/apis/rooms/panels)
- [Roles and permissions](/reference/roles-and-permissions)
