# Permission Sets

# Permission Sets

Permission Sets give organization admins fine-grained, scoped control over what members can do with the resources — **agents, corpora, and workflows** — who can view, edit, delete, publish, and create them, and how widely that access reaches. You compose a named bundle of scoped permissions and assign it to users.

Think of a permission set as a reusable access profile. You might create a “Content Editors” set that lets members view every agent in the organization, edit the agents on their own team, and edit only the corpora they own, and a separate “Admins” set that grants full control over all three resources. Members inherit the combined access of every set assigned to them, always resolving to the union of scopes they hold.

## How It Works

Every permission set is scoped to a single organization and defines access to a resource through a combination of actions and scopes.

| **Concept** | **What it means**                                                                                 |
| ----------- | ------------------------------------------------------------------------------------------------- |
| Resource    | The kind of object the permission applies to: agents, corpora, or workflows.                      |
| Action      | What the member is allowed to do: view, edit, delete, publish, or create. Not every resource supports every action — see Resources and their actions below. |
| Scope       | How far the action reaches — from a user’s owned resources all the way to the whole organization. |
| Principal   | Who the set is assigned to. Currently users.                                                      |

Scope grants are written at the organization level rather than per-member, so assigning or updating a permission set propagates to every affected member in constant time.

### Resources and their actions

The three governed resources do not all take the same actions or the same scopes. The differences follow the shape of each resource in the product rather than an arbitrary choice:

| **Resource** | **Scoped actions**          | **Available scopes**    | **Boolean** | **Why it differs**                                                                                                     |
| ------------ | --------------------------- | ----------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
| agents       | view, edit, delete, publish | all, project, team, own | create      | Agents live inside projects and have a staging → production publish step.                                               |
| corpora      | view, edit, delete          | all, team, own          | create      | A corpus belongs to the **organization**, not to a project, so there is no project scope. Corpora are never published.   |
| workflows    | view, edit, delete          | all, project, team, own | create      | Workflows live inside projects like agents, but are never published, so there is no publish action.                     |

Sending an action or a scope a resource does not support (for example `workflows.publish`, or `corpora.view: "project"`) is rejected by the APIs rather than silently ignored.

### Scopes

Each scoped action is assigned a scope.

| **Scope** | **Grants the action on…**                                                                |
| --------- | ------------------------------------------------------------------------------------------ |
| all       | Every resource of that kind in the organization (broadest).                                |
| project   | Resources belonging to projects the member can access. **Agents and workflows only.**      |
| team      | Resources the user’s team(s) can access.                                                   |
| own       | Only the resources the member owns (narrowest). A corpus or workflow is owned by its creator. |

## The Permissions Object

A permission set's access is expressed as a JSON permissions object with one block per resource. Each block takes that resource's scoped actions plus a boolean `create` flag.

**agents** — four scoped actions and one boolean:

| **Action** | **Type**      | **Description**                             |
| ---------- | ------------- | ------------------------------------------- |
| view       | scope \| null | View / read access to agents in scope.      |
| edit       | scope \| null | Modify an agent's configuration.            |
| delete     | scope \| null | Delete agents in scope.                     |
| publish    | scope \| null | Publish staging changes live to production. |
| create     | boolean       | Whether the member may create new agents.   |

**corpora** — three scoped actions and one boolean:

| **Action** | **Type**      | **Description**                                                                                                        |
| ---------- | ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| view       | scope \| null | View the corpus, its documents, sitemaps, conversation starters, and connected agents.                                  |
| edit       | scope \| null | Edit corpus metadata, upload/delete documents, manage sitemaps, trigger re-indexing — **and manage the permissions panel.** |
| delete     | scope \| null | Delete corpora in scope.                                                                                                |
| create     | boolean       | Whether the member may create new corpora.                                                                              |

**workflows** — three scoped actions and one boolean:

| **Action** | **Type**      | **Description**                                                     |
| ---------- | ------------- | --------------------------------------------------------------------- |
| view       | scope \| null | View and run workflows in scope.                                     |
| edit       | scope \| null | Modify a workflow's nodes, edges, and configuration — and its shares. |
| delete     | scope \| null | Delete workflows in scope.                                           |
| create     | boolean       | Whether the member may create new workflows.                         |

**Example**

    {
      "agents":    { "view": "all", "edit": "team",    "delete": null,  "publish": "own", "create": true },
      "corpora":   { "view": "all", "edit": "own",     "delete": "own", "create": true },
      "workflows": { "view": "all", "edit": "project", "delete": "own", "create": false }
    }

