Skip to content

feat(devin): add and harden CLI provider support - #7567

Closed
Noshkasss wants to merge 61 commits into
pingdotgg:mainfrom
Noshkasss:devin-cli-hardening
Closed

feat(devin): add and harden CLI provider support#7567
Noshkasss wants to merge 61 commits into
pingdotgg:mainfrom
Noshkasss:devin-cli-hardening

Conversation

@Noshkasss

@Noshkasss Noshkasss commented Aug 19, 2026

Copy link
Copy Markdown

Summary

This PR adds Devin as a native T3 Code provider and takes #6235 as its foundation. It preserves the original commits and attribution from Rafael França and the other contributors to #6235, then adds the reliability work that was needed after exercising the provider against a real Devin CLI installation in longer, stateful sessions.

The original work in #6235 supplies the provider architecture and the integration across the server, contracts, web, mobile, marketing, usage, and documentation surfaces. The additional commits in this branch harden session startup, command delivery, authentication, model changes, context continuity, profile isolation, usage discovery, settings coverage, and live verification.

Closes #3636.

Relationship to #6235

This is a continuation of #6235 rather than an independent reimplementation. The branch contains commit 4a808ef, the latest #6235 head used for this work, with its history and authorship intact. Reviewers can therefore evaluate the original provider foundation and the later hardening commits independently.

The added work focuses on behavior that was difficult to see in a basic provider smoke test. Those cases include notifications emitted before a consumer is attached, output that arrives just after a prompt result, saved authentication being ignored on a new chat, model labels that do not match ACP protocol values, and multiple provider profiles sharing state that should be isolated.

What changed

Reliable ACP sessions and complete command delivery

Devin commands and skills are now discovered from the live ACP session and forwarded into T3 Code. Startup notifications are retained even when Devin emits them during session creation, before the adapter has finished attaching its consumer. Later command and session updates continue to flow normally.

Turn settlement now allows delayed ACP output to arrive before the turn is closed. This prevents successful commands from appearing to return nothing when the final command output lands near the prompt result. It directly hardens flows such as context inspection, compaction, status, workspace, and skills supplied by the project.

The mock ACP agent was expanded to reproduce startup notifications, delayed command output, saved authentication, model changes, and context continuity. A focused adapter integration test now exercises the command path through the same boundary used by the application.

Saved authentication without repeated browser verification

The previous flow could treat the mere presence of an advertised authentication method as a reason to authenticate immediately. That caused a new T3 Code chat to reopen Devin browser verification even when the CLI already had a valid saved login.

T3 Code now starts with the existing Devin CLI session. It invokes the advertised login method only when the first prompt specifically reports missing or expired authentication, then retries that prompt once. Unrelated prompt failures are returned normally and never trigger login. The live probe confirms that a real prompt and all model configuration changes complete without an authenticate request.

Model switching, reasoning, and context continuity

Model selection is resolved against the live ACP configuration instead of assuming that a visible model label is also the protocol value. This handles Devin reasoning variants, normalized option identifiers, opaque values such as MODEL_PRIVATE_11, and stale model selections carried over from another provider.

A model can be changed inside an existing thread without replacing the Devin session or discarding its context. The final live probe writes a conversation sentinel, switches through every model value advertised by the installed CLI, returns to the starting model, and verifies that the sentinel is still present. It also verifies that this sequence does not reopen authentication.

Complete runtime controls and isolated profiles

The provider form now exposes every Devin CLI control that changes an ACP runtime: binary path, home path, JSON config path, agent type, permission mode, process sandbox, workspace trust behavior, and additional launch arguments. Model and reasoning remain live session controls in the existing picker.

A custom Devin home is treated as a complete profile root. T3 Code derives separate XDG config, data, and cache directories from that root, while an empty home continues to respect the user’s normal CLI environment. Runtime and continuation identities include the profile, config, and agent selection so independent Devin instances do not accidentally share cached capabilities or session state.

Usage collection now scans the effective XDG data directory for the default provider and every configured Devin instance. Repeated paths are deduplicated, so configurations with multiple accounts or presets are included without double counting.

CLI coverage and documentation

