Assign permissions
Distinguish user permissions, actor grants, and the capabilities given to a subagent.
On this page
Sign-in and permissions
User permissions control a person's access to the application. An actor's function selection and technical grants control execution inside a run. Profiles provide plugins; user permissions do not create additional plugins or functions.
A profile can export users as readonly ProfileUser[]. Each user has an ID, label, password,
and exact permission strings. Passwords can be non-empty values or env(...) references. When
the export is absent, the profile runs without sign-in. An empty list, duplicate IDs, invalid
permissions, or missing required password variables prevent startup.
import { env, type ProfileUser } from "./apps/server/src/config-definition.js";
export const users = [{
id: "reader",
label: "Read-only access",
password: env("RAGENTS_READER_PASSWORD"),
rights: ["runs.read", "ragents.overseer.read"],
}] as const satisfies readonly ProfileUser[];
A user can also have a personal token through token: env("RAGENTS_TOKEN"). It acts as a bearer
token with the same identity and permissions as that user, but has no session expiry. It is
intended for clients without a sign-in dialog. The server stores only its SHA-256 hash. Removing
the token from the profile and restarting the server revokes it.
Permission names are exact strings; * grants all permissions. Without users or
anonymousUser, access is unrestricted. An optional anonymousUser applies the same permissions
and allowed templates without a password. It cannot be combined with users. With sign-in
enabled and no valid session, all permissions are denied.
Run ownership
A run belongs to the user who created it. Users normally see and operate only their own runs and
the runs shared with them; runs.read.all adds visibility across owners. Ownership is recorded
once in the journal and is never rewritten. Runs created without authentication have no owner and
are visible only with runs.read.all when authentication is later enabled.
With sign-in, the owner can share a run with every user of the profile, with individual users, or
both, each share with its own access. read shows the run with its chat, apps, and journal as far
as the user's own permissions allow, and its workspace unless only its owner may reach it, but
operates nothing: no messages, app actions, answers, run scripts, restarts, or stops
(run-read-only, status 403). write lets the user see and operate the run as runs.read.all
would, still only within their own permissions. A user gets the higher of the share for everyone
and their own. Only the owner and users with runs.read.all change whom a run is shared with, and
a share never permits deleting the run. The browser and VS Code offer this as the "Share run"
dialog from the run list and the run header (Share runs).
The server enforces ownership on lists, methods, event channels, and file routes before opening a
run. An inaccessible run responds like a missing one. Each signed-in user has a global coordinator
of their own, reachable by nobody else, not even with runs.read.all; its tools act with that
user's access and rights, and runs it creates belong to that user. Without sign-in there is exactly
one coordinator. A start option can additionally mark a run
as ownerOnly, as the workspace binding does for tools running on the owner's machine. Other
users with visibility may still read its journal and, unless it is shared with them for reading,
stop it, but only its owner can send messages,
answer actions, restart actors, or invoke operations requiring runs.write. Its workspace is the
owner's alone even for reading: the workspace files in the Files tab, the process rail, and
language-server state are refused to everyone else, including runs.read.all
(run-workspace-owner-only). The run list asks nothing from such a
workspace on their behalf, and web and VS Code hide what needs it; the Files tab then shows only
the server's file store.
Only a signed-in user of a profile with users can register a workstation over the network. A
server without users (open, ACCESS_TOKEN, or anonymousUser) has one owner for every client, so it
accepts a workstation only over a loopback connection and otherwise refuses with
workspace-client-login-required. The VS Code extension then does not register and shows the reason
on the server.
runs.write permits messages and app actions in existing owned runs. Free-form runs,
preparation chats, and start options additionally require runs.create. Without it, a user can
start only explicitly allowed run scripts. runs.inspect protects models, journals, source code,
tools, and general technical views. Language-server views use their own plugin read permission.
runs.trace separately reveals reasoning and function-call content in chat. Without it, those
phases appear only as empty progress markers while arguments, source, results, and reasoning are
removed on the server.
Function selection and actor grants
An engine capability is a technical permission such as workspace.use. A grant assigns it to
an actor for the run or a workspace path and records whether the actor may use or delegate it.
User permissions such as runs.write instead control access to application routes.
The tools value on spawn selects the actor's function API: [] for a plain LLM, a list of
names for an exact selection, or null for the dynamic full set. The selection is not inherited
from the coordinator. Delegable engine capabilities are inherited as grants and can be reduced
with withoutCapabilities. Prompt instructions describe a role but grant no technical access.
Actor programs also declare required functions under capabilities; this limits calls but does
not supply missing grants. The runtime guide
shows selections for conversation and coding agents.