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

# Pods

> Named groups of profiles that share a filesystem workspace and a lightweight blackboard.

> **Last updated: 2026-09-06**

## What is a Pod?

A **Pod** groups profiles that need to collaborate through shared state. Pods add two things to each member profile:

* A role-aware filesystem policy under `/pools/{pool}/...`
* Pod tools: `pool_info`, `pool_post`, and `pool_inbox`

Pod membership does not replace the profile sandbox. Every profile still keeps its implicit home at `/agents/{self}/**`; pod access is layered on top.

<Note>
  The API, CLI, and SDKs still use the older name **pool** for this concept: routes live under `/api/pools`, the command is `orca pools`, the shared workspace is mounted at `/pools/{pool}/**`, and the tools are `pool_info`, `pool_post`, and `pool_inbox`. "Pod" in this documentation and "pool" in those identifiers refer to the same thing.
</Note>

***

## Pod Schema

```go theme={"dark"}
type AgentPool struct {
  ID          string
  Name        string
  PinnedAt    *time.Time // set by the pin endpoints
  Pinned      bool       // derived from PinnedAt on reads
  Description string
  Members     []PoolMember
  FS          *PoolFSPolicy
}

type PoolMember struct {
  Profile string
  Role    string // "lead" | "member" | "observer"
}
```

Roles default to `member` when omitted or unknown.

`POST /api/pools/{name}/pin` and `DELETE /api/pools/{name}/pin` set and clear `PinnedAt`. Listing pods (`GET /api/pools`) orders them by `pinnedAt` descending (pinned pods first), then `updatedAt` descending, then name.

***

## Creating a Pod

```bash theme={"dark"}
curl -X POST https://api.orcapods.ai/api/pools \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "research-team",
    "description": "Shared workspace for market research",
    "members": [
      { "profile": "researcher", "role": "lead" },
      { "profile": "reviewer", "role": "member" },
      { "profile": "auditor", "role": "observer" }
    ],
    "fs": {
      "read": ["/datasets/**"],
      "write": ["/pools/{pool}/sot/**"],
      "deny": ["/pools/{pool}/archive/private/**"]
    }
  }'
```

The conductor broadcasts pods to all runners, just like profiles.

The rest of the pods API follows the same shape as profiles:

| Method            | Path                                  | Description                                                                            |
| ----------------- | ------------------------------------- | -------------------------------------------------------------------------------------- |
| `GET`             | `/api/pools`                          | List pods for the active tenant                                                        |
| `GET`             | `/api/pools/{name}`                   | Get one pod                                                                            |
| `POST`            | `/api/pools`                          | Create a pod                                                                           |
| `PATCH`           | `/api/pools/{name}`                   | Update description, members, or `fs`                                                   |
| `DELETE`          | `/api/pools/{name}`                   | Delete a pod (requires the `admin` role; every other pod route only requires `member`) |
| `POST` / `DELETE` | `/api/pools/{name}/members/{profile}` | Add or remove a member                                                                 |
| `POST` / `DELETE` | `/api/pools/{name}/pin`               | Pin or unpin a pod                                                                     |

***

## Built-in Path Layout

Every pod uses the same directory conventions:

| Path                                  | Purpose                               |
| ------------------------------------- | ------------------------------------- |
| `/pools/{pool}/sot/`                  | Shared source-of-truth documents      |
| `/pools/{pool}/board/public/`         | Public blackboard for all members     |
| `/pools/{pool}/board/public/posts/`   | Markdown posts created by `pool_post` |
| `/pools/{pool}/board/private/{self}/` | Member-private workspace              |
| `/pools/{pool}/archive/`              | Shared archive                        |

`pool_info` returns the concrete paths for the active session.

***

## Role Permissions

| Role       | Read                                             | Write                                            | Delete                |
| ---------- | ------------------------------------------------ | ------------------------------------------------ | --------------------- |
| `lead`     | `sot`, public board, all private boards, archive | `sot`, public board, all private boards, archive | `sot`, board, archive |
| `member`   | `sot`, public board, own private board, archive  | public board, own private board                  | own private board     |
| `observer` | `sot`, public board, archive                     | none                                             | none                  |

Custom `fs.read`, `fs.write`, `fs.delete`, and `fs.deny` entries are additive. `deny` always wins.

***

## Pod Tools

`@pool` is part of `@default`, so normal profiles can inspect pod membership immediately. Tools that read or write posts use the runner's VirtualFS dispatcher; with no `VFS_*` environment they still work in that runner's in-memory storage, but posts are not shared with `vfs serve` or other runner processes.

| Tool         | Description                                                     |
| ------------ | --------------------------------------------------------------- |
| `pool_info`  | Returns pod memberships, role, roster, and path layout          |
| `pool_post`  | Writes a markdown post to `/pools/{pool}/board/public/posts/`   |
| `pool_inbox` | Lists recent public posts; use `read_file` to fetch a full post |

Typical agent workflow:

1. Call `pool_info` to discover memberships and paths.
2. Call `pool_inbox` to catch up on recent public posts.
3. Use `read_file` / `write_file` for shared documents.
4. Call `pool_post` for updates other members should see.

### Admin tools

A separate, opt-in `@pools.admin` capability bundle grants a second set of tools that manage the pod catalog itself, rather than just posting to it:

| Tool                 | Description                                          |
| -------------------- | ---------------------------------------------------- |
| `create_pool`        | Creates a pod                                        |
| `update_pool`        | Updates a pod's description, members, or `fs` policy |
| `delete_pool`        | Deletes a pod                                        |
| `add_pool_member`    | Adds a member to a pod                               |
| `remove_pool_member` | Removes a member from a pod                          |

These are state-changing mutations over the pods API above; grant `@pools.admin` only to profiles that should be able to create, reconfigure, or delete pods programmatically.

***

## Effective Filesystem Policy

The runner compiles a session policy in this order:

1. Implicit home grant: `/agents/{self}/**`
2. Profile `fs` grants and denies
3. Built-in pod grants for each membership role
4. Pod custom `fs` grants and denies

Tokens are substituted before matching:

| Token    | Value                |
| -------- | -------------------- |
| `{self}` | Current profile name |
| `{pool}` | Pod name             |
| `{role}` | Member role          |

Relative paths in `read_file`, `write_file`, and `delete_file` resolve under `/agents/{self}/`. Use absolute paths for pod files.
