Skip to main content
A scope describes which entities you mean. You write it as a CQL string (cql) or a structured filter (filter), preview what it matches, then compile it into context your agents consume. The same scope grammar drives ad-hoc preview, slice authoring, and compilation.

Scope: CQL or a structured filter

Both express the same thing with names, not UUIDs. cql is canonical if you pass both. New to CQL? Start with the CQL page.
// CQL string (terse)
{ cql: 'type:Company shape:"Account Intelligence" after:7d' }

// Structured filter (discoverable; the only form for property predicates)
{ filter: {
    types: ["Company"],
    shapes: ["Account Intelligence"],
    properties: [{ path: "stage", operator: "eq", value: "alpha" }],
    after: "2026-01-01",
} }
Membership tokens: type: (entity type names, union), shape: (one shape per scope), source: (source file names), source-shape:"file"->"shape", and after: / before: (created-at bounds). Same-kind tokens union; different-kind intersect.

Relative dates

after: / before: accept absolute ISO (YYYY-MM-DD) or relative expressions, resolved to absolute time server-side (UTC):
FormMeaning
last-week, last-month, last-yeara week / month / year ago
today, yesterday, nowstart of today / yesterday / this instant
7d, -7d, 2w, 12h, 3mo, 1yN units ago (sign ignored; past-only)

Honest warnings, never silent drops

Anything a scope can’t express comes back in scope_warnings instead of being dropped silently:
  • edge:, agent:, sort:, and free text are query/ranking concerns, not membership. They are ignored with a warning.
  • A second shape:, an unresolved shape/source name, or a malformed date each produce a warning.
  • Property predicates and gt / lt operators are available only on the structured filter, not in the CQL string.

Preview a scope

Preview resolves a scope to a matched count plus warnings, without saving. It is fast author-time feedback.
const preview = await pb.context.preview({ cql: "type:Company after:7d" });
// { matched: 4, scope_warnings: [], counts: { entities: 4, ... } }

Compile a scope or slice

Compile turns a scope, or a saved slice, into a CompiledContext payload your agents consume.
const compiled = await pb.context.compile({ slice_id: sliceId });
// or ad-hoc:
const adhoc = await pb.context.compile({ cql: "type:Concept type:Metric" });
When your key is scoped to a single project, the project is implicit. Otherwise pass project_id (or the X-Penumbra-Project header).

Method reference

MethodRESTDescription
pb.context.preview(scope)POST /v1/context/previewResolve a scope to a matched count + warnings.
pb.context.compile(scope)POST /v1/context/compileCompile a scope (or slice_id) into context.
pb.context.discover(input)GET /v1/context/discoverFind candidate types/sources/slices to scope from.

Slices

Save a scope under a name and reuse it.

CQL

The full scope-string grammar.