How to Integrate Prime Agent with External Systems Using RPC Mode

Prime Agent can be integrated with external systems by launching it in RPC mode, which enables headless operation via JSON-Lines communication over standard streams, allowing programmatic control through the RpcClient class.

Prime Agent from PrimeIntellect-ai/prime-agent supports a Remote Procedure Call (RPC) mode that transforms the agent into a headless service controllable via standard input and output streams. This architecture enables seamless integration with web servers, CI pipelines, microservices, and custom automation scripts without requiring a terminal user interface. By leveraging the RPC mode components, you can send commands, receive streaming events, and handle extension UI requests through a typed, event-driven API.

Understanding the RPC Architecture

The RPC implementation relies on a JSON-Lines protocol where each message is a single JSON object terminated by a newline. The architecture separates concerns between the client driver, the agent runtime, and UI bridging capabilities.

RpcClient

The RpcClient class, located in packages/coding-agent/src/modes/rpc/rpc-client.ts, serves as the primary interface for external systems. It spawns the agent process with the --mode rpc argument and manages the full lifecycle of the connection. The client handles request-response correlation, event subscription routing, and clean shutdown sequences.

RpcMode

RpcMode (implemented in packages/coding-agent/src/modes/rpc/rpc-mode.ts via the runRpcMode function) represents the agent-side execution loop. This component reads JSON-Lines from stdin, executes received commands, and writes responses or extension UI requests back to stdout. It also forwards internal agent events such as session_event and extension_error to the client.

RpcExtensionUiBridge

When running headless, the RpcExtensionUiBridge (found in packages/coding-agent/src/modes/rpc/rpc-extension-ui-context.ts) provides a minimal UI context that satisfies extension requests for dialogs and notifications. Responses are serialized as JSON-Lines and sent back through the communication channel, allowing programmatic handling of user interface interactions.

JSONL Helper

The jsonl.ts file in packages/coding-agent/src/modes/rpc/jsonl.ts provides utility functions attachJsonlLineReader and serializeJsonLine that handle the low-level newline-delimited JSON serialization and parsing required by the protocol.

How RPC Communication Works

Process Launch

The integration begins when RpcClient.start() spawns a Node.js process executing dist/cli.js with the arguments --mode rpc along with any provider or model configuration overrides.

Message Flow

Communication follows a strict request-response pattern:

  1. The client writes an RpcCommand (such as {type:"prompt",message:"Hello"}) to the child process's stdin using serializeJsonLine
  2. The agent reads the line, executes the command, and emits either an RpcResponse or an RpcExtensionUIRequest
  3. Agent events including session_event and extension_error are wrapped as JSON-Lines and streamed upstream

Request Correlation

Each outbound command receives a unique id identifier. The client stores a promise in an internal pendingRequests map and resolves it when the matching response arrives, enabling asynchronous request tracking.

Extension UI Handling

When the agent requires UI interaction (such as selection dialogs or confirmations), the bridge creates a temporary promise that resolves with an RpcExtensionUIResponse. In pure RPC deployments, you can supply default values or implement custom UI handlers to respond programmatically.

Graceful Shutdown

Calling RpcClient.stop() closes the JSONL reader, terminates the child process, and clears all pending request state, ensuring clean resource cleanup.

Implementation Examples

Basic RPC Client Setup

To integrate Prime Agent into your application, instantiate the RpcClient and subscribe to streaming events:

import { RpcClient } from "prime-agent/src/modes/rpc/rpc-client.js";

async function demo() {
  const client = new RpcClient({
    provider: "openai",
    model: "gpt-4o"
  });

  await client.start();

  // Listen for streaming events (agent_start, tool_call, finish)
  const unsub = client.onEvent((ev) => console.log("EVENT:", ev));

  // Send a prompt command
  await client.prompt("Explain quantum entanglement in one sentence.");

  // Cleanup
  await client.stop();
  unsub();
}

demo().catch(console.error);

Capturing Agent Responses

To receive the final result directly rather than through event streaming:

