Skip to content

feat(devin): add Devin CLI + API worker (MOT-3880) - #425

Merged
rohitg00 merged 10 commits into
iii-hq:mainfrom
rohitg00:devin-worker
Jul 7, 2026
Merged

feat(devin): add Devin CLI + API worker (MOT-3880)#425
rohitg00 merged 10 commits into
iii-hq:mainfrom
rohitg00:devin-worker

Conversation

@rohitg00

@rohitg00 rohitg00 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Linear: MOT-3880 (subtickets MOT-3883/3884/3885/3886)

What

A deploy: binary Rust worker that puts Devin on the iii bus, built on the grok scaffold and consistent with the grok / codex / claude-code / opencode agent-worker family. Devin has two distinct products and the worker exposes both:

  • The Devin CLI (cli.devin.ai) is a local coding agent (SWE-1.6) that runs in your terminal on your files. devin::run / start / stop / status / sessions::list drive it, matching the family surface, and stream onto devin::events + agent::events.
  • Devin cloud (docs.devin.ai) is the autonomous agent in a VM, reached over the REST API: devin::session::create / get / message, devin::pr-review::trigger / status, and a devin::api passthrough for the rest.

Functions (11)

Function Purpose
devin::run / start / stop / status / sessions::list Agent-worker family base: drive the local CLI agent (run, fire-and-forget, interrupt, inspect, list recorded runs)
devin::session::create / get / message Devin cloud session lifecycle
devin::pr-review::trigger / status Start and read a Devin PR review (composable with a GitHub PR-opened trigger)
devin::api Raw authenticated call to any v1/v3 endpoint {method, path, query?, body?}

The CLI surface (devin::run)

The value for an iii user is bidirectional: iii delegates a coding task to the local Devin agent, and with iii_context on, that agent discovers and calls any registered iii function (email, db, storage, other agents) mid-task. Because the CLI agent runs locally, it reaches the engine at localhost with no exposure of the engine.