The provider guide now explains how each CLI capability appears in T3 Code. Live ACP commands and project skills appear in the composer. Provider and model controls use native T3 Code surfaces. Interactive or destructive administration remains available through the integrated terminal so Devin retains its complete prompts and confirmation gates rather than being replaced by partial wrappers.

The guide also documents binary fallback behavior, launch arguments, profile isolation, authentication reuse, settings, usage, model changes, and the limits around moving an existing thread between accounts.

Why

A provider is only useful if it behaves consistently across repeated chats and longer sessions. Requiring browser verification for every chat, dropping a successful command response, or losing the selected model or context makes a technically connected provider feel unreliable in normal use.

These changes keep the architecture introduced by #6235 while closing the gaps found through real operation. The shared ACP changes are limited to startup update retention and session behavior that is covered by focused tests.

UI Changes

The provider card, icon, picker, usage presentation, and other Devin surfaces come from #6235. This hardening adds settings fields generated from the provider schema to the existing provider form and expands its tests. It does not introduce a new custom layout or animation.

Verification

The final branch passed 200 focused tests across 11 test files covering the driver, profile layout, adapter, provider registry, ACP runtime, model mapping, usage service, provider settings, and usage chart.

The optional live probe against the installed Devin CLI passed all 4 checks. It received every advertised command, completed a real prompt while reusing saved authentication, applied every advertised model configuration, and preserved conversation context after switching through every advertised model and returning to the starting model.

The server, web, and contracts packages passed their targeted type checks. The changed files passed focused lint and formatting checks, and the web application completed a production build.

To repeat the live checks, run T3_DEVIN_ACP_PROBE=1 pnpm exec vp test run apps/server/src/provider/acp/DevinAcpCliProbe.test.ts. Add T3_DEVIN_ACP_CONTEXT_PROBE=1 to include the context preservation check, which performs two real prompts.

Notes and scope

The optional context probe performs two real Devin prompts and remains disabled during normal test runs. Every other focused test uses mocks and does not consume Devin usage.

The separate macOS secure storage startup repair is intentionally excluded so this PR remains about Devin CLI provider support. Other providers are unchanged at the product surface.


Note

Medium Risk
New provider driver and ~2k-line ACP adapter touch session lifecycle, auth, and turn settlement; behavior is heavily tested but integrates with external CLI semantics.

Overview
Adds Devin as a first-class agent provider so threads can run through the Devin CLI over ACP, alongside updates to README, marketing, mobile usage charts, and provider registry tests.

The server introduces a full driver stack: binary resolution (devin / devin-desktop), XDG-based profile isolation and continuation keys, CLI health and devin models list discovery (with family/reasoning parsing and fallbacks), and a large ACP adapter that handles permissions, steering, token usage transcripts, live slash commands, and async /compact (wait for terminal chunks, cancel without hanging). ProviderProbeError is added for failed model-list probes. The mock ACP agent gains hooks for auth, startup commands, and delayed compact completion.

Mobile labels Devin in the model picker and usage UI; marketing adds Devin to the hero and harness grid.

Reviewed by Cursor Bugbot for commit 1313b81. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Devin as a built-in CLI provider with ACP runtime, adapter, and usage tracking

  • Introduces a full devin provider driver (DevinDriver.ts) with binary resolution, XDG profile isolation, environment setup, continuation grouping, and update capabilities via devin update.
  • Adds DevinAdapter and DevinAcpSupport wiring ACP session runtime to the Devin CLI: spawns devin acp, handles on-demand authentication with a single authenticate-and-retry on failure, and detects /compact as a background command with bounded 8,192-char output buffering.
  • Buffers available_commands_update and config_option_update ACP notifications received during session startup and replays them once the session is ready; merges and deduplicates slash commands, excluding native commands handled by T3 (e.g. model).
  • Adds DevinTextGeneration for commit messages, PR content, branch names, and thread titles via Devin ACP with a 180s timeout and typed JSON decoding.
  • Extends usage tracking to scan Devin transcript directories (default and per-instance), parse devin_usage JSONL lines with model slug normalization and promptIndex-based dedup, and persist entries through usageScanCache.
  • Adds DevinSettings schema (binary path, home path, config path, agent type, permission mode, sandbox, etc.) to contracts, wires settings into server and web UI, and displays Devin in provider pickers, usage charts, and the marketing page.
  • Risk: on-demand auth retry is attempted exactly once per prompt failure; a second consecutive auth failure surfaces as an error to the user.
