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

# Assign a supervisor

> Create a supervisor, give it a server, session, workflow, run level or some nodes to own, and decide which commands people may still send.

<dl />

**Use this when** you want one accountable owner for a unit of work: a supervisor that watches it, may step in, and decides whether people steer it directly. A [supervisor](https://yukta.infenia.com/concepts/supervisors.md) has a shell (what it owns, what it may send, whether people may steer through it) and an engine that decides.

**Prerequisites:** a server on `http://localhost:9858` and the `steer` session with workflow `slow` from [Control a run](https://yukta.infenia.com/guides/build/control-a-run.md). Creating supervisors and assignments needs an `ADMIN` key; add `-H "X-API-Key: $YUKTA_API_KEY"` to every `curl` if your server has keys.

![An assignment names the unit a supervisor owns: the whole server, a session, a workflow, only its run level, or chosen nodes. Every unit has exactly one owner.](https://yukta.infenia.com/images/diagrams/guide-assign-a-supervisor.light.svg)

Pick the smallest unit that fits. A second supervisor cannot own a unit that already has an owner.

## Steps

**1. Create the supervisor**

A supervisor has an `id` (letters, digits, `.`, `_`, `-`, up to 64), an engine `type` (`rules`, `http`, `workflow` or `process`) and `settings`. This one uses the `rules` engine with no rules yet, so it reviews and allows. Save as `release-guard.json`:

```json release-guard.json theme={"system"}
{
  "id": "release-guard",
  "type": "rules",
  "description": "Owns the slow workflow; people may pause and resume it",
  "settings": {
    "rules": [],
    "allowedCommands": ["PauseWorkflowCommand", "ResumeWorkflowCommand"],
    "operatorAccess": ["PauseWorkflowCommand", "ResumeWorkflowCommand"]
  }
}
```

* `allowedCommands` is what the supervisor itself may send. Name them, whatever the engine's default is.
* `operatorAccess` is what a **person** may send for what it owns (default none). A listed command is reviewed by the owner's engine.

Check the draft without saving, then save:

```bash theme={"system"}
curl -s -X POST localhost:9858/api/supervisors/validate -H 'Content-Type: application/json' -d @release-guard.json
curl -s -X POST localhost:9858/api/supervisors -H 'Content-Type: application/json' -d @release-guard.json
```

Validation answers `200` with `"valid": false` and a `settings.<key>` field for an unknown key or wrong type. Saving answers `201`; a second save of the same id with `POST` is `409`, so use `PUT /api/supervisors/{id}` to replace it.

![The Supervisors page catalogue listing the rules, http, workflow and process engines with their settings](https://yukta.infenia.com/images/ui/supervisors-catalogue.light.png)

Decision maker types, opened from the Supervisors page, list the four engines with their settings and an example; the create wizard checks settings before it saves.

**2. Say what it owns**

An **assignment** targets one unit:

| Target | Owns |
| - | - |
| `server` | Server-wide commands: scheduler limits, drain, recover |
| `session:<id>` | Every workflow of the session, run level and nodes |
| `workflow:<s>/<w>` | The run level and all nodes of one workflow |
| `run:<s>/<w>` | The run level only: start, pause, resume, stop, restart, priority |
| `workflow:<s>/<w>//<selector>,...` | Some nodes: a node id, `<prefix>.*` or `group:<stage>` |

Check first (it saves nothing), then set:

```bash theme={"system"}
curl -s -X POST localhost:9858/api/supervisors/release-guard/assignments/check \
  -H 'Content-Type: application/json' -d '[{"target":"workflow:steer/slow"}]'
curl -s -X PUT localhost:9858/api/supervisors/release-guard/assignments \
  -H 'Content-Type: application/json' -d '[{"target":"workflow:steer/slow"}]'
```

The check answers `{"valid": true, "problems": []}`. Setting replaces the assignments you made by hand, checks everything first and changes nothing if one check fails. CLI: `yukta-cli supervisors save -f release-guard.json`, `yukta-cli supervisors assign release-guard workflow:steer/slow`. MCP: `save_supervisor`, `check_assignment`, `set_assignments`.

**3. Try the one-owner rule**

Every unit has one owner. Save a second supervisor and give it the same workflow:

```bash theme={"system"}
curl -s -X POST localhost:9858/api/supervisors -H 'Content-Type: application/json' \
  -d '{"id":"other-guard","type":"rules","settings":{"rules":[]}}'
curl -s -X PUT localhost:9858/api/supervisors/other-guard/assignments \
  -H 'Content-Type: application/json' -d '[{"target":"workflow:steer/slow//wait"}]'
```

The save is refused with `409` and the code `OWNERSHIP_CONFLICT`, naming the other supervisor and the units in dispute (the `message` reads like `<unit> already owned by release-guard`):

```json theme={"system"}
{
  "status": 409,
  "message": "node wait of steer/slow already owned by release-guard",
  "error": "Conflict",
  "errors": [ { "field": "code", "message": "OWNERSHIP_CONFLICT" }, { "field": "supervisor", "message": "release-guard" } ]
}
```

Nothing is inherited and nothing is overridden. To give one node to a specialist, narrow the first supervisor's assignment (for example to `workflow:steer/slow//go`) before assigning the node.

**4. See what people may still do**

With a run going (`yukta-cli workflow start steer slow` or the start call from the control guide), ask the server before you send:

```bash theme={"system"}
curl -s "localhost:9858/api/supervision?execution=$EXEC"
curl -s "localhost:9858/api/supervision/ownership?session=steer&workflow=slow"
```

The first lists each command with `allowed`, `via` (the carrying supervisor, or `default`) and `reason`. The second names the owner of the run level and of each node. Now send commands as a person:

```bash theme={"system"}
curl -s -X POST localhost:9858/api/executions/$EXEC/pause        # in operatorAccess: allowed, reviewed by release-guard
curl -s -X POST "localhost:9858/api/executions/$EXEC/stop"       # not listed
```

```json theme={"system"}
{
  "status": 409,
  "message": "release-guard controls this. People cannot do this directly.",
  "errors": [ { "field": "code", "message": "CONTROLLED_BY_SUPERVISOR" }, { "field": "supervisor", "message": "release-guard" } ]
}
```

**5. Declare ownership in the workflow**

A session or workflow can name its supervisors, so imports, templates and every saved version carry them. The supervisor must exist when the definition is saved, and the one-owner rule runs first.

```json theme={"system"}
"workflows": {
  "slow": {
    "workflowId": "slow",
    "assignments": [
      { "supervisor": "release-guard", "nodes": ["wait"] },
      { "supervisor": "other-guard", "enabled": false }
    ],
    "nodes": [ "..." ],
    "edges": [ "..." ]
  }
}
```

A session-level `assignments` covers the whole session; a workflow-level one covers the workflow or only the listed `nodes` (ids, `<prefix>.*` or `group:<name>`). `enabled: false` declares and keeps it off. These assignments have source `DEFINITION`: saving the definition takes up what is declared and releases what is no longer declared, never touching hand-made ones. A supervisor a definition names cannot be deleted.

**6. Lock it**

`"locked": true` on an assignment means only a lock holder may change or remove it (any admin, or the keys in `yukta.supervisor.lock-holders`). To change it, add `?unlock=true`:

```bash theme={"system"}
curl -s -X PUT localhost:9858/api/supervisors/release-guard/assignments \
  -H 'Content-Type: application/json' -d '[{"target":"workflow:steer/slow","locked":true}]'
curl -s -X PUT "localhost:9858/api/supervisors/release-guard/assignments?unlock=true" \
  -H 'Content-Type: application/json' -d '[]'
```

Without `unlock`, the second call is `409`.

## Verify it worked

```bash theme={"system"}
curl -s "localhost:9858/api/supervisors/assignments?session=steer"
curl -s localhost:9858/api/supervision/summary
```

The list shows `release-guard` with target `workflow:steer/slow` and its `source` (`MANUAL`, `DEFINITION` or `SYSTEM`). The summary counts workflows nobody owns. Stopping the run as a person is refused with `409 CONTROLLED_BY_SUPERVISOR`, pausing it works, and `GET /api/control/audit` records both.

![A supervisor's page showing its settings, what it owns and its recent decisions](https://yukta.infenia.com/images/ui/supervisor-details.light.png)

A supervisor's page: its settings (secrets shown as \*\*\*), what it owns and what became of its commands.

## Variations

* **Units nobody owns** go to the default supervisor, which lets people act as before. Set `yukta.supervisor.default.enabled=false` in production so every workflow must name its owner; a person's command for an unowned unit is then `409 CONTROLLED_BY_SUPERVISOR` with no supervisor named.
* **Commands that need approval.** A rule's `requireApproval` parks a command and answers `202` with `{"status":"AWAITING_APPROVAL","requestId":"..."}`: [Write a rules supervisor](https://yukta.infenia.com/guides/supervise/write-a-rules-supervisor.md).
* **A veto** is a `403` with code `CONTROL_REJECTED` and the rule's reason.
* **Which engine?** `rules` for exact cases, `http` for an agent or another service, `workflow` for a decision you edit as a workflow, `process` for a local program: [Supervisor engines](https://yukta.infenia.com/reference/supervisors/engines.md).
* **Delete.** A supervisor can be deleted only when it owns nothing, no definition names it and no supervisor reports to it (`409` otherwise).

## Related

* [Supervisors](https://yukta.infenia.com/concepts/supervisors.md) for the shell and engine model.
* [Supervisor shell reference](https://yukta.infenia.com/reference/supervisors/shell.md) for every setting.
* [Use the Control dashboard](https://yukta.infenia.com/guides/supervise/use-the-control-dashboard.md) for the supervisors tile and the unowned count.


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