RAgents
Guide: Assign permissions

Guide

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.

Source: docs/spec/profiles.md. This chapter as Markdown.

Back to the guide