📊 Macroscope summarized 1313b81. 43 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

rafael-franca and others added 30 commits August 11, 2026 18:57
T3 Code now supports Devin as a first-class provider alongside Codex, Claude, Cursor, Grok, and OpenCode.

Server changes add the Devin driver, ACP adapter and runtime, provider snapshot, text generation, and usage transcript support. Web and contract changes add the Devin icon, settings, model selection, and usage attribution. Docs are updated with a Devin provider guide and related internals references.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Track both last received ACP usage and last written usage separately to prevent duplicate transcript entries. Add `lastWrittenAcpUsage` to session context and only write deltas when usage increases. Capture usage from `UsageUpdated` events and merge with `PromptResponse` usage.

Normalize reasoning variant matching to handle synonyms like "no-thinking"/"none" and "lightning-medium". Add variant expansion logic and tests for
- AcpNativeLogging: never emit raw ACP frames or payload debug logs; always summarize payloads before logging.
- DevinAcpSupport: remove leftover Console.log in model selection.
- DevinAdapter: remove Effect.logInfo of the raw session/new response.
- DevinProvider: introduce ProviderProbeError and use it for devin models list failures instead of ProviderAdapterProcessError with a fabricated 'probe' threadId.
- DevinProvider.test: add missing devin-models-list.txt fixture.
- mobile: include 'devin' in usage provider labels/colors and model display labels.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- DevinProvider: parse stdout alone, fallback to stderr for text output.
- DevinDriver: derive continuation group key from resolved home path.
- DevinHome: clear inherited DEVIN_HOME and always set resolved home path.
- DevinAdapter: remove Console import/dead locals, fix usage input derivation and
  equal-total breakdown, validate prompt before model switch, fork ACP drain
  into sessionScope.
- DevinAcpSupport: reuse AcpRuntimeModel config helpers, fail on missing model
  option, handle default reasoning and reason synonyms.
- AcpSessionRuntime: keep auth method authoritative; fail when not advertised.
- usageScanCache: accept 'devin' scan-cache entries.
- ProviderModelsSection: use orderedModels index for move buttons.
- DevinProvider.test: resolve fixture from import.meta.dirname.
- Add focused tests for DevinAdapter, DevinHome, usage scan cache, and ACP auth.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The Devin adapter's getThreadSemaphore inserted one Semaphore per threadId into threadLocksRef, but stopSessionInternal and stopAll never removed the entries. This caused unbounded memory growth for long-lived adapters. Remove the threadId from the map when the session stops so the lock table does not accumulate stale entries.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The hasDetails guard in ProviderModelsSection only checked capability labels and whether the model name differs from its slug, so models with only a description never triggered the info tooltip. Include a non-empty model.description in the guard so the tooltip renders.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
deriveProviderSettingsFields now exposes binaryPath, homePath, launchArgs and permissionMode for the Devin provider, matching the schema order. Update the test expectation to match the visible fields.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add Devin Desktop as an available editor option in the OpenInPicker menu and EDITORS registry. Include DevinIcon import, register "devin-desktop" command with "goto" launch style, and reformat EDITORS array for consistency.
Add Devin logo SVG, display Devin alongside other AI tools in hero section and harness grid, update copy to include Devin in orchestration list. Adjust mobile layout to accommodate six harnesses.

Refactor DevinAdapter to use Effect.fn wrapper, replace manual record guard with Schema-based DevinResume decoder, and improve type safety for resume parsing.
Remove unused EffectAcpErrors import, add DEVIN_AUTH_METHOD_ID to imports, and apply consistent formatting across test cases. Wrap long test descriptions and mock function chains to improve readability.
… logic

Add comprehensive test coverage for makeDevinTokenUsageSnapshot and makeDevinTokenUsageSnapshotFromUsageUpdate functions. Tests verify token accumulation, context compaction handling, and edge cases like zero-size contexts.

Refactor buildThreadTokenUsageSnapshot to simplify token delta calculations, use turn-based token counting when available, and properly track totalProcessedTokens across usage updates. Export snapshot functions for testability.
- Keep per-thread lock entry while replacing sessions

- Advance lastWrittenAcpUsage only after transcript write succeeds