Getting there took two corrections worth recording:

  • The official CLI is brew install --cask devin-cli (or curl -fsSL https://cli.devin.ai/install.sh | bash), authenticated with devin auth login. A different @usacognition-beta/devin npm build creates cloud sessions and muddied early testing; the worker targets the official local CLI.
  • A bare devin -- "<prompt>" starts an interactive TUI that needs a TTY. The non-interactive mode is -p/--print ("print response and exit"). devin::run now spawns devin --permission-mode auto --print -- <prompt>, so it runs headless, works with the files under cwd, and returns the agent's reply. The local record links to the Devin session id parsed from the CLI output.

Design

  • Family-consistent + only Devin's unique surface. Same base as the other agent workers plus the Devin cloud lifecycle and PR review. An audit removed code-scan (enterprise-gated, 403 for typical users) since it is reachable through devin::api when a token has enterprise access.
  • No re-implementation of engine capabilities. No scheduler (bind a cron trigger), no sub-agent fan-out (harness::spawn); devin::api reaches the long tail.
  • Two API shapes. Personal tokens use the flat v1 API; service keys use v3 scoped under organizations/{org_id}. The session wrappers pick the shape from whether org_id is set. api_key / org_id are env-expanded on load, so no secret lives in the repo.
  • Permissions. Functions that drive or mutate a Devin agent or spend ACUs stay at the needs_approval default; read-only introspection and stop are allow-listed.
  • Config-worker integration (Path B), best-effort so the worker boots for interface collection on a bare engine.

Verified end to end (both API modes, real data)

  • v1 (personal token): GET /v1/sessions, GET /v1/session/{id} return session data; message + create validate their required fields.
  • v3 (service key + org_id): through the worker on a live engine, devin::session::create created a real session, devin::session::get returned the full object, and the devin::api passthrough listed the org's sessions.
  • CLI: the official CLI's --print invocation reaches the local agent (verified; a full turn was limited only by daily quota at test time).
  • Registration, streaming onto devin::events + agent::events, and the local record linking to the Devin session all confirmed through the engine. fmt / clippy -D warnings / tests clean.

Draft note

Mutating functions (session::create / message, pr-review::trigger, devin::run) spend ACUs and spawn real agents; they are confirmed at the path/validation layer and, for the cloud session lifecycle, run to a real session. Marked for maintainer review of the surface and scoping.

Rust binary worker exposing Devin on the iii bus across two surfaces. The local devin CLI drives one headless turn via devin::run and streams onto devin::events and agent::events. The Devin v3 REST API drives the cloud agent: devin::session::{create,get,list,message} for the org-scoped session lifecycle, devin::pr-review::{trigger,status}, devin::code-scan::{findings,metrics,remediate}, and a devin::api passthrough for the rest of the v3 surface.

Modeled on the grok worker: credentials, base URL, streams, and the devin CLI path come from the configuration worker and hot-reload; DEVIN_API_KEY and DEVIN_ORG_ID are env-expanded so no secret lives in the repo. Mutating functions stay at the needs_approval default; read-only introspection is allow-listed. Scheduling and fan-out are left to the cron and harness workers rather than re-implemented.
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

@rohitg00 is attempting to deploy a commit to the motia Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rohitg00, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cabab68a-58a2-4475-afcc-28cd22d13379

📥 Commits

Reviewing files that changed from the base of the PR and between dc570d6 and 3476594.

⛔ Files ignored due to path filters (5)
  • devin/assets/capabilities.png is excluded by !**/*.png
  • devin/assets/iii-discovery.png is excluded by !**/*.png
  • devin/assets/session-create.png is excluded by !**/*.png
  • devin/assets/session-reply.png is excluded by !**/*.png
  • devin/assets/traces.png is excluded by !**/*.png
📒 Files selected for processing (10)
  • devin/README.md
  • devin/config.yaml
  • devin/iii-permissions.yaml
  • devin/iii.worker.yaml
  • devin/skills/SKILL.md
  • devin/src/api.rs
  • devin/src/cli.rs
  • devin/src/config.rs
  • devin/src/functions/mod.rs
  • devin/src/functions/types.rs
📝 Walkthrough

Walkthrough

Adds a new devin/ Rust crate implementing an iii worker that drives the local Devin CLI (devin::run/start/stop/status), wraps Devin cloud v1/v3 REST endpoints (sessions, PR review, code scan), streams events, persists session state, hot-reloads configuration, and includes permissions, worker manifest, docs, and tests.

Changes

Devin worker crate

Layer / File(s) Summary
Crate scaffolding
devin/Cargo.toml, devin/.gitignore, devin/build.rs, devin/src/manifest.rs, devin/src/lib.rs
Adds crate manifest, dependencies, gitignore, build script emitting TARGET env, module manifest builder, and library module exports.
Configuration and hot-reload
devin/src/config.rs, devin/src/configuration.rs, devin/config.yaml, devin/tests/config.rs
Defines Config struct/defaults, YAML load with env expansion, and ConfigCell registration/fetch/apply/trigger logic for hot config reload, with tests.
Session wire types and persistence
devin/src/wire.rs, devin/src/state.rs
Adds SessionRecord/Status/AssistantMessage types and load_session/save_session/list_sessions/mark_error state helpers.
Event streaming
devin/src/events.rs
Emits unique-id stream frames via stream::set triggers, best-effort.
Local CLI execution
devin/src/cli.rs
Spawns and streams the local devin CLI process, tracks live runs, composes prompts/argv, parses session refs.
Devin cloud REST client
devin/src/api.rs
HTTP client with request helper, v1/v3 path resolution, and wrappers for sessions, PR review, code scan.
Function registration
devin/src/functions/mod.rs, devin/src/functions/types.rs
Defines request types/prompt extraction and registers all devin::* iii functions wiring CLI/API/state.
Entrypoint and context prompt
devin/src/main.rs, devin/src/iii_prompt.rs
CLI parsing, worker registration, config bootstrap, shutdown handling, and iii runtime context prompt.
Permissions, manifest, docs
devin/iii-permissions.yaml, devin/iii.worker.yaml, devin/README.md, devin/skills/SKILL.md, README.md
Adds allow/deny permission rules, worker manifest, README/skill docs, and top-level module table entry.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant FunctionsMod as devin::run
  participant CliModule as cli::run
  participant Process as devin CLI process
  participant StateModule as state.rs
  participant EventsModule as events::emit

  Client->>FunctionsMod: devin::run(RunRequest)
  FunctionsMod->>CliModule: run(iii, cfg, req)
  CliModule->>StateModule: load_session
  CliModule->>Process: spawn devin with argv
  Process-->>CliModule: stdout lines
  CliModule->>EventsModule: emit raw_events_stream
  CliModule->>StateModule: save_session(status)
  CliModule->>EventsModule: emit turn_end/agent_end
  CliModule-->>FunctionsMod: result JSON
  FunctionsMod-->>Client: session result
Loading

Suggested reviewers: guibeira

Poem

A rabbit hops through Rust so bright, 🐇
Streaming Devin's thoughts by night,
Config hot-swapped, sessions saved,
CLI runs cleanly, cloud paths paved,
Hop, hop — the worker's alive and right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a Devin CLI and API worker.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Live-verified against api.devin.ai: personal tokens (apk_/clerk) use the flat v1 API (GET /v1/sessions, GET /v1/session/{id}, POST /v1/session/{id}/message), while v3 is org-scoped and rejects personal tokens. The session wrappers now pick the path shape from whether org_id is set (v1 flat by default, v3 organizations/{org_id}/... when set), base_url defaults to v1, and the create body carries the union of v1 and v3 fields (each omitted when absent).

Config::load now env-expands ${NAME} like the peer workers, so DEVIN_API_KEY and DEVIN_ORG_ID resolve at seed load and an unset org var becomes empty (v1 mode). pr-review and code-scan remain v3/enterprise-only.
@rohitg00 rohitg00 changed the title feat(devin): add Devin CLI + API worker feat(devin): add Devin CLI + API worker (MOT-3880) Jul 6, 2026
rohitg00 added 2 commits July 6, 2026 14:42
Match the grok and codex workers by defaulting iii_context on, so a devin::run turn is prepended with the iii runtime context. Extract the prompt composition into compose_prompt and cover it with tests (prepend on first turn, absent when disabled, not repeated on resume) plus a test that the CLI argv uses the documented devin -- <prompt> form.

Verified end to end against a live engine: the worker registers 15 functions; devin::session::list/get and devin::api return real Devin data; devin::run creates a real session and streams onto agent::events and devin::events; and with iii_context on, the created session's prompt carries the iii runtime context (confirmed via session::get).
Match the grok/codex/claude-code/opencode base surface: add devin::start (fire-and-forget), rename devin::runs::list to devin::sessions::list, and drop the cloud devin::session::list (list all cloud sessions via devin::api {GET sessions} instead, removing the sessions::list vs session::list clash).

Fix the local record so it links to the Devin session the CLI opened: parse the {id,url} the devin CLI prints and populate devin_session_id (was always null) plus return url. devin::status and devin::sessions::list now point at the real Devin session; verified end to end (a run linked to devin-6d10fe20...).
@rohitg00
rohitg00 marked this pull request as ready for review July 6, 2026 14:21
@rohitg00
rohitg00 marked this pull request as draft July 6, 2026 14:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
devin/src/api.rs (1)

98-227: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Percent-encode path segments before building Devin URLs

The path helpers splice org_id, session_id, scan_id, and finding_id directly into the URL, so reserved characters can change the target endpoint. Percent-encode each segment before formatting it into the path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@devin/src/api.rs` around lines 98 - 227, The URL path helpers in api.rs
insert org_id, session_id, scan_id, and finding_id directly into Devin
endpoints, which can break routing when those values contain reserved
characters. Update org_scoped, sessions_collection, session_item,
session_message_path, and code_scan_remediate to percent-encode each dynamic
path segment before formatting the path. Keep the existing request call sites
unchanged and apply the encoding at the helper level so all consumers get safe
paths.
🧹 Nitpick comments (1)
devin/src/manifest.rs (1)

13-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

supported_targets will always be a single-element list.

The field name suggests multi-target support, but it's populated from a single compile-time TARGET value, so it can only ever report the build's own triple. Harmless today, but worth a comment noting the intended semantics if this manifest is later consumed by tooling expecting multiple targets per artifact.

Also applies to: 22-22

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@devin/src/manifest.rs` around lines 13 - 14, The supported_targets field in
Manifest is only ever populated from the compile-time TARGET value, so document
that it is intentionally a single-element list. Add a clear comment near
Manifest/supported_targets or its population site explaining that it represents
the build’s own triple, so future tooling does not assume multi-target support.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@devin/src/main.rs`:
- Around line 62-69: Update the stale comment around Config::load in main to
match the actual fallback behavior: a seed config parse error does not fail
fast, it logs a warning via tracing::warn! and continues with seed = None so
later code can fall back to Config::default(). Keep the code path unchanged and
revise the comment near the seed loading logic to reflect that the configuration
worker is used as the fallback instead of treating a bad config as fatal.

In `@devin/src/state.rs`:
- Around line 62-70: The list_sessions path currently swallows corrupt
SessionRecord entries by using filter_map(...).ok(), which conflicts with the
fail-fast behavior used by load_session. Update the list_sessions parsing logic
to explicitly handle serde_json::from_value failures, and log each
skipped/corrupt item with enough context before continuing. Use the existing
SessionRecord and list_sessions symbols to locate the code, and preserve the
current behavior of returning only valid records while making
version-drift/corruption visible in logs.

---

Outside diff comments:
In `@devin/src/api.rs`:
- Around line 98-227: The URL path helpers in api.rs insert org_id, session_id,
scan_id, and finding_id directly into Devin endpoints, which can break routing
when those values contain reserved characters. Update org_scoped,
sessions_collection, session_item, session_message_path, and code_scan_remediate
to percent-encode each dynamic path segment before formatting the path. Keep the
existing request call sites unchanged and apply the encoding at the helper level
so all consumers get safe paths.

---

Nitpick comments:
In `@devin/src/manifest.rs`:
- Around line 13-14: The supported_targets field in Manifest is only ever
populated from the compile-time TARGET value, so document that it is
intentionally a single-element list. Add a clear comment near
Manifest/supported_targets or its population site explaining that it represents
the build’s own triple, so future tooling does not assume multi-target support.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b1db4f1-348a-42f7-9c64-59061a734c49

📥 Commits

Reviewing files that changed from the base of the PR and between 14a4260 and dc570d6.

⛔ Files ignored due to path filters (1)
  • devin/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (23)
  • README.md
  • devin/.gitignore
  • devin/Cargo.toml
  • devin/README.md
  • devin/build.rs
  • devin/config.yaml
  • devin/iii-permissions.yaml
  • devin/iii.worker.yaml
  • devin/skills/SKILL.md
  • devin/src/api.rs
  • devin/src/cli.rs
  • devin/src/config.rs
  • devin/src/configuration.rs
  • devin/src/events.rs
  • devin/src/functions/mod.rs
  • devin/src/functions/types.rs
  • devin/src/iii_prompt.rs
  • devin/src/lib.rs
  • devin/src/main.rs
  • devin/src/manifest.rs
  • devin/src/state.rs
  • devin/src/wire.rs
  • devin/tests/config.rs

Comment thread devin/src/main.rs
Comment on lines +62 to +69
// Seed from config.yaml when present; a parse error fails fast.
let seed = match Config::load(&cli.config) {
Ok(cfg) => Some(cfg),
Err(e) => {
tracing::warn!(path = %cli.config, error = %e, "failed to load seed config; relying on the configuration worker");
None
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale comment: contradicts actual fallback behavior.

The comment says a parse error "fails fast," but the code does the opposite — it logs a warning and continues with seed = None, later falling back to Config::default(). This matches the repo's config-fallback convention correctly; only the comment is wrong and could mislead future maintainers into thinking a bad seed file is fatal.

📝 Suggested comment fix
-    // Seed from config.yaml when present; a parse error fails fast.
+    // Seed from config.yaml when present; a parse error is logged and we fall
+    // back to the configuration worker / built-in defaults (never fails fast).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Seed from config.yaml when present; a parse error fails fast.
let seed = match Config::load(&cli.config) {
Ok(cfg) => Some(cfg),
Err(e) => {
tracing::warn!(path = %cli.config, error = %e, "failed to load seed config; relying on the configuration worker");
None
}
};
// Seed from config.yaml when present; a parse error is logged and we fall
// back to the configuration worker / built-in defaults (never fails fast).
let seed = match Config::load(&cli.config) {
Ok(cfg) => Some(cfg),
Err(e) => {
tracing::warn!(path = %cli.config, error = %e, "failed to load seed config; relying on the configuration worker");
None
}
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@devin/src/main.rs` around lines 62 - 69, Update the stale comment around
Config::load in main to match the actual fallback behavior: a seed config parse
error does not fail fast, it logs a warning via tracing::warn! and continues
with seed = None so later code can fall back to Config::default(). Keep the code
path unchanged and revise the comment near the seed loading logic to reflect
that the configuration worker is used as the fallback instead of treating a bad
config as fatal.

Source: Learnings

Comment thread devin/src/state.rs
Comment on lines +62 to +70
let arr = match v.as_array() {
Some(a) => a,
None => return Ok(vec![]),
};
Ok(arr
.iter()
.filter_map(|item| serde_json::from_value::<SessionRecord>(item.clone()).ok())
.collect())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Silent record drop in list_sessions contradicts the fail-fast policy for corrupt records.

load_session treats a corrupt/version-drifted record as a real error to surface (per its doc comment), but list_sessions silently discards the same failure via .ok(), so a corrupted session simply disappears from devin::runs::list with no log trace.

🛠️ Suggested fix: log skipped/corrupt entries
     Ok(arr
         .iter()
-        .filter_map(|item| serde_json::from_value::<SessionRecord>(item.clone()).ok())
+        .filter_map(|item| match serde_json::from_value::<SessionRecord>(item.clone()) {
+            Ok(rec) => Some(rec),
+            Err(e) => {
+                tracing::warn!(error = %e, "skipping corrupt session record in list");
+                None
+            }
+        })
         .collect())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let arr = match v.as_array() {
Some(a) => a,
None => return Ok(vec![]),
};
Ok(arr
.iter()
.filter_map(|item| serde_json::from_value::<SessionRecord>(item.clone()).ok())
.collect())
}
let arr = match v.as_array() {
Some(a) => a,
None => return Ok(vec![]),
};
Ok(arr
.iter()
.filter_map(|item| match serde_json::from_value::<SessionRecord>(item.clone()) {
Ok(rec) => Some(rec),
Err(e) => {
tracing::warn!(error = %e, "skipping corrupt session record in list");
None
}
})
.collect())
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@devin/src/state.rs` around lines 62 - 70, The list_sessions path currently
swallows corrupt SessionRecord entries by using filter_map(...).ok(), which
conflicts with the fail-fast behavior used by load_session. Update the
list_sessions parsing logic to explicitly handle serde_json::from_value
failures, and log each skipped/corrupt item with enough context before
continuing. Use the existing SessionRecord and list_sessions symbols to locate
the code, and preserve the current behavior of returning only valid records
while making version-drift/corruption visible in logs.

rohitg00 added 4 commits July 6, 2026 16:13
The official Devin CLI (the local SWE-1.6 coding agent, brew install --cask devin-cli) runs a bare 'devin -- <prompt>' as an interactive TUI that needs a TTY. Its non-interactive mode is -p/--print ('print response and exit'). build_args now emits '--permission-mode auto --print -- <prompt>' so devin::run runs the local agent headless, works with the files under cwd, and returns the agent's reply in result. Verified the invocation reaches the agent (blocked only by daily quota at test time).

Because the CLI agent runs locally, an iii_context turn can reach the engine at localhost with no exposure, which is the point of the CLI surface. Requires the official CLI plus 'devin auth login'; the earlier @usacognition-beta/devin npm build was a different, cloud-creating binary.
…hrough)

Audit trim: removed devin::code-scan::{findings,metrics,remediate}. Code scanning needs the enterprise UseAccountCodeScans permission, so the vast majority of iii users get 403 and cannot use it; the rare enterprise user reaches it through devin::api. Removes 3 functions, 3 request types, and 3 api wrappers (~150 LOC) that no typical iii user can call.

Worker is now 11 functions: the agent-worker family base (run/start/stop/status/sessions::list), the Devin cloud session lifecycle (session::create/get/message), pr-review::{trigger,status} (org-scoped, composable with a PR-opened trigger), and the devin::api passthrough.
Add four assets embedded via relative paths: iii-discovery (Devin discovering the live worker mesh from a plain question), capabilities (Devin grouping the engine's backend capabilities), session-reply (a real Devin cloud session in the app), and traces (every devin::run traced in the console). These show the bidirectional value: iii delegates to Devin and Devin operates the iii mesh on its own.

Correct the permission-mode docs: the devin CLI --help lists a nonexistent 'smart' mode; the real modes are auto (read-only), accept-edits, and dangerous (all tools). Only dangerous auto-approves command execution, so it is what a headless iii-context run needs to run iii trigger; the committed default stays auto.
…he local CLI

Default devin::run to --permission-mode dangerous so a headless iii-context run can run iii trigger against the engine out of the box (the point of the CLI surface, and consistent with grok/codex headless auto-approve). Drop to accept-edits or auto via cli_extra_args to restrict the local agent.

Refresh SKILL.md, README, and cli.rs module docs for the current reality: the Devin CLI is the local SWE-1.6 coding agent (official cask + devin auth login), driven headless via --print, with iii_context letting it discover and operate the mesh at localhost with no exposure. Removes stale framing (thin cloud client, bare devin -- prompt, dropped session::list, v3-only wording).
@rohitg00
rohitg00 marked this pull request as ready for review July 6, 2026 17:11
rohitg00 added 2 commits July 6, 2026 18:13
Show the devin::session::create call returning a real cloud session (id, url, tags) over the bus, then the same session replying in the Devin app.
The console API_KEY field was ambiguous (service key vs legacy). Document that api_key takes a personal token (apk_, v1) or an organization service key (cog_, v3 with org_id + base_url), and that it is separate from the devin CLI's own devin auth login. Also drop a stale code-scan mention from the org_id comment.
@rohitg00
rohitg00 merged commit 4de2451 into iii-hq:main Jul 7, 2026
11 of 13 checks passed
@rohitg00
rohitg00 deleted the devin-worker branch July 7, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant