# How to Integrate Cloud Agents (Devin, Codex Cloud, Jules) with OmniRoute

> Learn how to integrate cloud agents like Devin, Codex Cloud, and Jules with OmniRoute. Our unified API makes registering, authenticating, and calling agents seamless. Get started today!

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-11

---

**OmniRoute treats cloud agents like Devin, Codex Cloud, and Jules as first-class components that you can register, authenticate, and call through a unified API layer.**

The `diegosouzapw/OmniRoute` repository provides a **cloud-agent abstraction layer** in `src/lib/cloudAgent/` that standardizes how external AI agents are discovered, secured, and invoked. This guide walks through the three-step integration pattern using Codex Cloud as the reference implementation.

## The Three-Step Integration Pattern

OmniRoute's cloud-agent architecture follows a consistent registration-credential-execution flow. Each step maps to specific source files in the codebase.

### Step 1: Register the Agent in the Central Registry

OmniRoute discovers agents at runtime through a class-based registry. In [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts), the system iterates over `src/lib/cloudAgent/agents/*` and maps agent names to their implementing classes.

The registry is a simple `Map<string, typeof CloudAgentBase>` that the request router consults via [`open-sse/handlers/agentHandler.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/agentHandler.ts).

```typescript
// src/lib/cloudAgent/registry.ts
import { CodexCloudAgent } from '@/lib/cloudAgent/agents/codex';
import { DevinAgent } from '@/lib/cloudAgent/agents/devin';
import { JulesAgent } from '@/lib/cloudAgent/agents/jules';

// Register under canonical names
cloudAgentRegistry.set('codex', CodexCloudAgent);
cloudAgentRegistry.set('devin', DevinAgent);
cloudAgentRegistry.set('jules', JulesAgent);

```

Any class registered here must extend `CloudAgentBase` and implement five abstract methods: `createTask`, `getStatus`, `approvePlan`, `sendMessage`, and `listSources`.

### Step 2: Configure Credentials via the Public-Creds System

Cloud agents require OAuth credentials or API keys that must **never be hard-coded**. OmniRoute enforces this through the `resolvePublicCred()` helper in [`open-sse/utils/publicCreds.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/publicCreds.ts).

The Codex Cloud agent constructor in [`src/lib/cloudAgent/agents/codex.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/agents/codex.ts) retrieves its credentials through this abstraction:

```typescript
// Agent internals automatically call:
const clientId = await resolvePublicCred('PUBLIC_CLOUD_CODEX_CLIENT_ID');
const clientSecret = await resolvePublicCred('PUBLIC_CLOUD_CODEX_CLIENT_SECRET');

```

Set these in your environment:

```bash

# .env (never commit this file)

PUBLIC_CLOUD_CODEX_CLIENT_ID=your-client-id
PUBLIC_CLOUD_CODEX_CLIENT_SECRET=your-client-secret
PUBLIC_CLOUD_DEVIN_API_KEY=your-devin-key
PUBLIC_CLOUD_JULES_API_KEY=your-jules-key

```

This satisfies OmniRoute's **hard rule #11**: *Never embed public upstream credentials in source code*.

### Step 3: Call the Agent via HTTP API or SDK

OmniRoute auto-generates REST endpoints for each registered agent at `src/app/api/v1/agents/[agent]/route.ts`. The request pipeline runs CORS handling → Zod validation → optional authentication → agent delegation. Errors are sanitized via `buildErrorBody()` per **hard rule #12**.

#### HTTP API Example (Codex Cloud)

```typescript
// Create a task
const createResponse = await fetch('http://localhost:20128/v1/agents/codex/tasks', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    prompt: 'Refactor this Python class to use dataclasses',
    model: 'codex-latest',
    temperature: 0.2
  })
});

const { taskId, status } = await createResponse.json();

// Poll until completion
while (!['completed', 'failed'].includes(status)) {
  await new Promise(r => setTimeout(r, 2000));
  const poll = await fetch(`http://localhost:20128/v1/agents/codex/tasks/${taskId}`);
  ({ status } = await poll.json());
}

// Retrieve messages
const messages = await fetch(
  `http://localhost:20128/v1/agents/codex/tasks/${taskId}/messages`
).then(r => r.json());

