crouter
Concepts

Scopes and trust

When giving an application or node less authority, read this because a scope list is an allow-list enforced by the daemon and a bearer token can set the maximum authority for every run it creates.

Use scopes to give a node or remote application only the authority it needs. A node carries a scope list; a scoped bearer token carries a ceiling. Omitting a node scope list gives it the inherited runtime vocabulary. Supplying one narrows that authority. A token cannot create a node with scopes outside its own ceiling.

Scope strings are prefixed with crtr:. These are the ones the daemon and CLI check:

ScopeIt gates
crtr:llmDaemon-mediated model calls (POST /v1/llm) and starting a run
crtr:actCreating, forking, reviving, closing and messaging nodes; bash and files; creating a human request or review (the crtr human commands are hidden from a run without it)
crtr:scheduleCreating, pausing, resuming, running and deleting crons (the crtr cron commands are hidden without it)
crtr:memory:read:user[:path], crtr:memory:rw:user[:path], crtr:memory:manage:userThe person's documents: reading, writing (crtr doc), and manage for every privacy level and every document
crtr:memory:read:app:<id>, crtr:memory:rw:app:<id>Another app's documents; …:profile:<profile> narrows to one of its profiles
crtr:files:read|rw:user:<dir>, crtr:files:read|rw:app:<id>:<dir>, crtr:files:shareHost files the run may mount, and sharing files beyond the app's own space
crtr:conversations:read:app:<id>, crtr:objects:read:app:<id>Reading another app's conversations or node objects
<provider>:<group>One tool group of a provider

The memory in crtr:memory:* is the scope family's name for access to documents (see Documents); there is no separate memory store. The older short names (ask, act, schedule, memory:read, memory:write, llm) are not accepted by crtr sys connect --scopes. A node's own documents, and an app's documents for its own nodes, need no crtr:memory scope.

This is an allow-list, not a claim that code will behave. The daemon checks the scope at the route that performs the action and rejects an unavailable one. The SDK’s nodes.create scopes field narrows a run: a run's list must stay inside what its creator and grant hold, and crtr:act requires crtr:llm. client.memory is not scope-gated: it lists and reads the person's knowledge and preference documents, and the answer is filtered by privacy — an app sees public documents, and a grant holding crtr:memory:manage:user also sees friends and private ones. Who may read any document is the owner-and-privacy model, not a per-call scope.

Scopes rely on a more basic trust boundary: crtrd is the sole writer of durable canvas state and the sole owner of broker lifecycle. SDK clients, the CLI, and viewers call its API; they do not open the canvas database or launch their own broker. One owner serializes lifecycle changes, makes the same API usable locally and remotely, and keeps a client from silently creating a second state authority.

For a browser or remote process, run crtr sys connect. It enables the daemon’s TCP listener when needed and returns base_url plus a bearer token to give the application. crtr sys connect --app <id> --scopes … mints a new scoped token for that app instead of returning the owner token; --scopes requires --app, and accepts crtr:llm, crtr:act, crtr:schedule, crtr:memory:read:user, crtr:memory:read:app, crtr:memory:rw:app, crtr:files:read:user:. and crtr:files:rw:user:.. Treat either token as a credential: the remote app sends it as Authorization: Bearer <token>, and its scope list is the ceiling for scope-gated calls and newly created nodes.

The remote API is an explicit boundary, not permission to reach around it. Keep application code on the SDK or /v1 contract, and let the daemon own state transitions. Run crtr canvas read internal/nodes-and-canvas for the operational ownership model.