Policies and permissions
The policy document language, how Hexel Studio decides a request, how access flows from an organization to its workspaces and environments, and the managed policies you can use.
On this page
A policy is a JSON document that lists actions. You attach it to a member, a group, a service user or a role, and that principal may then perform the actions it allows. Hexel Studio denies everything a policy does not allow.
This page describes the language exactly as Hexel Studio reads it today, including the parts it stores but does not apply yet. To create and attach policies, see Write and attach policies.
A policy document
{
"Version": "2026-02-17",
"Statement": [
{
"Sid": "ReadWorkspaces",
"Effect": "Allow",
"Action": ["workspace:workspace:read", "env:env:read"],
"Resource": ["*"]
}
]
}| Field | Type | What Hexel Studio does with it |
|---|---|---|
Version | string | Stored. Any value is accepted and none changes the meaning. Use 2026-02-17, the value of the managed policies. |
Statement | array | The statements. A document needs at least one. |
Sid | string, optional | A label for the statement. Stored, not used in decisions. |
Effect | "Allow" or "Deny" | Allow grants the listed actions. Deny is stored but does not block normal API calls yet (see below). The value is case-sensitive: "allow" grants nothing. |
Action | string or array of strings | The actions the statement covers. See Action names and wildcards. |
Resource | string or array of strings | Required by the policy validator. Stored, not matched. Use ["*"]. |
Condition | object, optional | Stored, never evaluated. |
A document that is not valid JSON, or has no statement Hexel Studio can read, grants nothing. Hexel Studio does not check the document when you create a policy, and when you change one it checks only that the document is JSON. Validate it first.
Action names and wildcards
An action is named <service>:<resource>:<verb>, for example workspace:workspace:create or iam:policy:write. Names are case-sensitive. The actions reference lists every action.
A pattern in Action matches an action when it is:
| Pattern | Matches | Example |
|---|---|---|
* | Every action | "*" |
| An exact name | That action only | "iam:policy:read" |
A name ending in * | Every action that starts with the text before the * | "iam:*" (all IAM actions), "iam:policy:*" (all policy actions) |
Only a trailing * is a wildcard. iam:*:read matches nothing except an action literally named iam:*:read. A trailing * matches any text, so iam* also matches actions of any service whose name starts with iam.
How a request is decided
Your normal API calls are decided by the cached permission check. For each request, Hexel Studio collects the Allow actions of every policy that applies to the caller in the token's organization, and allows the request if one of them matches the action the API checks. If none matches, the request is denied with 403. Deny statements are not read by this check, so they have no effect on API calls today.
The policies that apply depend on who is calling:
| Caller | Policies that apply |
|---|---|
| Member | Policies attached to the member, policies attached to every group the member is in (including the membership group of their member role), and the policies of permission sets assigned to the member or their groups |
| Service user | Policies attached to the service user, to its groups, and of permission sets assigned to it |
| Role session | Only the policies attached to the role, limited by the role's permission boundary if it has one. The policies of the person or service user who assumed the role don't apply. See Roles. |
A permission never comes from a name, an email address or a header you send. Permissions are not stored in the access token, so a change applies to tokens that were already issued.
When you change an attachment, a group, a permission set or a policy document, Hexel Studio updates the cached permissions of the principals concerned, usually at once. Cached permissions also expire on their own, so a change always takes effect within about a minute.
Organization, workspace and environment scope
A request is made for one organization: the token's. It can also name a workspace and an environment of that organization, with the X-Workspace-Id and X-Environment-Id headers (see Headers). The endpoints for a single workspace or environment, such as PATCH /v1/workspaces/<workspace-id>, set this scope from the path for you.
Each grant has a scope, and a grant at one level applies to everything below it:
| Where the grant is placed | Applies to requests for |
|---|---|
| Organization: policy attachments, permission sets assigned without a workspace, organization-scoped roles | The organization and every workspace and environment in it |
Workspace: permission sets assigned with workspace_id, workspace-scoped roles | That workspace and its environments |
Environment: permission sets assigned with workspace_id and environment_id, environment-scoped roles | That environment only |
Policy attachments have no scope of their own: a policy attached to a member, group or service user always applies organization-wide.
Hexel Studio checks the scope before it looks at any permission:
- A request that names an environment must also name its workspace.
- The workspace must be an active workspace of the token's organization, and the environment must be an active environment of that workspace. Otherwise the request is denied, even for an owner.
- A request that names no workspace is checked against organization-level grants only. A grant placed on a workspace does not count for it.
Some actions are always checked at organization level, whatever headers you send. Creating a workspace (workspace:workspace:create) is one: a grant placed on a workspace can't let someone create workspaces.
Managed policies
Hexel Studio provides managed policies that every organization can attach. They appear in GET /v1/policies next to your own policies, with "is_system": true. You can attach them and read them, but you can't change or delete them.
These managed policies are the ones the default member roles use, plus a few full-access ones:
| Policy ID | Name | Allows |
|---|---|---|
pol_org_owner_full | Organization Owner Full Access | * |
pol_iam_full | IAM Full Access | iam:* |
pol_iam_admin | IAM Admin Access | Read and write IAM: policies, attachments, groups and their members, roles and trust policies, permission sets, iam:authz:simulate, and the Preview IAM features. Not iam:user:erase. |
pol_iam_readonly | IAM Read-Only Access | The :read IAM actions, and iam:tag:manage |
pol_org_full | Organization Full Access | org:* |
pol_org_member | Organization Member Access | org:org:read, org:org:update, org:member:invite, org:member:manage, org:settings:read, org:settings:write, org:billing:read, org:audit:read |
pol_org_readonly | Organization Read-Only | org:org:read, org:settings:read, org:billing:read, org:audit:read |
pol_billing_full | Billing Full Access | org:billing:read, org:billing:manage |
pol_billing_readonly | Billing Read-Only Access | org:billing:read |
pol_ws_full | Workspace Full Access | workspace:* |
pol_ws_readonly | Workspace Read-Only Access | workspace:workspace:read |
pol_env_full | Environment Full Access | env:* |
pol_env_readonly | Environment Read-Only Access | env:env:read |
pol_svc_account | Service Account Full Access | directory:service_account:create, :read, :update, :delete, :manage_keys |
pol_dir_readonly | Directory Read-Only Access | Includes directory:service_account:read |
pol_data_full / pol_data_readonly | Atlas Full Access / Atlas Read-Only Access | Atlas actions |
pol_memory_full / pol_memory_user / pol_memory_readonly | Memory Full / User / Read-Only Access | Hexel Managed Memory actions |
pol_skills_full / pol_skills_publisher / pol_skills_readonly | Skills Full / Publisher / Read-Only Access | Skills Registry actions |
Read a managed policy's document with GET /v1/policies/<policy-id>. The list also contains policies for other Hexel Studio products and policies Hexel Studio uses for its own services. The actions reference describes the actions.
Permission sets
A permission set is a named list of policy IDs. Assigning it to a member, a group or a service user grants all its policies to that principal, optionally only in one workspace or environment, and optionally until an expiry time. It is the way to grant a member access to a single workspace or environment.
- An assignment grants its policies while it exists and has not expired. Deleting the assignment removes the access.
- An assignment with
workspace_idgrants in that workspace and its environments. Withworkspace_idandenvironment_id, it grants in that environment only. Without either, it grants organization-wide. - The policy list is copied when you assign the set. Changing the set's
policy_idslater does not change existing assignments; changing a policy's document does.
GET /v1/permission-sets lists your permission sets and any that Hexel Studio provides. See Grant access in one workspace or environment for the API.
Role templates
GET /v1/role-templates and GET /v1/role-templates/<name> return role templates: a name, display_name, description, scope and a list of action names in permissions. They are reference lists you can copy actions from into a policy. A template grants nothing, and Hexel Studio does not create policies or roles from it. Reading templates needs iam:policy:write.
Nobody grants what they don't hold
To attach a policy, assign a permission set, add a member to a group, or change the document of a policy that is in use, you must already hold every action the change grants, at organization level. Otherwise the request is refused with 403:
{
"error": "forbidden",
"reason": "cannot grant actions the caller does not hold",
"missing_actions": ["iam:user:erase"]
}An owner holds *, so an owner can grant anything. An admin can grant only what the admin policies give them. A wildcard counts only if you hold an equal or wider one: holding iam:policy:read and iam:policy:write does not let you grant iam:policy:*.
What is not enforced yet
These parts of the language are accepted and stored, but don't change the result of your API calls yet:
| Feature | Today | Read more |
|---|---|---|
Deny statements | Not applied to API calls. Only the test access endpoints apply them. Remove the Allow instead. | Guardrails (Preview) |
Resource and Condition | Stored and ignored everywhere | Fine-grained access (Preview) |
| Permission boundaries on members and service users, service control policies, resource control policies | Not applied to API calls | Guardrails (Preview) |
A permission boundary set on a role does apply: it caps every call made with that role's sessions. See Roles.