# How to Set Up OmniRoute Cloud Agents with Task Lifecycle Management

> Learn to set up OmniRoute cloud agents and manage task lifecycles effectively. Discover the four-step process for standardizing autonomous LLM-backed services with this powerful framework.

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

---

**OmniRoute provides a lightweight Cloud-Agent framework that standardizes autonomous LLM-backed services through a four-step lifecycle (create, poll, approve, message) implemented via the abstract `CloudAgentBase` class in [`src/lib/cloudAgent/baseAgent.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/baseAgent.ts).**

OmniRoute ships a production-ready cloud agent subsystem that unifies autonomous coding agents like Jules, Devin, and Codex under a single task lifecycle management interface. Located in `src/lib/cloudAgent/`, this framework lets you orchestrate remote LLM workers using consistent TypeScript abstractions and REST endpoints according to the diegosouzapw/OmniRoute source code.

## Understanding the Cloud Agent Architecture

### The Base Contract (CloudAgentBase)

All cloud agents inherit from `CloudAgentBase` defined in [`src/lib/cloudAgent/baseAgent.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/baseAgent.ts). This abstract class enforces a uniform contract across providers, ensuring that Jules, Devin, Codex, or custom agents behave identically within your OmniRoute installation.

The base class provides the **`mapStatus`** helper method, which normalizes provider-specific status strings (e.g., `"in_progress"`, `"pending"`) into canonical **`CloudAgentStatus`** values. This guarantees consistent UI rendering regardless of which LLM service powers the agent.

### Provider Registry System

Concrete agent implementations are registered in [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts). This registry maps provider identifiers (e.g., `"jules"`, `"devin"`, `"codex"`) to their respective classes. When the API receives a request for a specific provider, the registry instantiates the correct agent class and injects the necessary credentials via `getCredentialsForProvider()`.

## The Four-Step Task Lifecycle

The framework implements a standardized four-step lifecycle through abstract methods that each concrete agent must implement.

### Step 1: Creating Tasks with createTask()

The **`createTask(params, credentials)`** method initiates work on the remote service. It transmits the prompt, metadata, and configuration options to the provider's endpoint, returning a `CloudAgentTask` record containing a generated **`externalId`**. This external ID serves as the persistent handle for all subsequent lifecycle operations.

### Step 2: Polling Status via getStatus()

Use **`getStatus(externalId, credentials)`** to query the remote service for current state. The method returns standardized status values (`queued`, `running`, `awaiting_approval`, `completed`, `failed`) along with interim activities and optional results. This enables your UI or CLI to display real-time progress without provider-specific parsing logic.

### Step 3: Approving Plans with approvePlan()

When `getStatus` returns `awaiting_approval`, the task pauses pending human authorization. The **`approvePlan(externalId, credentials)`** method sends the approval signal, allowing cost-sensitive or destructive operations (like PR creation) to proceed. This implements human-in-the-loop governance for autonomous agents.

### Step 4: Interactive Messaging via sendMessage()

For multi-turn conversations or incremental refinements, **`sendMessage(externalId, message, credentials)`** transmits follow-up instructions to an active task. The method appends the interaction to the task's activity log stored in [`src/lib/cloudAgent/db.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/db.ts), maintaining a complete audit trail of agent interactions.

## Setting Up Your Environment

### Configuring Agent Credentials

Each agent requires an **`AgentCredentials`** object containing `apiKey` and optional `baseUrl`. Credentials are persisted through the helper functions in [`src/lib/cloudAgent/credentials.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/credentials.ts) and retrieved internally via `getCredentialsForProvider()`. Store these securely in the OmniRoute database before activating agents.

### Registering Custom Agents

To add a new provider, create a class in `src/lib/cloudAgent/agents/<name>.ts` that extends `CloudAgentBase` and implements the four lifecycle methods. Export this class and add an entry to the `AGENT_REGISTRY` object in [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts). The HTTP facade in [`src/lib/cloudAgent/api.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/api.ts) automatically exposes REST endpoints for your new agent under `/api/v1/cloud-agents/:provider/`.

## Consuming the Cloud Agent API

