# Participants and authority

> How humans, agents, and services are declared, and how an agent's authority chains to a responsible human.

Every actor in a workflow is a participant, whether it breathes or not. That uniformity is deliberate: it is what lets human and machine work be scheduled, attributed, and audited under one contract.

```json
{
  "participants": [
    { "id": "podcast_host", "kind": "human", "name": "Podcast Host",
      "role": "host", "organization_id": "org_studio_media" },
    { "id": "caption_agent", "kind": "agent", "name": "Caption Agent",
      "operated_by": "podcast_host", "organization_id": "org_studio_media" },
    { "id": "publish_api", "kind": "service", "name": "Example Publishing" }
  ]
}
```

## Fields

`id` and `kind` are both required — `kind` is the only required field beyond an identifier anywhere in the entity registries, which signals how load-bearing it is.

| Field | Type | Notes |
|---|---|---|
| `id` | string | **Required** |
| `kind` | enum | **Required.** See below |
| `name` | string | Display name |
| `role` | string | Open set: `host`, `editor`, `vfx-supervisor`, `colorist` |
| `organization_id` | string | The organization this participant belongs to |
| `works_for` | string | Organization-level delegation (PROV `actedOnBehalfOf`) |
| `operated_by` | string | **For agents:** the accountable participant |
| `identity` | string \| object | Verifiable identity. See below |

### `kind`

| Value | Meaning |
|---|---|
| `human` | A natural person |
| `agent` | Autonomous software, including generative AI |
| `service` | A deterministic software service |
| `department` | An organizational unit |
| `organization` | An organization acting as a participant |

The `agent` / `service` distinction is the one that matters most. A `service` does the same thing every time. An `agent` exercises judgement, which is why it needs an accountability chain that a service does not.

> A participant with no `organization_id` is a third party — an external SaaS, say. That is legitimate and used in practice, but it means nothing in the graph vouches for it. Treat unowned participants as a review signal.

## Agent authority

An agent's authority is never ambient. It is a declared edge to a responsible principal:

```json
{
  "id": "agent_dubber",
  "kind": "agent",
  "name": "Localization Agent",
  "operated_by": "s.okafor",
  "organization_id": "org_studio",
  "identity": {
    "scheme": "did",
    "id": "did:web:example.com:agents:dubber",
    "credential_scope": ["read:assets", "write:outputs"]
  }
}
```

- **`operated_by`** names the participant on whose authority the agent acts. It maps to PROV `actedOnBehalfOf`. The generative-AI profile makes it **required** for agent executors.
- **`works_for`** is the organization-level equivalent.
- **`identity.credential_scope`** bounds what the agent may do.

This is what makes *"who did this, and on whose say-so"* a query rather than an investigation, and it is what makes AI disclosure fall out of the data instead of being compiled by hand. An asset produced by `agent_dubber` traces to `s.okafor` and `org_studio` with no extra record-keeping.

### Chains

`operated_by` may chain — an agent operated by an agent operated by a human. The chain **must terminate** at a `human` or `organization` participant; an authority loop is meaningless, and a validator is required to reject one. See [Validation](/validation#pass-3-graph).

### Identity

`identity` accepts a bare string or an object:

| Field | Notes |
|---|---|
| `scheme` | Open set. `urn`, `did` |
| `id` | **Required** within the object form |
| `credential_scope` | string[] — what this identity is permitted to do |

Decentralized identifiers (`did:`) are the intended direction for agent identity, so that an agent's identity is verifiable rather than merely asserted by whoever wrote the document.

> **`credential_scope` is a declaration, not an enforcement mechanism.** The specification defines where an agent's permitted scope is recorded; enforcing it is the implementation's responsibility. Do not assume a document that declares a scope was executed within it.

## Organizations

```json
{
  "organizations": [
    { "id": "org_studio_media", "name": "Example Studio Media" },
    { "id": "org_vfx_north", "name": "North VFX", "role": "vfx-vendor" }
  ]
}
```

Only `id` is required. `role` is an open set — `studio`, `vfx-vendor`, `broadcaster`, `service-provider`.

Organizations are the top of the delegation chain and the natural boundary for a turnover: cross-company work means edges that cross an organization boundary, which is exactly what a [scoped subgraph](/subgraphs-and-turnovers) controls.

## Infrastructure

Infrastructure is where work runs. Declaring it is what makes cost attribution and multi-cloud portability properties of the graph rather than of a spreadsheet.

```json
{
  "infrastructure": [
    { "id": "studio_ws", "type": "workstation", "owner": "org_studio_media",
      "apps": ["audacity", "premiere"] },
    { "id": "gpu_cloud", "type": "gpu_compute", "owner": "org_mediasvc",
      "spec": "A100 80GB" },
    { "id": "cloud_platform", "type": "saas_platform" }
  ]
}
```

| Field | Type | Notes |
|---|---|---|
| `id` | string | **Required** |
| `type` | string | Open set: `cloud_gpu`, `gpu_compute`, `workstation`, `render_farm`, `saas_platform`, `storage`, `camera`, `facility` |
| `owner` | string | Organization id |
| `location` | string | Region or physical site |
| `host`, `product` | string | Platform detail |
| `spec` | string \| object | e.g. `"A100 80GB"` |
| `apps` | string[] | Applications available on this target |

A task's `ran_on` points here. Because capability is described rather than assumed, an engine can match work to a target dynamically instead of relying on hand-routing — the difference between a workflow that runs where it was told and one that runs where it fits.