import { RpcClient } from "prime-agent/src/modes/rpc/rpc-client.js";

async function askAndGetResult() {
  const client = new RpcClient();
  await client.start();

  const respPromise = new Promise((resolve) => {
    client.onEvent((ev) => {
      if (ev.type === "agent_finish") resolve(ev);
    });
  });

  await client.prompt("What is the capital of France?");
  const result = await respPromise;
  console.log("Answer:", result.data?.message);
  
  await client.stop();
}

In-Process Integration

For scenarios requiring tighter coupling without process isolation, embed the RPC handler directly using an existing AgentSessionRuntime:

import { runRpcModeWithConnection } from "prime-agent/src/modes/rpc/rpc-mode.js";
import { InProcessAgentConnection } from "prime-agent/src/modes/agent-connection/in-process-agent-connection.js";
import { AgentSessionRuntime } from "prime-agent/src/core/agent-session-runtime.js";

async function embedRpc() {
  const runtime = new AgentSessionRuntime(/* configuration */);
  const connection = new InProcessAgentConnection(runtime);
  
  // This call runs the RPC loop indefinitely
  await runRpcModeWithConnection(connection);
}

Handling UI Dialogs Programmatically

When extensions request user interface interactions, respond programmatically using the client methods:

import { RpcClient } from "prime-agent/src/modes/rpc/rpc-client.js";

async function automatedSelect() {
  const client = new RpcClient();
  await client.start();

  // Intercept UI requests and provide automated responses
  client.onObservedSessionEvent((ev) => {
    if (ev.type === "extension_ui_request" && ev.method === "select") {
      client.respondToExtensionUiRequest(ev.id, { value: "option-2" });
    }
  });

  // Continue with normal operation
  await client.prompt("Select the best option from the list.");
}

Summary

  • Prime Agent's RPC mode enables headless operation via JSON-Lines over stdin/stdout, eliminating the need for terminal UI interaction
  • The RpcClient class manages process lifecycle and provides typed methods for sending commands and subscribing to events
  • Request correlation uses unique identifiers to match responses with outbound commands in asynchronous workflows
  • RpcExtensionUiBridge allows programmatic handling of extension UI requests when running without a graphical interface
  • In-process embedding via runRpcModeWithConnection supports scenarios requiring tighter integration than separate process spawning
  • All RPC communication relies on the JSON-Lines protocol implemented in jsonl.ts for reliable message framing

Frequently Asked Questions

What is RPC mode in Prime Agent?

RPC mode is a headless operational mode where Prime Agent runs as a child process accepting JSON-Lines commands via stdin and emitting responses and events via stdout. According to the PrimeIntellect-ai/prime-agent source code, this mode is activated by passing the --mode rpc argument to the CLI, enabling programmatic integration without graphical user interface dependencies.

How does Prime Agent handle UI interactions in headless mode?

When extensions require user input (such as confirmation dialogs or selection menus), the RpcExtensionUiBridge creates a pending promise that awaits a programmatic response. The client receives an extension_ui_request event through the JSON-Lines stream and can resolve the interaction by calling respondToExtensionUiRequest() with the appropriate response ID and data, allowing fully automated operation of otherwise interactive features.

Can I run Prime Agent RPC without spawning a separate process?

Yes. While the standard approach uses RpcClient.start() to spawn a subprocess, you can embed the RPC handler directly in your application using runRpcModeWithConnection() from packages/coding-agent/src/modes/rpc/rpc-mode.ts. This accepts an InProcessAgentConnection wrapping an existing AgentSessionRuntime instance, eliminating process overhead while maintaining the same JSON-Lines communication protocol.

What protocol does Prime Agent use for RPC communication?

Prime Agent uses a JSON-Lines (JSONL) protocol where each message is a single JSON object terminated by a newline character. The serializeJsonLine function in packages/coding-agent/src/modes/rpc/jsonl.ts handles outgoing serialization, while attachJsonlLineReader manages inbound parsing. This format supports streaming events and request-response correlation through standard POSIX streams.

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 →