```

#### SDK Client Alternative

For programmatic use, import the typed client from [`src/lib/cloudAgent/sdk.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/sdk.ts):

```typescript
import { CloudAgentClient } from '@/lib/cloudAgent/sdk';

const client = new CloudAgentClient({ baseUrl: 'http://localhost:20128' });

// Fire-and-forget with auto-polling
const result = await client.runToCompletion('devin', {
  prompt: 'Create a React component for a date picker',
  context: { repository: 'github.com/acme/app' }
});

console.log(result.output);

```

## Key Architectural Components

| Component | Location | Purpose |
|-----------|----------|---------|
| **Agent base class** | [`src/lib/cloudAgent/CloudAgentBase.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/CloudAgentBase.ts) | Abstract interface all agents must implement |
| **Registry** | [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts) | Runtime discovery and name-to-class mapping |
| **Codex implementation** | [`src/lib/cloudAgent/agents/codex.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/agents/codex.ts) | OAuth flow, task lifecycle, message streaming |
| **Auto-generated routes** | `src/app/api/v1/agents/[agent]/route.ts` | HTTP entry point per registered agent |
| **SDK client** | [`src/lib/cloudAgent/sdk.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/sdk.ts) | TypeScript client for programmatic access |
| **Error sanitization** | [`open-sse/utils/buildErrorBody.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/buildErrorBody.ts) | Security-compliant error responses |

## Adding a New Cloud Agent

To integrate additional agents (e.g., a custom enterprise agent), follow the same pattern established for Codex Cloud, Devin, and Jules:

1. **Create agent file**: Add [`src/lib/cloudAgent/agents/youragent.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/agents/youragent.ts) extending `CloudAgentBase`
2. **Implement required methods**: `createTask`, `getStatus`, `approvePlan`, `sendMessage`, `listSources`
3. **Register**: Add `cloudAgentRegistry.set('youragent', YourAgentClass)` in [`registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/registry.ts)
4. **Configure credentials**: Add `PUBLIC_CLOUD_YOURAGENT_*` variables to your environment

No other files require modification—the routing and validation layers are fully generic.

## Summary

- **Registration**: Add agent classes to [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts) for runtime discovery
- **Security**: Store all credentials externally via `resolvePublicCred()` to satisfy hard rule #11
- **Execution**: Use auto-generated HTTP endpoints at `/v1/agents/{agent}/` or the `CloudAgentClient` SDK
- **Extensibility**: New agents require only a single source file and one registry line
- **Standards**: All agents implement `CloudAgentBase`, ensuring consistent task lifecycle semantics

## Frequently Asked Questions

### What authentication methods does OmniRoute support for cloud agent credentials?

OmniRoute's `resolvePublicCred()` system supports environment variables, secret managers (via pluggable backends), and local `.env` files. The [`open-sse/utils/publicCreds.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/publicCreds.ts) module abstracts the source so agent implementations remain environment-agnostic. OAuth client credentials and API keys are both supported—each agent class specifies its required credential keys in the constructor.

### How does OmniRoute handle rate limiting and errors from external agent APIs?

Each agent implementation in `src/lib/cloudAgent/agents/*.ts` wraps upstream API calls with retry logic and exponential back-off. Errors are normalized through `buildErrorBody()` in [`open-sse/utils/buildErrorBody.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/buildErrorBody.ts), which strips sensitive details before returning them to clients. The HTTP layer returns standard status codes (429 for rate limits, 502/503 for upstream failures) with sanitized error messages.

### Can I use multiple cloud agents in a single OmniRoute deployment?

Yes. The registry in [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts) holds multiple agents simultaneously. Each registered name gets its own route handler under `/v1/agents/{name}/`. You can call Codex Cloud, Devin, and Jules from the same running OmniRoute instance, with credentials isolated per agent.

### Is there a way to stream agent responses instead of polling?

The base interface in [`CloudAgentBase.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/CloudAgentBase.ts) includes `sendMessage()` which supports streaming implementations. Check individual agent files—[`src/lib/cloudAgent/agents/codex.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/agents/codex.ts) implements Server-Sent Events (SSE) for real-time output, while others may return complete responses. The SDK's `client.streamTask()` method provides a unified async iterator interface regardless of the underlying transport.