The public API routes are implemented in [`src/lib/cloudAgent/api.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/api.ts) and exposed through the Next.js app router at `src/app/api/v1/cloud-agents/`. Below is a complete TypeScript example demonstrating the full lifecycle against a local OmniRoute instance:

```typescript
import fetch from "node-fetch";

const provider = "jules";                     // one of the built‑in agents
const base = "http://localhost:20128/v1";
const apiKey = process.env.OMNIROUTE_API_KEY; // your OmniRoute API key

// 1️⃣ Create a new task
async function createTask() {
  const res = await fetch(`${base}/cloud-agents/${provider}/tasks`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      prompt: "Add a new feature to the README.md file",
      source: "github",
      options: { autoCreatePr: true, planApprovalRequired: true },
    }),
  });
  const { externalId } = await res.json();
  return externalId;
}

// 2️⃣ Poll status (simple loop)
async function pollStatus(externalId: string) {
  while (true) {
    const res = await fetch(`${base}/cloud-agents/${provider}/tasks/${externalId}/status`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    const data = await res.json();
    console.log("Current status:", data.status);
    if (["completed", "failed", "cancelled"].includes(data.status)) break;
    if (data.status === "awaiting_approval") {
      // 3️⃣ Approve the plan
      await fetch(`${base}/cloud-agents/${provider}/tasks/${externalId}/approve`, {
        method: "POST",
        headers: { Authorization: `Bearer ${apiKey}` },
      });
      console.log("Plan approved");
    }
    await new Promise(r => setTimeout(r, 2000)); // wait before next poll
  }
}

// 4️⃣ Send a follow‑up message (optional)
async function sendMessage(externalId: string, msg: string) {
  await fetch(`${base}/cloud-agents/${provider}/tasks/${externalId}/messages`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({ message: msg }),
  });
}

// Example orchestration
(async () => {
  const id = await createTask();
  console.log("Task created, id =", id);
  await pollStatus(id);
  // optional follow‑up
  await sendMessage(id, "Please add unit tests for the new code.");
})();

```

This example demonstrates credential injection via headers, asynchronous task creation, polling loops with approval gating, and optional messaging—all routed through the standardized API surface.

## Summary

- **OmniRoute cloud agents** follow a strict four-step lifecycle implemented in [`src/lib/cloudAgent/baseAgent.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/baseAgent.ts): `createTask()`, `getStatus()`, `approvePlan()`, and `sendMessage()`.
- The `CloudAgentBase` abstract class enforces provider-agnostic behavior and includes the `mapStatus()` helper for normalizing external state to canonical `CloudAgentStatus` values.
- Concrete implementations reside in `src/lib/cloudAgent/agents/` (e.g., [`jules.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/jules.ts), [`devin.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/devin.ts)) and register via [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts).
- Credentials are managed through [`src/lib/cloudAgent/credentials.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/credentials.ts) using the `AgentCredentials` interface.
- The HTTP API layer in [`src/lib/cloudAgent/api.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/api.ts) exposes versioned endpoints under `/api/v1/cloud-agents/` with full Zod validation and authentication middleware.

## Frequently Asked Questions

### What is the CloudAgentBase class in OmniRoute?

`CloudAgentBase` is an abstract TypeScript class defined in [`src/lib/cloudAgent/baseAgent.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/baseAgent.ts) that defines the contract all cloud agents must implement. It specifies the four lifecycle methods (`createTask`, `getStatus`, `approvePlan`, `sendMessage`) and provides the `mapStatus` helper to normalize provider-specific status strings into canonical values like `queued`, `running`, or `awaiting_approval`.

### How do I add a new cloud agent provider to OmniRoute?

Create a new file in `src/lib/cloudAgent/agents/<name>.ts` that extends `CloudAgentBase` and implements the required abstract methods. Then add the provider identifier and class to the `AGENT_REGISTRY` object in [`src/lib/cloudAgent/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/cloudAgent/registry.ts). The system automatically exposes REST endpoints for your agent without modifying the API layer.

### What are the canonical task statuses used in the lifecycle?

The `mapStatus` method in `CloudAgentBase` normalizes all provider responses to the following canonical statuses: `queued`, `running`, `awaiting_approval`, `completed`, `failed`, and `cancelled`. These values are defined in the `CloudAgentStatus` type and used consistently across the API response schema.

### How does human-in-the-loop approval work in OmniRoute cloud agents?

When an agent returns a plan requiring authorization (e.g., before creating an expensive PR), the `getStatus` method returns `awaiting_approval`. Client code must then call the `approvePlan(externalId, credentials)` method—either manually or via automated policy—to authorize continuation. This gating mechanism prevents autonomous actions until explicitly approved, implementing cost controls and safety checks.