A resource block may be omitted entirely. An **absent** block is not a decision about that resource — it is how every set authored before corpora and workflows were onboarded looks, and editing a set only to adjust agents must not silently change a member's corpus access. To explicitly withhold access, include the block with every action `null` and `create: false`.

**No separate manage action:** for corpora and workflows, managing shares — granting, updating, and revoking user or team access — is part of **edit**. A member who can edit the resource can also manage who else can reach it.

**View auto-escalation:** A member who can edit, delete, or publish a resource must also be able to see it. If any of those actions is granted a broader scope than view, view is automatically raised to match — per resource, independently. If the broader scopes mix team and project (neither of which implies the other), view escalates all the way to all. Corpora have no project scope, so they can never hit that case.

---
## Roles vs. Permission Sets
 
Ejento AI controls access through **two complementary layers**. Understanding the difference is key to setting people up correctly.
 
1. **Account roles** — a broad tier assigned to each person that sets their *baseline reach* across the organization.
2. **Permission Sets** — fine-grained, reusable rules layered *on top* of a role that decide exactly what a person can **create, view, edit, delete, and deploy** for which specific agents, corpora, and workflows.

A useful way to think about it: **roles decide *how far* someone's authority extends; Permission Sets decide *exactly what* they can touch within each resource.**
 
### The account roles
 
| Role | Scope of control | What they can typically do |
|---|---|---|
| **Global Admin** | The **entire organization** | Full control: manage all users, teams, projects, agents, corpora, and workflows; configure organization settings; create and assign **Permission Sets**. This is the highest level of access. |
| **Application Admin** | **Application-level** functions and resources | Elevated administrative access over many areas and shared resources, but **without full organization-admin authority**. Sits *below* a Global Admin. |
| **User** | **Only the resources they own or are granted** | Works within their own agents, projects, corpora, and workflows, plus anything explicitly shared with them. |
 
> **Note:** On any *individual* resource (a specific agent, corpus, workflow, team, or project), a user can additionally hold an **Admin** or **Member** access, which further refines what they can do with that one item — independent of their org-wide role.
 
### How Permission Sets fit on top
 
- **Roles set the ceiling; Permission Sets carve out the precise access beneath it.** Assigning someone the "User" role doesn't, by itself, say *what* they can do to *which* agents, corpora, or workflows — the Permission Sets you attach to them do.
- **High-impact actions stay gated.** Even a user who *can* edit a configuration may be blocked from **deploying** it to a live environment.

**In short:** use **roles** to establish broad trust levels (who is an admin vs. a regular user), and use **Permission Sets** to precisely define what each user can see and change within agents, corpora, and workflows.

---

## Creating & Managing Permission Sets

Organization admins can create, update, and delete permission sets. Set names must be unique within an organization.

A few sets are treated specially:

  - System sets (is\_system) are built-in presets. They cannot be deleted, and only their default flag may be changed — name, description, and permissions are locked.

  - Default sets (is\_default) are auto-assigned to newly invited/added organization members. An organization must always keep at least one default set, so you cannot remove or delete the last one.

### Endpoints

| **Method** | **Endpoint**                                  | **Description**                                                                                                     |
| ---------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| GET        | /api/v2/permission-sets                       | List the organization's permission sets. Supports search (query), sorting (sort\_by=name), and optional pagination. |
| POST       | /api/v2/permission-sets                       | Create a permission set from a name, optional description, default flag, and permissions object.                    |
| GET        | /api/v2/permission-sets/{permission\_set\_id} | Retrieve a single permission set by ID.                                                                             |
| PUT        | /api/v2/permission-sets/{permission\_set\_id} | Update name, description, default flag, or permission scopes.                                                       |
| DELETE     | /api/v2/permission-sets/{permission\_set\_id} | Delete a permission set and revoke its permission grants. System sets cannot be deleted.                            |

## Assigning Members

A permission set takes effect once it is assigned to a user. You can approach assignment from either direction — add many users to one set, or add many sets to one user.

**Partial success:** Batch assignment requests are processed item by item. Valid items succeed even if others fail; each failure is returned with a reason (for example, principal not found in the organization, or the per-principal cap reached). Items already assigned are treated as successful (idempotent).

**Cap:** Each user can hold at most 20 permission sets within an organization.

### Endpoints

| **Method** | **Endpoint**                                          | **Description**                                                                                   |
| ---------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| GET        | /api/v2/permission-sets/{permission\_set\_id}/members | List the users assigned to a set. Supports search, sorting (name, subject\_type), and pagination. |
| POST       | /api/v2/permission-sets/{permission\_set\_id}/members | Assign one or more users to the set.                                                              |
| DELETE     | /api/v2/permission-sets/{permission\_set\_id}/members | Remove one or more users from the set.                                                            |
| POST       | /api/v2/users/{user\_id}/permission-sets              | Assign a single user to multiple permission sets in one call.                                     |

