Scopes
Complete reference for Nenjo's scope system covering API keys, platform scopes, and mode escalation.
Scopes
Scopes control what actions an API key, agent role, or mode session can perform. They apply consistently across the MCP server, worker execution, and mode system.
Scope Format
Scopes follow the pattern resource:permission:
tickets:read
tickets:write
projects:writeEach resource group has a :read and :write scope (except chat and graph, which are read-only).
Complete Scope Reference
| Scope | Description |
|---|---|
tickets:read | List and get tickets |
tickets:write | Create, update, and delete tickets |
projects:read | List and get projects |
projects:write | Create and update projects |
documents:read | List documents and read content |
documents:write | Delete documents |
pipelines:read | List and get pipelines, steps, and edges |
pipelines:write | Create, update, and delete pipelines, steps, and edges |
executions:read | List and get execution runs |
executions:write | Create execution runs and send commands |
agents:read | List and get agents and agent roles |
agents:write | Create, update, and delete agents |
councils:read | List and get councils |
councils:write | Create, update, and delete councils |
chat:read | List chat sessions and messages |
graph:read | Get dependency graphs and execution order |
Total: 16 scopes across 8 resource groups.
Scope Rules
Write Implies Read
A :write scope automatically grants the corresponding :read scope for the same resource. If a key has tickets:write, it can also perform tickets:read operations without explicitly listing both.
Empty Scopes = Full Access
An API key or role with an empty scopes array has unrestricted access to all resources. This is the default when creating a key without specifying scopes.
Scope Checking Logic
The scope check follows this logic:
- If the scopes array is empty, access is granted (full access).
- If the exact scope is present, access is granted.
- If the requested scope is
:readand the corresponding:writescope is present, access is granted. - Otherwise, access is denied.
Where Scopes Apply
Scopes are used in three contexts with consistent behavior:
API Key Scopes
When you create an API key, the scopes field restricts which MCP tools are accessible. The tools/list response only includes tools whose scope is satisfied by the key's scopes.
{
"name": "Read-only Key",
"scopes": ["tickets:read", "projects:read", "executions:read"]
}This key can call tickets_list, tickets_get, projects_list, etc., but cannot call tickets_create or any write tool.
Platform Scopes (Agent Roles)
Each agent role has a platform_scopes field (TEXT[] in the database) that controls which MCP tools the worker makes available when building the agent's tool set. These scopes are checked at agent build time and work identically to API key scopes.
Platform scopes are configured per role and are seeded with sensible defaults for system roles.
Mode Additional Scopes
Modes can temporarily escalate an agent's platform scopes for the duration of a mode session through the additional_scopes field in the mode's ModeToolConfig:
{
"additional_scopes": ["tickets:write", "projects:write"]
}When a mode session is active, the worker merges these additional scopes with the role's base platform_scopes before filtering MCP tools. This allows modes like /the-creator to grant write access that the role does not normally have.
Scope Inference on the Worker
The worker's MCP client infers required scopes from tool names when filtering tools for a role:
| Tool Name Pattern | Inferred Scope |
|---|---|
list_*, get_* | resource:read |
create_*, update_*, delete_* | resource:write |
The resource name is derived from the tool name prefix (e.g., tickets_list infers tickets:read). This inference is a fallback -- the canonical scope is always the one defined in the tool's ToolDef.scope field in the registry.
Examples
Minimal read-only key
curl -X POST \
-H "Authorization: Bearer <clerk-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Dashboard Reader",
"scopes": ["tickets:read", "projects:read", "executions:read"]
}' \
https://your-instance/api/v1/api-keysFull-access key (no scopes)
curl -X POST \
-H "Authorization: Bearer <clerk-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Worker Full Access"
}' \
https://your-instance/api/v1/api-keysWrite-only for a specific resource
curl -X POST \
-H "Authorization: Bearer <clerk-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Ticket Manager",
"scopes": ["tickets:write"]
}' \
https://your-instance/api/v1/api-keysThis key can read and write tickets (:write implies :read) but has no access to any other resource.