- Exclude cached read tokens from totalProcessedTokens

- Update snapshot test expectation

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The new provider probe error encoded failure modes only in detail prose, so callers could not recover the probe stage or CLI exit code. Add stage and exitCode fields so the error is structurally recoverable and keep the human-readable detail for messages/logs.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace string-based stage and detail fields with typed enums (ProviderProbeStage, ProviderProbeFailureKind). Generate error messages from failureKind instead of storing detail prose. Update Devin adapter to use new typed fields.
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
- Add promptIndex to Devin usage transcript records and dedup key so
  steered prompts in the same turn are counted separately.
- Prevent makeDevinTokenUsageSnapshot from shrinking totalProcessedTokens
  when PromptResponse totalTokens lags accumulated UsageUpdated events.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
rafael-franca and others added 19 commits August 17, 2026 17:37
When Devin compacts context, totalTokens can decrease. Previously this caused negative deltas and skipped usage writes. Now `isAcpUsageGreaterOrNew` returns true on any totalTokens change (including decreases), `devinUsageDeltaTotals` returns undefined for compaction events, and the usage write logic updates `lastWrittenAcpUsage` without recording a transcript line when compaction occurs.
- devinUsageDeltaTotals now computes per-field deltas and returns undefined
  only when all deltas are zero, fixing token-lag drops in totalTokens.
- sendTurn no longer updates lastWrittenAcpUsage when the delta is zero;
  it only advances the baseline after a successful transcript write.
- UsageUpdated no longer rebases lastWrittenAcpUsage to the context used
  value, preventing re-counting after context compaction.
- Wrap the ACP notification event handler body in withThreadLock to remove
  the race with sendTurn when mutating lastWrittenAcpUsage.
Wrapping the ACP notification stream in withThreadLock caused a deadlock:
prepared.acp.drainEvents emits an EventStreamBarrier and waits for its
acknowledgement while holding the per-thread permit, but the consumer
acknowledges the barrier only after acquiring the same permit. Grok and
Cursor already ack barriers outside the lock.

Keep the baseline/delta fixes from the previous commit (no lastWrittenAcpUsage
rebase on UsageUpdated, per-field deltas, no baseline advance when no delta is
written) and restore the notification handler to run without the lock.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The empty state appeared when no search was active, so it now renders only while filtering.
…ings

