> ## Documentation Index
> Fetch the complete documentation index at: https://docs.matrices.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Narrow an agent's permissions

> Allow one tool for reads only, and take a whole family away.

You'll let the research agent from the [first guide](/guides/first-agent) make
HTTP requests, but only `GET` ones, and block it from managing agents for
good.

## 1. Find the tool names

A permission names both the tool and who owns it. Built-ins start with
`tool:builtin:` and are listed in [Built-in tools](/reference/built-in-tools).
Tools your workspace registered start with `tool:workspace:` and sit under
their [toolset](/model/toolsets) namespace, which you can list:

```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl --fail --silent --show-error -H "Authorization: Bearer $MATRICES_API_KEY" \
  "https://api.matrices.com/v1/toolsets?limit=50" | jq -r '.toolsets[].namespace'
```

A toolset in the `billing` namespace publishes `billing.lookup_invoice`, so you
grant `tool:workspace:billing.lookup_invoice`. Managed provider toolsets (Gmail,
Calendar, Linear) ship with Matrices, so they never show up in that list. You
still grant them by name, like `tool:managed:gmail.*`.

## 2. Write the allows

`http.request` makes one HTTP call, using whatever `method` the model picked.
Put a condition on the entry and you pin that field, so this role can read from
an API but never write to one:

```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export HTTP_ROLE_ID="$(
  curl --fail --silent --show-error "https://api.matrices.com/v1/roles" \
    -H "Authorization: Bearer $MATRICES_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Read-only HTTP",
      "description": "Calls other APIs, but never changes anything.",
      "allow": [
        "tool:builtin:web.*",
        { "tool": "tool:builtin:http.request", "where": [{ "path": "input.method", "op": "eq", "value": "GET" }] }
      ]
    }' | jq -er '.role.id'
)"
```

`where` is checked against the tool input exactly as the model wrote it. The
operators and paths are in [Permissions](/reference/permissions#conditional-allows).

## 3. Deny a whole family

An allow only ever adds tools. To take one away no matter what the other roles
grant, deny it:

```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl --fail --silent --show-error -X PATCH \
  "https://api.matrices.com/v1/roles/$HTTP_ROLE_ID" \
  -H "Authorization: Bearer $MATRICES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "deny": ["tool:builtin:agents.*"] }'
```

Now even a second role handing out `tool:*` can't let this agent create or
delete agents. Denies only work on built-in tools, never on a toolset
namespace.

## 4. Select the role in the profile

Roles attach to the [profile](/model/profiles), not the agent. The patch
replaces the whole list instead of adding to it, so send every role you want,
including the one from the first guide:

```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl --fail --silent --show-error -X PATCH \
  "https://api.matrices.com/v1/profiles/$PROFILE_ID" \
  -H "Authorization: Bearer $MATRICES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "configuration": { "roleIds": ["'"$ROLE_ID"'", "'"$HTTP_ROLE_ID"'"] } }'
```

Every agent on this profile gets the change on its next turn. If only one of
them should, give that one its own profile first.

## Check it worked

```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl --fail --silent --show-error -H "Authorization: Bearer $MATRICES_API_KEY" \
  "https://api.matrices.com/v1/agents/$AGENT_ID/effective-permissions" |
  jq '{ builtIns, conditional }'
```

`builtIns` lists the exact tools the agent can call. `http.request` is there,
and nothing from `agents.*` is. `conditional` shows the `GET`-only grant. Ask the
agent to POST something and the call is refused before it runs.

Allows add up, conditions narrow one entry, denies win. The full stacking
table is in [Permissions](/reference/permissions#stacking).

## Where next

<CardGroup cols={2}>
  <Card title="Approve a tool call" icon="hand" href="/guides/approve-a-tool-call">
    Let the write through, but only after a human says yes.
  </Card>

  <Card title="Connect a service" icon="link" href="/guides/connect-a-service">
    Give it a login to go with the permission.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.