# How to Integrate Cloud Agents Like Codex Cloud with OmniRoute's ACP Registry

> Learn to integrate cloud agents like Codex Cloud with OmniRoute's ACP registry for consistent CLI access. Explore HTTP proxy and ACP path support.

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

---

**OmniRoute supports both HTTP proxy and ACP (Agent Client Protocol) paths, allowing cloud agents like Codex Cloud to be registered and exposed through the ACP registry for consistent CLI-based access.**

Integrating cloud-based LLM providers into OmniRoute's ACP ecosystem requires bridging HTTP-based APIs with the local agent protocol. This guide walks through registering Codex Cloud as a first-class ACP participant using the dual-registry architecture found in `diegosouzapw/OmniRoute`.

## Understanding OmniRoute's Dual-Provider Architecture

OmniRoute offers two complementary methods for reaching LLM providers:

- **HTTP proxy** — Standard request/response via the provider's REST API
- **ACP (Agent Client Protocol)** — Spawns a locally-installed CLI agent (stdio or HTTP) and routes requests through that process

Cloud agents like **Codex Cloud** are HTTP-based providers by nature, but the ACP registry allows OmniRoute to treat them like any other CLI agent. This enables auto-detection, session management, and unified request routing.

## Step 1: Implement the Cloud Agent Class

Every cloud agent requires a class that extends `CloudAgentBase`. This class handles task creation, status polling, and follow-up messaging.

The reference implementation lives in [`src/lib/cloudAgent/agents/codex.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/agents/codex.ts). The `CodexCloudAgent` class implements:

- `createTask()` — Initialize a new conversation task
- `pollStatus()` — Check completion state
- `sendMessage()` — Stream or return responses

```typescript
// src/lib/cloudAgent/agents/codex.ts
// CodexCloudAgent extends CloudAgentBase
// Implements HTTP-based task lifecycle management

```

## Step 2: Register in the Cloud-Agent Registry

The cloud-agent registry maps provider IDs to concrete implementations. Open [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts) and add your agent to the exported registry object:

```typescript
// src/lib/cloudAgent/registry.ts
export const cloudAgentRegistry = {
  "codex-cloud": new CodexCloudAgent(),
  // … other agents
};

```

The key `"codex-cloud"` becomes the canonical provider identifier used throughout the request pipeline.

## Step 3: Expose Through the ACP Registry

The ACP registry ([`src/lib/acp/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/acp/registry.ts)) defines CLI agents that `AcpManager` can spawn. Each entry requires a `providerAlias` that bridges to the cloud-agent registry.

Add this definition to `AGENT_DEFINITIONS`:

```typescript
// src/lib/acp/registry.ts
{
  id: "codex-cloud",
  name: "Codex Cloud CLI",
  binary: "codex-cloud",               // must exist on $PATH
  versionCommand: "codex-cloud --version",
  providerAlias: "codex-cloud",        // ↔ cloudAgentRegistry key
  spawnArgs: ["--quiet"],
  protocol: "stdio",
}

```

When `AcpManager.detectInstalledAgents()` runs, it executes `versionCommand` to verify availability. Upon success, the agent appears in `getAvailableAgents()`.

## Step 4: Create the CLI Wrapper

The `binary` field references a local executable that translates ACP messages to HTTP calls. This thin wrapper:

- Reads JSON payloads from stdin (ACP protocol)
- Forwards to `CodexCloudAgent` methods
- Returns responses in ACP-compliant format