Always override inherited Devin permission mode with the configured setting.\nInclude deduplicated provider-instance Devin homes in usage transcript scans.
Normalize Devin reasoning option ids before matching underscored configuration identifiers.
Cover startup notifications, delayed command output, authentication reuse, model changes, and context continuity in the shared mock agent.
Add typed settings for Devin profiles, config files, agent modes, process sandboxing, workspace trust, permission modes, and custom launch arguments.
Resolve the real XDG profile used by Devin, keep provider instances isolated, and pass config, agent, sandbox, trust, permission, and launch options to the CLI.
Keep startup updates, reuse existing authentication, retry only genuine login failures, preserve context, expose live commands, and resolve visible model names to the opaque values used by Devin ACP.
Forward live ACP commands and session updates, retain asynchronous output through turn settlement, add focused adapter integration coverage, and remove an accidental duplicate upload.
Read usage from the active XDG data directory for the default provider and every configured Devin instance, while deduplicating repeated paths.
Verify every Devin CLI runtime field, default, selectable value, and usage chart provider fixture.
Document profiles, runtime controls, saved login reuse, live commands, model selection, context behavior, and usage collection in plain language.
Model startup notifications, delayed command output, saved authentication, model changes, and context continuity in the mock ACP agent.
Run the live ACP probe on the live clock, switch through every model advertised by the installed CLI, and prove the original conversation state remains after returning to the starting model.
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b834af27-2f43-4ef3-a19e-7bc656870bec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 19, 2026
Comment on lines +973 to +980
const DevinSettingsPatch = Schema.Struct({
enabled: Schema.optionalKey(Schema.Boolean),
binaryPath: Schema.optionalKey(TrimmedString),
homePath: Schema.optionalKey(TrimmedString),
launchArgs: Schema.optionalKey(TrimmedString),
permissionMode: Schema.optionalKey(DevinPermissionMode),
customModels: Schema.optionalKey(Schema.Array(Schema.String)),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High src/settings.ts:973

ServerSettingsPatch rejects configPath, agentType, sandbox, and respectWorkspaceTrust, so updates to these Devin controls are dropped before they reach providers.devin and the runtime keeps its defaults. Add the four fields to DevinSettingsPatch to match DevinSettings.

Suggested change
const DevinSettingsPatch = Schema.Struct({
enabled: Schema.optionalKey(Schema.Boolean),
binaryPath: Schema.optionalKey(TrimmedString),
homePath: Schema.optionalKey(TrimmedString),
launchArgs: Schema.optionalKey(TrimmedString),
permissionMode: Schema.optionalKey(DevinPermissionMode),
customModels: Schema.optionalKey(Schema.Array(Schema.String)),
});
const DevinSettingsPatch = Schema.Struct({
enabled: Schema.optionalKey(Schema.Boolean),
binaryPath: Schema.optionalKey(TrimmedString),
homePath: Schema.optionalKey(TrimmedString),
configPath: Schema.optionalKey(TrimmedString),
agentType: Schema.optionalKey(DevinAgentType),
launchArgs: Schema.optionalKey(TrimmedString),
permissionMode: Schema.optionalKey(DevinPermissionMode),
sandbox: Schema.optionalKey(Schema.Boolean),
respectWorkspaceTrust: Schema.optionalKey(Schema.Boolean),
customModels: Schema.optionalKey(Schema.Array(Schema.String)),
});
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/contracts/src/settings.ts around lines 973-980:

`ServerSettingsPatch` rejects `configPath`, `agentType`, `sandbox`, and `respectWorkspaceTrust`, so updates to these Devin controls are dropped before they reach `providers.devin` and the runtime keeps its defaults. Add the four fields to `DevinSettingsPatch` to match `DevinSettings`.

Comment on lines +28 to +30
An empty `Home path` means T3 Code uses Devin's default home directory (`~/.devin` on macOS and
Linux, and the equivalent Windows user profile path). T3 Code sets this as `DEVIN_HOME` when it
spawns the Devin process.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Low user/providers-devin.md:28

The default-profile instructions tell users that an empty Home path uses ~/.devin and sets DEVIN_HOME, but T3 Code actually preserves the normal XDG-based Devin profile and leaves DEVIN_HOME unset. Users following this guide will inspect or back up the wrong directory and may misunderstand which existing login/state the provider reuses; please document the actual behavior here.

Suggested change
An empty `Home path` means T3 Code uses Devin's default home directory (`~/.devin` on macOS and
Linux, and the equivalent Windows user profile path). T3 Code sets this as `DEVIN_HOME` when it
spawns the Devin process.
An empty `Home path` leaves Devin's normal XDG-based profile unchanged; T3 Code does not set `DEVIN_HOME` for the default provider.
🤖 Copy this AI Prompt to have your agent fix this:
In file @docs/user/providers-devin.md around lines 28-30:

The default-profile instructions tell users that an empty `Home path` uses `~/.devin` and sets `DEVIN_HOME`, but T3 Code actually preserves the normal XDG-based Devin profile and leaves `DEVIN_HOME` unset. Users following this guide will inspect or back up the wrong directory and may misunderstand which existing login/state the provider reuses; please document the actual behavior here.

Profile path: empty
Config file: empty
Agent type: Default coding agent
Permission mode: Auto (read-only)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Low user/providers-devin.md:22

The default settings example shows Permission mode: Auto (read-only), but T3 Code actually defaults to and labels this field Normal. Users copying this supposedly default configuration will see a conflicting value; update the example to match the schema and the normal default described below.

Suggested change
Permission mode: Auto (read-only)
Permission mode: Normal
🤖 Copy this AI Prompt to have your agent fix this:
In file @docs/user/providers-devin.md around line 22:

The default settings example shows `Permission mode: Auto (read-only)`, but T3 Code actually defaults to and labels this field `Normal`. Users copying this supposedly default configuration will see a conflicting value; update the example to match the schema and the `normal` default described below.

