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

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. The CodexCloudAgent class implements:

  • createTask() — Initialize a new conversation task
  • pollStatus() — Check completion state
  • sendMessage() — Stream or return responses
// 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 and add your agent to the exported registry object:

// 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) 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:

// 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. 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 and the key in src/lib/cloudAgent/registry.ts.

Complete Integration Example

// 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) for dynamic registration:

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
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; ACP definitions in 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) maps provider IDs to HTTP-based implementations that handle direct API communication. The ACP registry (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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →