Devin 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 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 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.
iii worker add devinFor the API surface (devin::session::*, devin::api), set DEVIN_API_KEY in the worker environment. Get a key from the Devin settings page.
For the CLI surface (devin::run / devin::start), install the local Devin CLI (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.
Install the devin agent skill for Claude Code, Cursor, and 30+ other agents:
npx skills add iii-hq/workers --skill devinFrom zero to a Devin cloud session over the bus:
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 worker add devin
iii # starts the engine + workerThe 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:
# 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):
The same session runs in the Devin app and replies:
Run the local CLI as one turn and stream it onto the bus:
iii trigger devin::run --timeout-ms 600000 \
--json '{"prompt":"summarize what this repo does","cwd":"/path/to/repo"}'
# streams raw stdout onto devin::events, AgentEvent frames onto agent::eventsReach any endpoint the typed wrappers do not cover:
# 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:
iii trigger devin::session::create --helpThe 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.
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:
iii trigger devin::run --json '{"prompt":"What workers are connected to this iii engine and what does each do?","cwd":"/tmp"}' | jq -r '.result'Or ask it to map the whole engine by capability area, and it groups what it finds itself:
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.
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.
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.
devin::run mirrors every stdout line from the CLI verbatim onto devin::events (group_id = session_id) and emits a terminal AgentEvent frame onto agent::events, so the iii console renders a Devin CLI turn like any other agent worker. 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.
Managed by the configuration worker; config.yaml is the seed installed on first registration and the live value hot-reloads.
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
events_stream: agent::events # AgentEvent frames
raw_events_stream: devin::events # verbatim CLI stdout
iii_context: true # prepend iii runtime context to a CLI promptapi_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.
configuration(required): holds the API key, base URL, and stream names; hot-reloads changes.cron(optional): scheduledevin::session::createor polldevin::session::getwithout a polling loop.harness(optional): fan multiple Devin runs out as sub-agents withharness::spawn.
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.
| Devin | iii |
|---|---|
one local devin --print -- <prompt> turn (SWE-1.6 agent) |
devin::run invocation |
| every CLI stdout line, verbatim | devin::events stream frame |
| 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 |




