NorthlightSDK
Concepts

Scopes and grants

A scope is what your app may ask for, a grant is what one person allowed, and a run's scopes narrow it further.

Three things limit what your app can do for a person: the scopes your app may ask for, the grant that person approved, and the scopes list of each run you start. Each can only narrow the one before.

LayerSet byWhere
What the app may ask forYouThe console, app page, What it asks for tab → Add permissions
The grantOne personThe consent page, when they connect your app
A run's scopesYour coderuns.start({scopes: […]})

What your app may ask for

An app can only ask for scopes it has been given. A new app starts with crtr:llm and crtr:act. On the What it asks for tab, Add permissions searches the full list: agent access, parts of the person's space, and the tools of each provider. Take scope strings from that list or from providers.tools. Do not invent them. Without sms:send on the list, the consent page does not offer it and providers.call for sms is refused.

The same tab holds What your app requires (providers the app does not work without: see Providers) and Monthly spend cap, the most your app can spend on each person's AI subscription in a month. People see the cap on the consent page.

The protocol scopes

openid, email and profile are available to every app and are not saved in the list. You request them in authorizeUrl for sign-in: openid for the person's id, email for their email, profile for their name and photo. A request with only these scopes signs the person in without creating a grant or a connection.

The grant

When a person connects your app, the consent page shows each scope you asked for and the spend cap. What they approve is the grant. Your authorizeUrl should request only the scopes your app uses, because the grant holds what was requested and approved. A person can change or remove the grant from their Northlight account. Link to that page with await oauth.accountAppUrl(); never build the path yourself.

If you change what the app asks for, people already connected approve the new list the next time they sign in. Lowering the spend cap applies to everyone at once; raising it reaches each person only after they approve again.

What each scope gates

A run can only do what the grant holds and the run's own scopes allow. Narrowing a run's scopes removes abilities, so pass the smallest list that works.

ScopeA run (or your server) with it canWithout it
crtr:llmUse the person's AI subscription for the run's model calls. List it in every run's scopes.The run has no model access.
crtr:actStart runs (runs.start) and use a shell. Every bash call on the hosted (Linux) runtime needs it.runs.start is refused with 403 scope_missing. Add it on the What it asks for tab and list it in the run's scopes.
crtr:scheduleCreate, pause, resume and run schedules.Schedule calls are refused.
crtr:memory:read:user, crtr:files:read:user:., crtr:files:rw:user:.Read the person's documents beyond their public ones; read or write the person's files.The run sees only the person's public documents and its own app space.
sms:send (a provider scope)Call the sms provider's send tool, which texts the person's own verified phone.providers.call is refused.

crtr:act requires crtr:llm, so drop both together. A run that only reasons and submits a typed result needs only crtr:llm.

Other scopes follow the same shape. A provider scope is <provider>:<tool group>; see Providers. Scopes for the person's files and documents are named crtr:files:… and crtr:memory:…; copy them from Add permissions.

A run's scopes

await runtime.runs.start({prompt, scopes: ['crtr:llm']});

A run's list must stay inside the grant, and a child agent never regains a scope its parent's list dropped. Leaving scopes out gives the run everything the grant holds. Prefer a list.

Your app's own space

Your app has its own space on each person's runtime: documents and files owned by your app. Your server and runs started without a scopes list read and write it freely. A run started with a scopes list needs crtr:memory:read:app:<your client id> or crtr:memory:rw:app:<your client id> to touch it. Another app's space is reachable only where that app allows it.

Checked and not checked

From the SDK source, the directory console source and the existing SDK guide. 403 scope_missing for a missing crtr:act and the consent page's behavior are not yet checked on production.

On this page