if (suffix === undefined && variant.label === undefined) {
continue;
}
const label = buildDevinVariantOptionLabel(variant.label, familyName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/DevinProvider.ts:301

Unlabeled variants are emitted with the same { id: "default", label: "Default" }, so claude-opus-5-medium and claude-opus-5-high cannot be represented or selected separately in the picker. Although suffix is resolved above, it is discarded when variant.label is absent; use that suffix as the fallback label, while an empty suffix should continue to produce Default.

-    const label = buildDevinVariantOptionLabel(variant.label, familyName);
+    const label = buildDevinVariantOptionLabel(variant.label ?? suffix, familyName);
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/DevinProvider.ts around line 301:

Unlabeled variants are emitted with the same `{ id: "default", label: "Default" }`, so `claude-opus-5-medium` and `claude-opus-5-high` cannot be represented or selected separately in the picker. Although `suffix` is resolved above, it is discarded when `variant.label` is absent; use that suffix as the fallback label, while an empty suffix should continue to produce `Default`.

if (!configPath && agentType === "default") {
return undefined;
}
return `${configPath ? expandHomePath(configPath) : ""}\0${agentType}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High Drivers/DevinHome.ts:129

makeDevinRuntimeIdentity gives every relative configPath the same identity regardless of session cwd, so instances using configPath: "devin.json" can load different account/config files while sharing a continuation group. Include the effective cwd when resolving this path, or require an absolute configPath before constructing the identity.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/DevinHome.ts around line 129:

`makeDevinRuntimeIdentity` gives every relative `configPath` the same identity regardless of session `cwd`, so instances using `configPath: "devin.json"` can load different account/config files while sharing a continuation group. Include the effective `cwd` when resolving this path, or require an absolute `configPath` before constructing the identity.

): boolean {
return (
notification.update.sessionUpdate === "available_commands_update" ||
notification.update.sessionUpdate === "config_option_update"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High acp/AcpSessionRuntime.ts:282

Retained config_option_update notifications are published but do not update configOptionsRef, so after startup getConfigOptions, config validation, duplicate detection, and model selection continue using the stale setup options. The buffered notifications are replayed through projectSessionUpdate/handleSessionUpdate, which only emits ConfigOptionsChanged; apply each retained config update to the runtime snapshot before completing startup.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/acp/AcpSessionRuntime.ts around line 282:

Retained `config_option_update` notifications are published but do not update `configOptionsRef`, so after startup `getConfigOptions`, config validation, duplicate detection, and model selection continue using the stale setup options. The buffered notifications are replayed through `projectSessionUpdate`/`handleSessionUpdate`, which only emits `ConfigOptionsChanged`; apply each retained config update to the runtime snapshot before completing startup.

const previousUsedTokens = input.previous?.usedTokens ?? 0;
const previousTotalProcessed = input.previous?.totalProcessedTokens ?? 0;

const maxTokens =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/DevinAdapter.ts:504

buildThreadTokenUsageSnapshot removes the previously known maxTokens from the returned snapshot when a later Devin update omits it or reports 0, so subsequent thread.token-usage.updated events lose the context-window limit. Preserve input.previous.maxTokens when the new value is not positive, as makeDevinTokenUsageSnapshot does.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/DevinAdapter.ts around line 504:

`buildThreadTokenUsageSnapshot` removes the previously known `maxTokens` from the returned snapshot when a later Devin update omits it or reports `0`, so subsequent `thread.token-usage.updated` events lose the context-window limit. Preserve `input.previous.maxTokens` when the new value is not positive, as `makeDevinTokenUsageSnapshot` does.


for (const instance of Object.values(settings.providerInstances)) {
if (instance.driver !== "devin") continue;
const dir = yield* resolveDevinUsageTranscriptDirectory(toDevinHomeConfig(instance.config));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium usage/UsageService.ts:115

Devin instance usage is omitted when homePath is empty and the instance sets an XDG_DATA_HOME, because this call resolves against the server process environment instead of instance.environment. Merge the instance environment into the base environment passed to resolveDevinUsageTranscriptDirectory.

-      const dir = yield* resolveDevinUsageTranscriptDirectory(toDevinHomeConfig(instance.config));
+      const dir = yield* resolveDevinUsageTranscriptDirectory(toDevinHomeConfig(instance.config), {
+        ...process.env,
+        ...instance.environment,
+      });
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/usage/UsageService.ts around line 115:

Devin instance usage is omitted when `homePath` is empty and the instance sets an `XDG_DATA_HOME`, because this call resolves against the server process environment instead of `instance.environment`. Merge the instance environment into the base environment passed to `resolveDevinUsageTranscriptDirectory`.

.harness-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-columns: repeat(6, 1fr);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium pages/index.astro:842

At viewports just above the 960px responsive breakpoint, six columns leave each .harness card only about 68px of content width, so tags such as devin auth login are clipped by the grid's overflow: hidden. Use fewer desktop columns or move the two-column breakpoint higher.

Suggested change
grid-template-columns: repeat(6, 1fr);
grid-template-columns: repeat(5, 1fr);
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/marketing/src/pages/index.astro around line 842:

At viewports just above the `960px` responsive breakpoint, six columns leave each `.harness` card only about `68px` of content width, so tags such as `devin auth login` are clipped by the grid's `overflow: hidden`. Use fewer desktop columns or move the two-column breakpoint higher.

const fileSystem = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const processEnv = mergeProviderInstanceEnvironment(environment);
const continuationGroupKey = yield* makeDevinContinuationGroupKey(config);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High Drivers/DevinDriver.ts:106

Instances with an empty homePath and per-instance HOME or XDG_* overrides receive a continuationKey derived from the server environment, so distinct Devin profiles can share continuation state across accounts. makeDevinContinuationGroupKey must use the same merged environment passed to makeDevinEnvironment.

Suggested change
const continuationGroupKey = yield* makeDevinContinuationGroupKey(config);
const continuationGroupKey = yield* makeDevinContinuationGroupKey(config, processEnv);
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/DevinDriver.ts around line 106:

Instances with an empty `homePath` and per-instance `HOME` or `XDG_*` overrides receive a `continuationKey` derived from the server environment, so distinct Devin profiles can share continuation state across accounts. `makeDevinContinuationGroupKey` must use the same merged environment passed to `makeDevinEnvironment`.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the new Devin provider code against the Effect service conventions. One finding: the new ACP runtime factory takes the ChildProcessSpawner service instance as a parameter and re-provides it with Layer.succeed instead of declaring it as an environment requirement. Everything else (error definitions in provider/Errors.ts, make/driver construction in Drivers/DevinDriver.ts, namespace imports, Effect.catchTags usage in DevinTextGeneration.ts) matches the conventions.

Posted via Macroscope — Effect Service Conventions

AcpSessionRuntime.AcpSessionRuntimeOptions,
"authMethodId" | "authenticationMode" | "clientCapabilities" | "isAuthenticationFailure" | "spawn"
> {
readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

makeDevinAcpRuntime receives the ChildProcessSpawner service instance as a value and then re-provides it via Layer.succeed(...) (line 127), so the dependency never appears in the factory's R channel (currently only Crypto.Crypto | Scope.Scope). Consider dropping childProcessSpawner from DevinAcpRuntimeInput and acquiring it inside the generator instead (const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner), letting the requirement propagate to callers. makeDevinAdapter/startSession and makeDevinTextGeneration already resolve the spawner from the environment and can provide it the same way they provide Crypto.Crypto, or simply let it flow through.

Posted via Macroscope — Effect Service Conventions

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1313b81. Configure here.

familySlug,
reasoningValue: getConfigOptionCurrentValue(configOptions, reasoningConfigId),
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ACP model IDs treated as family slugs

Medium Severity

currentDevinAcpModelSelection stores the live ACP currentValue as familySlug. That value is often a protocol id such as claude-opus-5-medium or MODEL_PRIVATE_11, not the picker family slug. ConfigOptionsChanged then copies it onto session.model and currentModelId, so the UI selection and later comparisons no longer match advertised family slugs after Devin echoes config.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1313b81. Configure here.

@macroscopeapp

macroscopeapp Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Skipped

Macroscope did not run approvability analysis for this PR. Diff is too large for automated approval analysis, so this PR cannot be approved automatically.

Not approved because:

  • 8 blocking correctness issues found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@t3-code t3-code Bot mentioned this pull request Aug 20, 2026
4 tasks
@t3dotgg

t3dotgg commented Aug 23, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Outside Devin integration that duplicates another large outside provider proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add Devin CLI support

3 participants