The expected payload schema is defined in [`src/lib/acp/manager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/acp/manager.ts). Your wrapper must handle:

- `initialize` — Session setup
- `chat/completions` — Core inference requests
- `terminate` — Cleanup

## Step 5: Verify Provider Alias Wiring

The `providerAlias` field creates the critical link between registries. When a request arrives with `providerId: "codex-cloud"`:

1. The request pipeline (`open-sse/handlers/*`) resolves the ID
2. If ACP path is selected, `AcpManager` looks up the definition
3. `providerAlias` retrieves the `CodexCloudAgent` instance from `cloudAgentRegistry`
4. HTTP requests flow through the cloud agent while ACP manages the local process

**Mismatched aliases break the chain.** Ensure exact string equality between `providerAlias` in [`src/lib/acp/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/acp/registry.ts) and the key in [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts).

## Complete Integration Example

```typescript
// 1. Cloud agent implementation (src/lib/cloudAgent/agents/codex.ts)
import { CloudAgentBase } from "../base";

export class CodexCloudAgent extends CloudAgentBase {
  async createTask(params: TaskParams): Promise<TaskId> {
    const response = await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: { Authorization: `Bearer ${this.apiKey}` },
      body: JSON.stringify(params),
    });
    return response.json().then(r => r.id);
  }
  // … pollStatus, sendMessage implementations
}

// 2. Cloud registry entry (src/lib/cloudAgent/registry.ts)
export const cloudAgentRegistry = {
  "codex-cloud": new CodexCloudAgent(),
};

// 3. ACP registry entry (src/lib/acp/registry.ts)
export const AGENT_DEFINITIONS = [
  {
    id: "codex-cloud",
    name: "Codex Cloud CLI",
    binary: "codex-cloud",
    versionCommand: "codex-cloud --version",
    providerAlias: "codex-cloud",
    spawnArgs: ["--quiet"],
    protocol: "stdio",
  },
];

// 4. Runtime usage
import { acpManager } from "@/lib/acp";

const session = await acpManager.acquireSession("codex-cloud");
const response = await session.send({
  model: "codex",
  messages: [{ role: "user", content: "Write a hello-world function in Python." }],
});
console.log(response);

```

## Runtime Customization

Custom agents can be added without modifying source files. The registry exposes `setCustomAgents()` (lines 88-91 in [`src/lib/acp/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/acp/registry.ts)) for dynamic registration:

```typescript
import { setCustomAgents } from "@/lib/acp/registry";

setCustomAgents([
  {
    id: "my-custom-cloud",
    name: "My Cloud Agent",
    binary: "my-cloud-cli",
    versionCommand: "my-cloud-cli --version",
    providerAlias: "my-custom-provider",
    protocol: "stdio",
  },
]);

```

These persist through the settings database and merge with built-in definitions.

## Testing Your Integration

Validate the full stack with a unit test that exercises:

1. Registry registration
2. ACP session acquisition
3. Message routing to the cloud agent

```typescript
test("Codex Cloud ACP integration", async () => {
  const agent = (await detectInstalledAgents()).find(a => a.id === "codex-cloud");
  expect(agent).toBeDefined();

  const session = await acpManager.acquireSession("codex-cloud");
  const response = await session.send({ model: "codex", messages: [] });
  expect(response).toHaveProperty("choices");
});

```

## Summary

- **Dual registry system**: Cloud agents live in [`cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/cloudAgent/registry.ts); ACP definitions in [`acp/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/acp/registry.ts)
- **Provider alias bridges**: The `providerAlias` field must exactly match the cloud-agent registry key
- **CLI wrapper required**: Cloud agents need a local executable implementing the ACP protocol
- **Auto-detection**: `AcpManager` validates binaries via `versionCommand` before listing as available
- **Dynamic extension**: `setCustomAgents()` enables runtime registration without source changes

## Frequently Asked Questions

### What is the difference between the cloud-agent registry and the ACP registry?

The **cloud-agent registry** ([`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts)) maps provider IDs to HTTP-based implementations that handle direct API communication. The **ACP registry** ([`src/lib/acp/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/acp/registry.ts)) defines local CLI processes that OmniRoute can spawn and manage. The `providerAlias` field links an ACP definition to its corresponding cloud-agent implementation, allowing requests to flow through either path.

### Why does a cloud agent need a local CLI binary?

ACP is designed around locally spawned processes using stdio or HTTP transports. Cloud agents natively use remote HTTP APIs. The CLI binary bridges these models: it presents the ACP interface to OmniRoute while internally forwarding requests to the cloud agent's HTTP implementation. This maintains architectural consistency across all provider types.

### How does OmniRoute detect whether a cloud agent is available?

`AcpManager.detectInstalledAgents()` executes each definition's `versionCommand` and checks the exit code. For Codex Cloud, this runs `codex-cloud --version`. A successful execution (exit 0) marks the agent as installed and includes it in `getAvailableAgents()` results. Failed commands exclude the agent from the available list without throwing errors.

### Can I integrate a cloud agent without modifying OmniRoute's source code?

Yes. Use `setCustomAgents()` from [`src/lib/acp/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/acp/registry.ts) to register custom ACP definitions at runtime. These persist in the settings database and merge with built-in definitions. However, you still need a CLI binary on `$PATH` and a corresponding cloud-agent implementation registered via your own plugin mechanism or fork.