# devin

> Devin CLI + API as an iii worker; devin::run/start/stop/status/sessions::list follow the agent-worker family and deliver AgentEvent frames on the devin::agent-event trigger type, devin::session::* wrap the Devin cloud session lifecycle, devin::pr-review::* exposes Devin's review surface, and devin::api reaches any Devin v1/v3 endpoint.

| field | value |
|-------|-------|
| version | 0.1.19 |
| type | binary |
| license | Apache-2.0 |
| repo | https://github.com/iii-hq/workers |
| supported_targets | x86_64-apple-darwin, aarch64-apple-darwin, x86_64-pc-windows-msvc, aarch64-pc-windows-msvc, x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-unknown-linux-musl, armv7-unknown-linux-gnueabihf |
| author | iii |

## installation

```sh
iii trigger compose::add worker=devin@0.1.19
```

## configuration

```yaml
- base_url: https://api.devin.ai/v1
  cli_extra_args:
    - --permission-mode
    - dangerous
  devin_executable: 
  iii_context: true
  request_timeout_secs: 120
  session_recording: true
```

## readme

# devin

[Devin](https://docs.devin.ai) as an iii worker: the Devin coding agent exposed as functions and streams on the iii bus. Devin has two distinct products and this worker exposes both. The local [Devin CLI](https://cli.devin.ai/docs) is a SWE-1.6 coding agent that runs on your machine; `devin::run` drives it headless and, with the iii runtime context, lets it discover and operate your engine on its own. The [Devin cloud](https://docs.devin.ai) agent runs in a VM, reached over the REST API: `devin::session::*` wrap the session lifecycle, `devin::pr-review::*` run reviews, and `devin::api` reaches any v1/v3 endpoint the typed wrappers do not cover.

This worker is deliberately thin. It does not re-implement scheduling, sub-agents, or persistence that the engine already provides. Schedule a Devin session with the `cron` worker, fan Devin runs out with `harness::spawn`, and let the engine trace and persist every call. The worker's job is to put Devin on the bus, nothing more.

## Install

```bash
iii trigger compose::add worker=devin
```

For the API surface (`devin::session::*`, `devin::api`), set `DEVIN_API_KEY` in the worker environment. Get a key from the [Devin settings page](https://app.devin.ai/settings/api-keys).

For the CLI surface (`devin::run` / `devin::start`), install the local [Devin CLI](https://cli.devin.ai/docs) (`brew install --cask devin-cli`, or `curl -fsSL https://cli.devin.ai/install.sh | bash`) and run `devin auth login`. This is the local coding agent (SWE-1.6), distinct from the Devin cloud the API targets: the worker drives it in non-interactive `--print` mode, so the agent runs on the host, works with the local files under `cwd`, and returns its reply in `result`. Because it runs locally, an `iii_context` turn can reach the engine at `localhost` with no exposure.

## Skills

Install the `devin` agent skill for Claude Code, Cursor, and 30+ other agents:

```bash
npx skills add iii-hq/workers --skill devin
```

## Quickstart

From zero to a Devin cloud session over the bus:

```bash
curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
export DEVIN_API_KEY=...       # personal token (v1) or service key (cog_..., v3)
# service-key users only: also `export DEVIN_ORG_ID=org_...` and set base_url to v3
iii trigger compose::add worker=devin
iii   # starts the engine + worker
```

The API has two shapes and the worker picks one from your config. A **personal token** uses the flat v1 API and is the default (leave `org_id` empty, `base_url` stays `.../v1`). A **service key** (`cog_...`) uses the v3 API scoped to an organization: set `org_id` and `base_url` to `https://api.devin.ai/v3`. The `devin::pr-review::*` functions are v3 features.

Start a cloud session and read it back:

```bash
# start an autonomous Devin session in the cloud
iii trigger devin::session::create --timeout-ms 60000 \
  --json '{"prompt":"Open a PR that adds a /health endpoint to the api repo","title":"health endpoint"}'
# { "session_id": "devin-...", "url": "https://app.devin.ai/sessions/...", ... }

# poll its status, output, and messages
iii trigger devin::session::get session_id=devin-...

# send a follow-up
iii trigger devin::session::message \
  --json '{"session_id":"devin-...","message":"Also add a test for it"}'

# list recent sessions
iii trigger devin::api --json '{"method":"GET","path":"sessions","query":{"limit":10}}'
```

`devin::session::create` returns a real Devin cloud session over the bus (session id, url, tags):

![devin::session::create returning a real Devin cloud session id and url over the iii bus](https://raw.githubusercontent.com/iii-hq/workers/main/devin/assets/session-create.png)

The same session runs in the Devin app and replies:

![The Devin cloud session opened via devin::session::create, replying in the Devin app](https://raw.githubusercontent.com/iii-hq/workers/main/devin/assets/session-reply.png)

Run the local CLI as one turn and deliver it on the bus:

```bash
iii trigger devin::run --timeout-ms 600000 \
  --json '{"prompt":"summarize what this repo does","cwd":"/path/to/repo"}'
# raw stdout on devin::raw-event, AgentEvent frames on devin::agent-event
```

Reach any endpoint the typed wrappers do not cover:

```bash
# paths are relative to base_url. v1 (personal token) uses flat paths:
iii trigger devin::api --json '{"method":"GET","path":"sessions","query":{"limit":5}}'

# v3 (service key) paths are org-scoped:
iii trigger devin::api --json '{"method":"GET","path":"organizations/org_.../sessions"}'
```

Ask the engine for any function's contract:

```bash
iii trigger devin::session::create --help
```

## Functions

The worker follows the same base surface as the grok, codex, claude-code, and opencode agent workers (`run` / `start` / `stop` / `status` / `sessions::list` / `events`), then adds the functions unique to Devin's cloud (session lifecycle, PR review, and a passthrough for the rest).

| Function | Surface | Purpose |
| --- | --- | --- |
| `devin::run` | CLI | Run one local CLI turn, wait, return the result |
| `devin::start` | CLI | Start a turn and return immediately; progress on the streams |
| `devin::stop` | CLI | Interrupt a live CLI run |
| `devin::status` | CLI | A recorded run's state: live flag, status, linked Devin session id |
| `devin::sessions::list` | CLI | Every run this worker has recorded (each linked to its Devin session) |
| `devin::session::create` | Cloud | Start a Devin cloud session from a prompt |
| `devin::session::get` | Cloud | Fetch one session (status, messages, output) |
| `devin::session::message` | Cloud | Send a follow-up message to a running session |
| `devin::pr-review::trigger` | Cloud | Start a Devin review for a pull/merge request |
| `devin::pr-review::status` | Cloud | Latest Devin review for a pull/merge request |
| `devin::api` | Cloud | Raw authenticated call to any v1/v3 endpoint |

To list all Devin cloud sessions org-wide, use `devin::api {method: GET, path: sessions}` (v1) or `{path: organizations/{org_id}/sessions}` (v3); `devin::sessions::list` is scoped to the runs this worker made, matching the family convention.

`devin::run` / `devin::start` accept either a bare `prompt` string or a `messages` array (`[{ role: 'user', content: [{ type: 'text', text }] }]`), the same input contract as the claude-code and grok workers, so the acp worker can drive it with `--brain-fn devin::run`. Pass `parent_session_id` to nest the run under the session that delegated it in the console, the same link a harness sub-agent carries.

Because the CLI agent runs locally with the iii runtime context, a plain question makes Devin discover and operate your engine on its own, no commands spelled out:

```bash
iii trigger devin::run --json '{"prompt":"What workers are connected to this iii engine and what does each do?","cwd":"/tmp"}' | jq -r '.result'
```

![Devin answering a plain question by discovering the live iii worker functionality through the iii CLI](https://raw.githubusercontent.com/iii-hq/workers/main/devin/assets/iii-discovery.png)

Or ask it to map the whole engine by capability area, and it groups what it finds itself:

![Devin grouping the engine's backend capabilities by area, discovered live](https://raw.githubusercontent.com/iii-hq/workers/main/devin/assets/capabilities.png)

`devin::session::create` accepts `prompt` plus the union of the v1 and v3 create fields (`title`, `tags`, `playbook_id`, `knowledge_ids`, `secret_ids`, `max_acu_limit`; v3 `devin_mode`, `repos`, `attachment_urls`, `resumable`, `bypass_approval`; v1 `snapshot_id`, `unlisted`, `idempotent`); each is omitted from the body when not supplied, so populate the ones your token's API version accepts. `devin::session::*` follow the v1 flat paths by default and switch to v3 org-scoped paths when `org_id` is set.

### PR review

`devin::pr-review::trigger` starts a Devin review for a `pr_url`; `devin::pr-review::status` returns the latest review for that PR. Bind a GitHub PR-opened trigger to `devin::pr-review::trigger` for automatic reviews. Devin's other cloud surfaces (knowledge, playbooks, secrets, repos, code scan, org admin) are reachable through `devin::api` when a token has access to them.

### The passthrough

`devin::api` is the escape hatch for the full v3 surface (roughly 250 endpoints: knowledge, playbooks, secrets, repos, PR review, code scan, org and usage admin). It takes `{ method, path, query?, body? }`, adds the bearer token and organization header, and returns the parsed response. Reach for it whenever a capability is not one of the typed wrappers above; graduate a wrapper only when a call proves common.

### Sessions, event feeds and observability

`devin::run` records every turn as a `session-manager` session under its `session_id`, writing the same records a harness turn does: `session::ensure` (title from the prompt and `{ agent: "devin" }` metadata; a run with `parent_session_id` carries it and nests under that parent, a run without one is created as an `automation` session rather than a human chat), the user prompt, an assistant entry streamed with the CLI output as it prints, a `custom` `error` entry when the run fails, and the session status (`working`, then `done`, `done` + `stopped` after `devin::stop`, or `error` with the cause). The run therefore appears in the console's session list and transcript like a harness session, and can be replayed after it ends with `session::messages`. The `--print` CLI output is plain text, so tool calls appear inside that text, not as separate function rows.

It also delivers every stdout line verbatim on the `devin::raw-event` trigger type and the terminal AgentEvent frames on `devin::agent-event` (see Event feeds). Recording is on by default and switched off with `session_recording: false` (config, or per turn). Both are best-effort: when `session-manager` is not installed the worker logs that once, skips those writes, re-checks once a minute, and the run itself is unaffected; a feed with no binding delivers nothing, and a failing consumer never fails the run. The cloud functions return their JSON directly and do not stream; poll `devin::session::get` for progress, or bind a `cron` trigger to poll on a schedule instead of looping.

Every `devin::*` call is a traced invocation on the engine with no extra instrumentation: the input payload, output, duration, and ok/error land in the console's trace explorer, including the `iii trigger` calls a `devin::run` agent makes on its own.

![Every devin::run call traced in the iii console, with input prompt and output result](https://raw.githubusercontent.com/iii-hq/workers/main/devin/assets/traces.png)

### Event feeds

The worker owns two trigger types. Bind one to a function of your own with `{ session_id }` to receive one session's frames:

| Trigger type | Carries |
| --- | --- |
| `devin::agent-event` | the terminal AgentEvent frames of a `devin::run` turn (`turn_end` with the final assistant message, then `agent_end`), what the acp worker renders |
| `devin::raw-event` | every CLI stdout line, verbatim, as `{ "type": "stdout", "line": "..." }` |

Binding config: `{ "session_id": "<iii session id>", "metadata": { } }`. `session_id` is required (non-empty, at most 512 characters); `metadata` is optional and is handed to your function (it wins over the binding's own metadata). Any other key rejects the binding, and each trigger type accepts at most 256 bindings.

Your function gets one fire-and-forget call per frame:

```json
{
  "session_id": "sess-1",
  "event_id": "sess-1-<epoch>-00000003",
  "seq": 3,
  "epoch": "<uuid>",
  "source": "devin",
  "event": { "type": "stdout", "line": "done" }
}
```

`seq` counts from 0 per feed and session within one `epoch` (a uuid minted per worker process, so a restart starts a new epoch); the two feeds count independently. Deliveries may arrive out of order: order by `(epoch, seq)` and dedup by `event_id`. The feeds are ephemeral: nothing is stored or replayed, and a binding made mid-turn only sees later frames. History lives in the session-manager transcript (`session::messages` with the run's `session_id`), the session record (`devin::status`, `devin::sessions::list`) and the `devin::run` result. These trigger types replace the former `agent::events` / `devin::events` streams (see the guide "Migrate from iii-stream and pubsub").

## Configuration

Managed by the `configuration` worker; `config.yaml` is the seed installed on first registration and the live value hot-reloads.

```yaml
api_key: "${DEVIN_API_KEY}"       # env-expanded on load; empty disables the API surface
org_id: "${DEVIN_ORG_ID}"         # empty = v1 personal mode; set = v3 org-scoped mode
base_url: https://api.devin.ai/v1 # set to .../v3 alongside org_id for a service key
request_timeout_secs: 120
devin_executable: ""                          # path to the devin CLI; empty = PATH
cli_extra_args: ["--permission-mode", "dangerous"]  # before `--print --`; dangerous lets the agent run iii trigger
iii_context: true                             # prepend iii runtime context to a CLI prompt
session_recording: true                       # record each CLI turn as a console session
```

`api_key` and `org_id` are referenced as `${DEVIN_API_KEY}` and `${DEVIN_ORG_ID}` and expanded from the environment on load (an unset var becomes empty), so neither secret lives in the repo. An empty `api_key` disables the API surface while the CLI surface still works if the local `devin` binary is authenticated. `org_id` selects the API shape: empty uses the flat v1 session paths (personal tokens), set uses the v3 org-scoped paths (service keys) and becomes the required path segment for pr-review.

`iii_context` defaults on: a `devin::run` turn is prepended with the iii runtime context so the local agent discovers and calls engine functions through the `iii` CLI (turn it off per turn with `iii_context: false`). `cli_extra_args` defaults to `--permission-mode dangerous`, which is the only devin CLI mode that auto-approves command execution, so a headless run can actually run `iii trigger` against the engine; the local agent then auto-approves all tools, so drop to `accept-edits` or `auto` to restrict it.

`session_recording` defaults on: each `devin::run` / `devin::start` turn is recorded as a `session-manager` session (see Sessions, event feeds and observability). Set it to `false` to keep Devin runs out of the console entirely, or override one turn with the `session_recording` payload field.

## Dependent workers

- `configuration` (required): holds the API key, base URL, and CLI settings; hot-reloads changes.
- `session-manager` (optional): records each `devin::run` turn as a console session and transcript. Without it runs still work, unrecorded.
- `cron` (optional): schedule `devin::session::create` or poll `devin::session::get` without a polling loop.
- `harness` (optional): fan multiple Devin runs out as sub-agents with `harness::spawn`.

## Permissions

`devin::run`, `devin::start`, `devin::session::create`, `devin::session::message`, and `devin::api` drive or mutate a Devin agent and spend ACUs, so they stay at the `needs_approval` default; an agent invoking them without human approval is a privilege escalation. The read-only introspection functions (`devin::status`, `devin::sessions::list`, `devin::session::get`, `devin::pr-review::status`) and `devin::stop` are allow-listed in `iii-permissions.yaml`.

## How it maps

| Devin | iii |
| --- | --- |
| one local `devin --print -- <prompt>` turn (SWE-1.6 agent) | `devin::run` invocation |
| one `devin::run` session (prompt, output, status) | `session-manager` session, listed in the console |
| every CLI stdout line, verbatim | `devin::raw-event` delivery |
| turn end | `turn_end` + `agent_end` frames on `devin::agent-event`, function return value |
| a Devin cloud session | `devin::session::create` / `::get` / `::message` |
| a Devin PR review | `devin::pr-review::trigger` / `::status` |
| any other v1/v3 endpoint | `devin::api` passthrough |
| scheduling a run | `cron` worker trigger, not a worker feature |
| fanning runs out | `harness::spawn`, not a worker feature |

## skills

This version ships 1 skill file for agents, also browsable on the worker page:

- [`SKILL.md`](https://workers.iii.dev/workers/devin?tab=skills&skill=SKILL.md&version=0.1.19)

### SKILL.md

# devin

The devin worker exposes [Devin](https://docs.devin.ai) as iii functions across
two distinct surfaces.

The **CLI surface** drives the local [Devin CLI](https://cli.devin.ai/docs) (the
SWE-1.6 coding agent that runs in your terminal on your files). `devin::run`
executes one headless turn (`devin --permission-mode dangerous --print -- <prompt>`)
and delivers stdout on the `devin::raw-event` trigger type with the terminal
AgentEvent frames on `devin::agent-event`. Because the agent runs locally with the iii runtime context
prepended, a plain-language prompt makes Devin discover and operate your engine
on its own: it runs `iii trigger engine::functions::list`, calls any registered
function, and reports back, reaching the engine at `localhost` with no exposure.

The **cloud surface** calls the Devin REST API: `devin::session::create` starts
an autonomous cloud session, `devin::session::get` reads it, `devin::session::message`
steers it, `devin::pr-review::*` runs code reviews, and `devin::api` reaches any
endpoint the typed wrappers do not cover.

The CLI surface needs the official Devin CLI installed (`brew install --cask devin-cli`)
and authenticated (`devin auth login`). The cloud surface needs `DEVIN_API_KEY`
(and `DEVIN_ORG_ID` for a service key). When a run needs a capability beyond
Devin itself, add another iii worker to the bus instead of bolting it on.

## When to Use

- Delegate a coding task to the local agent in a chosen directory: `devin::run`
  with `prompt` and `cwd`; follow the session transcript (`session::messages`)
  or bind `devin::agent-event` / `devin::raw-event` with `{ session_id }`;
  interrupt with `devin::stop`.
- Have Devin operate your iii workers: with `iii_context` on (default), ask a plain
  question ("what workers are connected and what does each do?") and Devin
  discovers and calls engine functions itself through the iii CLI.
- Delegate a whole task to Devin's cloud agent ("open a PR that adds X"):
  `devin::session::create`, then poll `devin::session::get` and steer with
  `devin::session::message`.
- Review a pull request: `devin::pr-review::trigger` with a `pr_url`, then
  `devin::pr-review::status`; bind a GitHub PR-opened trigger for auto-review.
- Reach any other Devin capability with no typed wrapper (knowledge, playbooks,
  secrets, repos, code scan, org admin): `devin::api` with
  `{ method, path, query?, body? }`.
- Schedule or fan out: bind a `cron` trigger to `devin::session::create`, or
  spawn multiple runs with `harness::spawn`. The worker does not re-implement
  scheduling or sub-agents.

## Boundaries

- `devin::run` / `devin::start` spawn the local Devin CLI headless with
  `--permission-mode dangerous` by default, so the agent auto-approves all local
  tools (needed to run `iii trigger` without blocking). Drop to `accept-edits`
  or `auto` via `cli_extra_args` to restrict it.
- `devin::run` needs the official Devin CLI installed and `devin auth login`; it
  is not available inside a bare container without it.
- The cloud surface spends ACUs and mutates real Devin state; cloud functions
  return JSON directly and do not stream, so poll `devin::session::get` (or
  schedule the poll with `cron`) rather than spinning a tight loop.
- Mutating functions (`run`, `start`, `session::create` / `message`,
  `pr-review::trigger`, `api`) stay at the `needs_approval` default; read-only
  reads and `stop` are allow-listed.
- An empty `api_key` disables the cloud surface; the CLI surface still works if
  the local binary is authenticated.

## Functions

- `devin::run` — run one local CLI turn and wait; accepts `prompt` (or a
  `messages` array), `cwd`, `iii_context`, `parent_session_id`, and
  `session_recording`; returns
  `{session_id, devin_session_id, url, result, stop_reason, is_error}`. Unless
  `session_recording` is off, the turn is also recorded as a `session-manager`
  session with the same `session_id` (prompt, streamed output, failure notice,
  status): nested under `parent_session_id` when given, otherwise an
  `automation` session. Read it back with `session::messages`.
- `devin::start` — same payload, returns `{session_id, started}` immediately;
  progress arrives in the session transcript and on the event feeds.
- `devin::stop` — interrupt the live CLI run for a session.
- `devin::status` — point-in-time view of a recorded run: live flag, status,
  linked Devin session id.
- `devin::sessions::list` — every run this worker has recorded (each linked to
  its Devin session). For all cloud sessions org-wide, use `devin::api`.
- `devin::session::create` — start a Devin cloud session; accepts `prompt` (or a
  `messages` array) plus `title`, `tags`, `playbook_id`, `knowledge_ids`,
  `secret_ids`, `max_acu_limit`, and the v3 (`devin_mode`, `repos`, ...) or v1
  (`snapshot_id`, `unlisted`, `idempotent`) fields your token accepts.
- `devin::session::get` — fetch one session by id (status, output).
- `devin::session::message` — send a follow-up `message` to a running session.
- `devin::pr-review::trigger` — start a Devin review for a `pr_url`.
- `devin::pr-review::status` — latest review for a `pr_url` (optional `commit_sha`).
- `devin::api` — raw authenticated call to any v1/v3 endpoint:
  `{ method, path, query?, body? }`.

## api reference

```json
{
  "functions": [
    {
      "description": "Call any Devin v3 API endpoint directly: {method, path, query?, body?}. Use for anything the typed devin::session::* wrappers do not cover.",
      "metadata": {},
      "name": "devin::api",
      "request_schema": {
        "description": "A raw pass-through call to any Devin v3 endpoint. Use this for anything the typed wrappers do not cover. Paths are relative to the configured base URL (e.g. `organizations/{org_id}/sessions`).",
        "properties": {
          "body": {
            "description": "Optional JSON request body."
          },
          "method": {
            "description": "HTTP method: GET, POST, PUT, PATCH, or DELETE.",
            "type": "string"
          },
          "path": {
            "description": "Path relative to the configured base URL, e.g. `organizations/{org_id}/sessions`.",
            "type": "string"
          },
          "query": {
            "description": "Optional query parameters as a flat object."
          }
        },
        "required": [
          "method",
          "path"
        ],
        "title": "ApiRequest",
        "type": "object"
      },
      "response_schema": {
        "additionalProperties": true,
        "type": "object"
      }
    },
    {
      "description": "Internal: reload devin configuration when it changes.",
      "metadata": {
        "internal": true
      },
      "name": "devin::on-config-change",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Get the latest Devin review status for a pull/merge request.",
      "metadata": {},
      "name": "devin::pr-review::status",
      "request_schema": {
        "description": "Look up the latest Devin PR review for a pull/merge request.",
        "properties": {
          "commit_sha": {
            "description": "Commit SHA (full or short); defaults to the PR head when omitted.",
            "type": [
              "string",
              "null"
            ]
          },
          "pr_url": {
            "description": "Full URL of the pull/merge request to look up.",
            "type": "string"
          }
        },
        "required": [
          "pr_url"
        ],
        "title": "PrReviewStatusRequest",
        "type": "object"
      },
      "response_schema": {
        "additionalProperties": true,
        "type": "object"
      }
    },
    {
      "description": "Trigger a Devin review for a pull/merge request by its URL.",
      "metadata": {},
      "name": "devin::pr-review::trigger",
      "request_schema": {
        "description": "Trigger a Devin PR review for a pull/merge request.",
        "properties": {
          "pr_url": {
            "description": "Full URL of the pull/merge request to review.",
            "type": "string"
          }
        },
        "required": [
          "pr_url"
        ],
        "title": "PrReviewTriggerRequest",
        "type": "object"
      },
      "response_schema": {
        "additionalProperties": true,
        "type": "object"
      }
    },
    {
      "description": "Run one Devin CLI turn and wait for the result. Accepts `prompt` or a `messages` array; records the turn as a session-manager session (listed in the console, nested under `parent_session_id` when given), delivers raw CLI stdout on devin::raw-event and terminal AgentEvent frames on devin::agent-event, and returns {session_id, devin_session_id, url, result, stop_reason, is_error}.",
      "metadata": {},
      "name": "devin::run",
      "request_schema": {
        "definitions": {
          "Message": {
            "properties": {
              "content": {
                "description": "Either a plain string or an array of content blocks."
              },
              "role": {
                "type": "string"
              }
            },
            "required": [
              "content",
              "role"
            ],
            "type": "object"
          }
        },
        "properties": {
          "cwd": {
            "default": null,
            "description": "Working directory the CLI runs in. Empty = the worker's process directory.",
            "type": [
              "string",
              "null"
            ]
          },
          "iii_context": {
            "default": null,
            "description": "Prepend the iii runtime discovery prompt as leading instructions (default from config).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "messages": {
            "description": "Alternative to prompt: role/content messages; the last user entry becomes the prompt.",
            "items": {
              "$ref": "#/definitions/Message"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "parent_session_id": {
            "default": null,
            "description": "The session delegating this run. Written to the session-manager session metadata on creation, which nests the run under its parent in the console — the same link a harness sub-agent carries.",
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "default": null,
            "description": "The prompt handed to the `devin` CLI for this turn.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "default": null,
            "description": "iii session id; reuse to keep the same local record. Omit to generate one.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_recording": {
            "default": null,
            "description": "Record this turn as a session-manager session listed in the console (default from config `session_recording`).",
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "title": "RunRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "busy": {
            "type": "boolean"
          },
          "devin_session_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_error": {
            "type": "boolean"
          },
          "num_turns": {
            "type": "integer"
          },
          "reason": {
            "type": "string"
          },
          "result": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "stop_reason": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Create a Devin cloud session from a prompt. Optional fields (title, tags, playbook_id, snapshot_id, idempotent, max_acu_limit, secret_ids, knowledge_ids, unlisted) map to POST /sessions.",
      "metadata": {},
      "name": "devin::session::create",
      "request_schema": {
        "definitions": {
          "Message": {
            "properties": {
              "content": {
                "description": "Either a plain string or an array of content blocks."
              },
              "role": {
                "type": "string"
              }
            },
            "required": [
              "content",
              "role"
            ],
            "type": "object"
          }
        },
        "description": "Create a Devin session. `prompt` (or a user `messages` entry) is required. The remaining fields are the union of the v1 (`POST /v1/sessions`) and v3 (`POST /v3/organizations/{org_id}/sessions`) bodies; each is omitted when absent, so populate the ones your token's API version accepts.",
        "properties": {
          "attachment_urls": {
            "default": null,
            "description": "(v3) File attachment URLs.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "bypass_approval": {
            "default": null,
            "description": "(v3) Skip approval workflows for this session.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "devin_mode": {
            "default": null,
            "description": "(v3) Agent mode: normal, fast, lite, ultra, or fusion.",
            "type": [
              "string",
              "null"
            ]
          },
          "idempotent": {
            "default": null,
            "description": "(v1) Reuse an existing matching session instead of creating a duplicate.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "knowledge_ids": {
            "default": null,
            "description": "Knowledge ids to attach to the session.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "max_acu_limit": {
            "default": null,
            "description": "Cap the session's ACU consumption.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "messages": {
            "description": "Alternative to prompt: role/content messages; the last user entry becomes the prompt.",
            "items": {
              "$ref": "#/definitions/Message"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "playbook_id": {
            "default": null,
            "description": "Playbook id to run.",
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "default": null,
            "description": "The task prompt for the new Devin session.",
            "type": [
              "string",
              "null"
            ]
          },
          "repos": {
            "default": null,
            "description": "(v3) Repository identifiers to attach to the session.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "resumable": {
            "default": null,
            "description": "(v3) Preserve VM state so the session can be resumed (default true).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "secret_ids": {
            "default": null,
            "description": "Secret ids to expose to the session.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "snapshot_id": {
            "default": null,
            "description": "(v1) Machine snapshot id to start the session from.",
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "default": null,
            "description": "Tags to apply to the session.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "title": {
            "default": null,
            "description": "Human-readable session title.",
            "type": [
              "string",
              "null"
            ]
          },
          "unlisted": {
            "default": null,
            "description": "(v1) Create the session as unlisted.",
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "title": "SessionCreateRequest",
        "type": "object"
      },
      "response_schema": {
        "additionalProperties": true,
        "type": "object"
      }
    },
    {
      "description": "Fetch one Devin cloud session (status, messages, output) by session id.",
      "metadata": {},
      "name": "devin::session::get",
      "request_schema": {
        "properties": {
          "session_id": {
            "description": "iii session id (devin::run) or Devin cloud session id (devin::session::*).",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SessionIdRequest",
        "type": "object"
      },
      "response_schema": {
        "additionalProperties": true,
        "type": "object"
      }
    },
    {
      "description": "Send a message to continue a running Devin cloud session.",
      "metadata": {},
      "name": "devin::session::message",
      "request_schema": {
        "description": "Send a follow-up message to a running Devin session.",
        "properties": {
          "message": {
            "description": "The message to send.",
            "type": "string"
          },
          "session_id": {
            "description": "Devin cloud session id (returned by devin::session::create).",
            "type": "string"
          }
        },
        "required": [
          "message",
          "session_id"
        ],
        "title": "SessionMessageRequest",
        "type": "object"
      },
      "response_schema": {
        "additionalProperties": true,
        "type": "object"
      }
    },
    {
      "description": "List the Devin CLI runs this worker has recorded, each linked to its Devin cloud session id. For all Devin cloud sessions org-wide, use devin::api {method: GET, path: sessions}.",
      "metadata": {},
      "name": "devin::sessions::list",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "sessions": {
            "items": {
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Start a Devin CLI turn and return immediately; follow the session-manager session (session::messages, session_id) or bind devin::agent-event / devin::raw-event with { session_id } for progress and turn_end.",
      "metadata": {},
      "name": "devin::start",
      "request_schema": {
        "definitions": {
          "Message": {
            "properties": {
              "content": {
                "description": "Either a plain string or an array of content blocks."
              },
              "role": {
                "type": "string"
              }
            },
            "required": [
              "content",
              "role"
            ],
            "type": "object"
          }
        },
        "properties": {
          "cwd": {
            "default": null,
            "description": "Working directory the CLI runs in. Empty = the worker's process directory.",
            "type": [
              "string",
              "null"
            ]
          },
          "iii_context": {
            "default": null,
            "description": "Prepend the iii runtime discovery prompt as leading instructions (default from config).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "messages": {
            "description": "Alternative to prompt: role/content messages; the last user entry becomes the prompt.",
            "items": {
              "$ref": "#/definitions/Message"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "parent_session_id": {
            "default": null,
            "description": "The session delegating this run. Written to the session-manager session metadata on creation, which nests the run under its parent in the console — the same link a harness sub-agent carries.",
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "default": null,
            "description": "The prompt handed to the `devin` CLI for this turn.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "default": null,
            "description": "iii session id; reuse to keep the same local record. Omit to generate one.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_recording": {
            "default": null,
            "description": "Record this turn as a session-manager session listed in the console (default from config `session_recording`).",
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "title": "RunRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "session_id": {
            "type": "string"
          },
          "started": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Check the status of a local Devin CLI run.",
      "metadata": {},
      "name": "devin::status",
      "request_schema": {
        "properties": {
          "session_id": {
            "description": "iii session id (devin::run) or Devin cloud session id (devin::session::*).",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SessionIdRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "live": {
            "type": "boolean"
          },
          "record": {
            "type": [
              "object",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Stop a running Devin CLI turn for a session.",
      "metadata": {},
      "name": "devin::stop",
      "request_schema": {
        "properties": {
          "session_id": {
            "description": "iii session id (devin::run) or Devin cloud session id (devin::session::*).",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SessionIdRequest",
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "stopped": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    }
  ],
  "triggers": [
    {
      "description": "Translated AgentEvent frames of one devin session. Config: { session_id, metadata? }. Payload: { session_id, event_id, seq, epoch, source, event }. Ephemeral (not stored, not replayed); order by (epoch, seq).",
      "invocation_schema": {},
      "metadata": {},
      "name": "devin::agent-event",
      "return_schema": {}
    },
    {
      "description": "Raw Devin CLI stdout lines ({ type: stdout, line }, verbatim) of one devin session. Config: { session_id, metadata? }. Payload: { session_id, event_id, seq, epoch, source, event }. Ephemeral (not stored, not replayed); order by (epoch, seq).",
      "invocation_schema": {},
      "metadata": {},
      "name": "devin::raw-event",
      "return_schema": {}
    }
  ]
}
```