## Effective Permissions

A member usually holds several permission sets. Their effective permission for each resource and action is the union of scopes granted by all of those sets. The create flag is effective if any assigned set grants it.

Each resource is aggregated independently — a set that grants broad agent access says nothing about corpora or workflows.

For example, if one set grants `agents.edit` at team scope and another grants `agents.edit` at all, the member can edit any agent in the organization; if neither set grants `corpora.edit`, they can still edit no corpus.

 
## Directly Shared Resources

Permission sets grant scoped access across whole populations of resources, but an individual agent, corpus, or workflow can also be shared directly with a user or a team. A direct share does **not** grant actions by itself. It names *which* resource a user may act on; the *actions* they can perform still come entirely from the permission sets they hold.

A direct share is granted at one of two levels:

| **Share level** | **What it can unlock (given a matching permission set)**                                |
| --------------- | ----------------------------------------------------------------------------------------- |
| member          | View only.                                                                                |
| admin           | View, edit, delete — plus publish for agents |

### Corpus roles: `viewer` and `editor` are retired

Corpus sharing used to offer **three** roles — `viewer`, `editor`, `admin`. It now uses the same two tiers as agents and workflows:

| Old relation | New relation | Why                                                                                                                   |
| ------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `viewer`     | `member`     | Renamed — read-only access                                                                                     |
| `editor`     | `admin`      | **Merged.** An editor could only edit, while `admin` could edit, delete *and* re-share a corpus; `admin` alone is the tier that now carries those. |

**What this means for API clients**

  - `VALID_RELATIONS` for a corpus grant is now `["admin", "member"]`.

**Note:** A former **editor** now sits in the admin tier, so they also resolve against the corpus **delete** capability. They can delete the corpus only if a permission set grants them `corpora.delete`.



### How access resolves

For each action, a directly-shared user's access is the intersection of their share level with their **capability** for that action. A capability is the scope-agnostic union of every scope grant the user holds for that action across all of their assigned permission sets — in other words, "does this user have view (or edit, delete, publish) on this resource at *any* scope?"

  - **Member share:** the user can **view** the resource if they hold any permission set that grants view on that resource at any scope. A member share contributes nothing to edit, delete, or publish.
  - **Admin share:** the user can **view, edit, or delete** the resource — action by action — if they hold any permission set that grants that same action on that resource at any scope. An admin share never unlocks an action the user has no permission set for.

**Public Agents and Corpora:** these are shared with all users in the organization at once with member access. Every user then resolves against their own view capability individually, so only members who already hold view somewhere gain access. Workflows cannot be made public.

> Note: Direct shares to a *team* behave slightly differently — a team share is gated at `team` scope rather than by the scope-agnostic capability. The capability-based resolution above applies to shares made directly to an individual user.

---

## System and default Permission Sets
 
Not every Permission Set behaves the same way. Two special categories carry rules you can't override, and there are a few organization-wide limits worth knowing before you start creating sets.
 
### System Permission Sets
 
**System Permission Sets cannot be modified.** Their scopes are fixed. You *can*, however:
 
- **Set/Unset them as default** (on/off), and
- **Assign or remove users.**
You just can't change what the set grants.
 
### Default Permission Sets
 
A **default** Permission Set is one that is **automatically assigned to every new user** added to the organization, so people start with a baseline of access from day one. Because of this, defaults follow special rules:
 
- **An organization must always have at least one default Permission Set.**
- **The last remaining default cannot have its default field toggled off** — this guarantees the organization is never left without a default. (Once another set is marked default, the previous one can be freely toggled again.)
- Turning a set's default on or off changes only *future* assignments to new users; it doesn't retroactively add or remove the set from existing users.
### Assignment limits
 
- **A user can have at most 20 Permission Sets assigned at any one time.** Plan for this ceiling when designing sets — favor a smaller number of well-scoped sets over many narrow ones.
> **Quick reference**
>
> | Rule | Detail |
> |---|---|
> | System sets | Scopes are locked; only the default toggle and user assignments can change. |
> | Minimum defaults | At least one default must always exist in the organization. |
> | Last default | Its default field cannot be toggled off while it's the only default. |
> | New users | All default sets are auto-assigned to every new user. |
> | Per-user limit | Maximum of **20** Permission Sets per user at a time. |
 
---
