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

# Policy and Roles

> Control which tools each user can access with glob-pattern roles.

Toolshed uses role-based access control to filter which tools a user can see and invoke. Each role defines a set of glob patterns that match tool paths.

## Role schema

```typescript theme={null}
{
  id: string;       // Unique role ID
  name: string;     // Human-readable name
  patterns: string[]; // Array of glob patterns
}
```

## Pattern syntax

Patterns match against dot-separated tool paths:

| Pattern               | Matches                                       | Does not match        |
| --------------------- | --------------------------------------------- | --------------------- |
| `github.issues.*`     | `github.issues.create`, `github.issues.list`  | `github.repos.search` |
| `github.**`           | `github.issues.create`, `github.repos.search` | `linear.issues.list`  |
| `gmail.messages.read` | `gmail.messages.read` only                    | `gmail.messages.list` |
| `*`                   | Everything                                    | --                    |

* `*` matches exactly one segment
* `**` matches zero or more segments at any depth

### Example roles

**Developer** -- full GitHub access, read-only Slack:

```json theme={null}
{
  "id": "developer",
  "name": "Developer",
  "patterns": ["github.**", "linear.issues.*", "slack.channels.list"]
}
```

**Admin** -- access to everything:

```json theme={null}
{
  "id": "admin",
  "name": "Admin",
  "patterns": ["*"]
}
```

**Read-only** -- only list and read operations:

```json theme={null}
{
  "id": "viewer",
  "name": "Viewer",
  "patterns": ["*.*.list", "*.*.read", "*.*.search", "*.*.get"]
}
```

## How filtering works

The policy engine provides two functions from `@toolshed/policy`:

### `filterToolsByRole(tools, role)`

Returns only the tools whose paths match at least one pattern in the role:

```typescript theme={null}
import { filterToolsByRole } from "@toolshed/policy";

const visibleTools = filterToolsByRole(allTools, userRole);
// Only tools matching userRole.patterns are included
```

### `matchPattern(toolPath, pattern)`

Tests whether a single tool path matches a single pattern:

```typescript theme={null}
import { matchPattern } from "@toolshed/policy";

matchPattern("github.issues.create", "github.issues.*");  // true
matchPattern("github.issues.create", "github.**");         // true
matchPattern("github.issues.create", "linear.**");         // false
```

## Annotation resolution

The policy package also resolves whether a tool requires approval:

```typescript theme={null}
import { resolveAnnotations } from "@toolshed/policy";

const annotations = resolveAnnotations(tool);
// { requiresApproval: true, reason: "Tool is marked as destructive" }
```

Resolution priority (first match wins):

1. **OpenAPI tools:** `metadata.httpMethod` -- GET, HEAD, OPTIONS are safe
2. **GraphQL tools:** `metadata.operationType` -- queries are safe, mutations require approval
3. **MCP tools:** `metadata.mcpAnnotations.destructiveHint`
4. **Plugin tools:** falls back to the explicit `destructive` flag
