Files
OmniRoute/docs/DEVIN_CLAUDE_BRIDGE.md
Diego Rodrigues de Sa e Souza f51cd295c8 chore(providers): bump Claude Code wire identity + Devin bridge pin to 2.1.258 (#12604)
17 de 18 checks verdes, **zero falhas** — incluindo os quatro shards de unit, Vitest, CodeQL, semgrep, Docs Gates, Merge integrity e o **Fast Quality Gates**, que era exatamente o que o rebaseline do `RoutingTab.tsx` (1606→1607, a linha do seletor que acompanha a nova versão de identidade) veio consertar.

O único check restante, `No new ESLint warnings`, ficou enfileirado sem iniciar (duração 0) atrás da saturação de runners de hoje. Cobri os dois comandos que ele executa, localmente e sobre este HEAD:

- `npm run check:codeql-ratchet` → **0 alertas abertos** contra baseline 6 (sem regressão).
- `npx eslint --max-warnings 0` nos 9 arquivos de código que esta branch altera → **exit 0**, nenhum warning.

Conteúdo: os dois commits do #12402 que não estavam subsumidos, com autoria do @ggiak preservada pelo cherry-pick `-x`, mais o rebaseline e o fragmento de changelog que faltava. `typecheck:core` limpo e **138/138** nos testes focados. As três versões (`claudeCodeClient.ts`, `Dockerfile`, `compose.yml`) conferem em 2.1.258, e `npm view @anthropic-ai/claude-code@2.1.258` resolve — o Dockerfile instala esse pin exato.
2026-09-03 13:49:46 -03:00

8.0 KiB

Devin Claude Bridge

devin-cli-agentic lets the real Claude Code runtime use OmniRoute's local Anthropic Messages endpoint while the official Devin CLI supplies model responses over ACP stdio. It does not modify the existing Anthropic, Claude OAuth, Claude Web, or devin-cli providers.

Current status: pinned Claude Code 2.1.258; offline and live validation last recorded on 2.1.220. The 2.1.220 pin completed three isolated scenarios through Devin CLI 3000.2.17 and model swe-1-7-lightning; that final live run proved client-owned Read, Edit, and Bash turns, successful npm test results, project command and skill discovery, Devin-only routing, and zero Claude egress. The pin was then raised to 2.1.258 (the CLI generation OmniRoute's Claude identity impersonates, and the first line that ships the Fable 5.1 tier natively). On the new pin the install layer and claude --version were verified on the pinned base image, and the bridge unit suite, compose config and the static isolation proof pass — but the offline mock scenario and the live three-scenario suite have not been re-run yet. Re-run them (see "Updating pinned tools") before relying on the bridge with this pin.

Architecture

Claude Code 2.1.258 (isolated non-root Linux container)
  -> http://omniroute:20128/v1/messages
  -> devin-cli-agentic (Claude-format, no-auth provider)
  -> devin acp --agent-type summarizer (official ACP stdio, no Devin tools)
  -> Devin account in the dedicated devin-auth volume

The official CLI's default ACP agent can execute its own tools, so this bridge does not use it. It starts the fixed summarizer ACP agent, whose official CLI mode has no tools, and frames the serialized Anthropic request as an execution trace. When another Claude-owned action is needed, the response must contain exactly one client tool envelope. Any ACP tool_call or tool_call_update is rejected before a response can be reported as successful.

The serializer in open-sse/executors/devin-agentic/serializer.ts preserves system, text, tool_use, tool_result, thinking, redacted_thinking, tool_choice, and the tools supplied by Claude Code. Images and unknown blocks fail explicitly. Large tool results use a visible truncation marker.

The parser accepts one standalone <tool>{...}</tool> envelope per model turn. It checks the name against the request's tool list, validates arguments against that tool's JSON Schema, rejects mixed narrative/actions, and permits one bounded repair. Claude Code then executes the resulting Anthropic tool_use locally and sends the tool_result back through OmniRoute.

Isolation and threat model

The host's Claude installation, account, and configuration are out of scope and treated as forbidden. The Compose services:

  • run as UID/GID 10001:10001, with a read-only root filesystem, dropped capabilities, and no-new-privileges;
  • use a private /home/bridge, a dedicated Claude config volume, isolated OmniRoute data, and a separate devin-auth volume;
  • mount only disposable .sandbox workspaces/evidence;
  • do not mount the host home, Keychain, SSH, cloud credentials, or Docker socket;
  • construct explicit environments and remove Anthropic API/OAuth/routing variables;
  • direct Claude Code inference only to http://omniroute:20128 with a local-only key.

The offline profile uses an internal network. In the live profile, OmniRoute reaches the official Devin endpoints only through network-guard; unrelated destinations are denied. Claude Code has a separate deny-all egress guard and can reach only the local OmniRoute service through NO_PROXY. Guard audit files are mounted only by their guard process. The scripts verify file ownership, mode, link count, and every decision before exporting token-free evidence.

Run the isolation proof independently:

./scripts/devin-bridge/verify-anthropic-isolation

It validates topology, named mounts, non-root/read-only settings, explicit local routing, absence of sensitive environment variables, absence of the Docker socket, blocked access to api.anthropic.com and claude.ai, Devin-only provider selection, and explicit failure when the ACP backend is unavailable.

First-time setup and normal use

Build the pinned image:

./scripts/devin-bridge/build

Authenticate only the isolated Devin volume:

ENABLE_LIVE_DEVIN_TESTS=1 ./scripts/devin-bridge/login-devin

The login command uses the official manual-token flow intended for remote/container environments. The value is entered directly into the CLI prompt; it is not passed as a process argument, written to Git, or copied from the host.

Launch the isolated Claude Code runtime:

./scripts/devin-bridge/launch

launch rechecks isolation, Devin authentication, and model discovery before starting the containerized Claude Code. It never runs the host's Claude executable. Model aliases can be set in .env.devin-bridge; every configured value must keep the devin-cli-agentic/ prefix.

Validation commands

The reproducible offline path requires no Devin account and has no runtime Internet:

./scripts/devin-bridge/test-unit
./scripts/devin-bridge/test-contract
./scripts/devin-bridge/test-e2e-mock
./scripts/devin-bridge/verify-anthropic-isolation

The authenticated opt-in live path is:

ENABLE_LIVE_DEVIN_TESTS=1 ./scripts/devin-bridge/test-live-devin

The live runner waits between scenarios to avoid opening ACP sessions in a burst and validates structured Claude stream events instead of trusting textual claims. Its three scenarios prove:

  1. direct project reads and defect analysis;
  2. a real Edit, a client-owned Bash npm test, and a terminal result;
  3. /bridge-check plus bridge-proof discovery, project reads, another successful client-owned npm test, and completion without pending work.

The final gate also checks the Devin network audit and requires the Claude egress audit to remain empty.

Updating pinned tools

The image pins Node, Claude Code, and Devin CLI in docker/devin-bridge/Dockerfile. To update:

  1. change the explicit versions;
  2. replace both architecture-specific Devin archive checksums with values for the official artifact;
  3. rebuild and run every offline validation command;
  4. confirm the versions inside the image;
  5. rerun the authenticated three-scenario live suite.

Do not install either CLI globally on the host or replace checksum verification with an unverified download.

Diagnosis and cleanup

  • docker compose -f docker/devin-bridge/compose.yml --profile offline logs omniroute shows local routing and sanitized executor errors.
  • .sandbox/evidence/mock-acp.jsonl records deterministic mock ACP actions.
  • .sandbox/evidence/claude-stream.jsonl records the real Claude Code offline run.
  • .sandbox/evidence/live-*.jsonl records the three validated live streams.
  • .sandbox/evidence/egress.jsonl and .sandbox/evidence/claude-egress.jsonl are validated, token-free copies of the guard audits.

Stop owned containers and networks while preserving login/config volumes:

./scripts/devin-bridge/clean

Remove the complete bridge-owned environment, including named volumes:

./scripts/devin-bridge/clean --all

Limits

  • The bridge relies on the fixed no-tools summarizer role because Devin CLI 3000.2.17 does not expose a neutral no-tools ACP agent. The adapter compensates for summary-shaped intermediate responses, but one bounded repair can still fail explicitly.
  • Live ACP calls can return transient 502/504 responses. The harness spaces scenarios; persistent failure remains fail-closed and never selects another provider.
  • ACP context is reconstructed from each Anthropic request; there is no process/session affinity.
  • One tool call is supported per model response; parallel calls are rejected.
  • Images are explicitly unsupported. Vision, thinking output, effort controls, and a 1M context window are not advertised.
  • SSE uses valid Anthropic lifecycle events but is emitted after the bounded ACP turn is collected; ACP chunks are not forwarded incrementally.