How Python-Backed Skills Use Typed Host Requests in Prime Agent

Python-backed skills in Prime Agent communicate with the TypeScript host runtime by calling rlm.host_request() with a type string and JSON-serializable payload, which the kernel routes through the typed HostRequestHandlers map defined in packages/coding-agent/src/core/kernel/shared.ts.

The Prime Agent framework allows developers to write skills in Python while leveraging host-side services like web search, file system access, and sub-agent spawning. This integration relies on a strictly typed host request protocol that bridges the IPython REPL environment with the JavaScript kernel.

Understanding the Typed Host Request Architecture

The architecture separates concerns between the Python execution environment and the host runtime. Python skills request capabilities through typed messages, while the host implements handlers that fulfill these requests asynchronously.

The Host Request Type System

At the core of this system is the type definition found in packages/coding-agent/src/core/kernel/shared.ts. This file establishes the contract between Python skills and the host runtime:

// packages/coding-agent/src/core/kernel/shared.ts
export type HostRequestHandler = (
  payload: Record<string, unknown>
) => Promise<Record<string, unknown>>;

export type HostRequestHandlers = Record<string, HostRequestHandler>;

The HostRequestHandler type defines a function that accepts a Record<string, unknown> payload and returns a promise resolving to another record. This loose typing on the host side allows for dynamic request routing while maintaining type safety through the dispatcher pattern.

The HostRequestHandlers type creates a registry map where keys are the request type strings (such as "websearch.query" or "http.fetch") and values are the corresponding handler implementations.

The Python Bridge

The IPython bridge in packages/coding-agent/src/core/tools/ipython.ts exposes the rlm module to Python skills. This module provides the host_request function that serializes Python dictionaries into JSON payloads and dispatches them across the language boundary:


# Inside a Python-backed skill

import rlm

async def fetch_data():
    result = await rlm.host_request(
        "http.fetch", 
        {"url": "https://api.example.com/data"}
    )
    return result

The bridge ensures that all payloads remain JSON-serializable, preserving type information as dictionaries on both sides of the communication channel.

Implementing Typed Host Requests in Python Skills

Python skills initiate host requests by importing the rlm module and awaiting the host_request coroutine. The function signature requires two parameters: the request type string and the payload dictionary.

Basic Request Pattern

When a skill needs to perform a web search, it issues a typed request like this:


# skills/websearch_example.py

import rlm

async def search_primes(query: str):
    # Typed host request with specific request type

    response = await rlm.host_request(
        "websearch.query",
        {"query": query, "max_results": 10}
    )
    
    # Response is a Python dict matching the handler's return type

    return response.get("results", [])

The first argument "websearch.query" serves as the lookup key in the host's HostRequestHandlers registry. The second argument must be a dictionary that serializes to valid JSON, matching the expected schema for that specific request type.

Sub-Agent Creation Requests

Skills can also request the host to spawn sub-agents through typed requests:


# skills/orchestrator.py

import rlm

async def create_worker(model: str):
    reply = await rlm.host_request(
        "subagent.spawn",
        {"name": "worker", "model": model, "timeout": 300}
    )
    
    # Typed response contains agent identifier

    return reply["agentId"]

The payload structure varies by request type, but all follow the same pattern: a string key identifying the capability and a dictionary containing the parameters.

Registering Handlers on the Host Side

On the TypeScript side, developers register handlers by populating the HostRequestHandlers map. Each entry connects a request type string to an async function that implements the requested functionality.

Handler Registration Example

Consider the implementation of an HTTP fetch handler:

// packages/coding-agent/src/core/tools/http.ts
import { HostRequestHandlers } from "../kernel/shared";

export const httpHandlers: HostRequestHandlers = {
  "http.fetch": async ({ url, method = "GET" }) => {
    const response = await fetch(url as string, { 
      method: method as string 
    });
    const body = await response.text();
    
    return { 
      status: response.status, 
      body,
      headers: Object.fromEntries(response.headers)
    };
  },
};

The handler receives the payload as Record<string, unknown> and must return a Promise<Record<string, unknown>>. The kernel automatically serializes this return value back to Python as a dictionary.

Integrating Handlers into the Kernel

Handlers are aggregated into a single registry during kernel initialization:

// packages/coding-agent/src/core/kernel/index.ts
import { httpHandlers } from "../tools/http";
import { websearchHandlers } from "../tools/websearch";

const hostHandlers: HostRequestHandlers = {
  ...httpHandlers,
  ...websearchHandlers,
  // Additional handlers merged here
};

This centralized registration allows the dispatch mechanism to route incoming requests from Python skills to the appropriate TypeScript implementation.

Request Flow and Data Flow

The execution flow follows a strict async request-response pattern across the language boundary:

  1. Request Initiation: The Python skill calls await rlm.host_request("type", payload)
  2. Serialization: The IPython bridge serializes the payload to JSON and emits a host_request event
  3. Dispatch: The kernel receives the event, extracts the request type, and looks up the handler in the HostRequestHandlers map in shared.ts
  4. Execution: The matched handler executes with the deserialized payload
  5. Response: The handler returns a promise that resolves to a record
  6. Reply: The kernel emits a host_reply event containing the result
  7. Deserialization: The bridge converts the response back to a Python dictionary
  8. Resolution: The original rlm.host_request() call returns the dictionary to the skill

This flow ensures that Python skills remain agnostic to the implementation details of host services while maintaining type contracts through the Record<string, unknown> interfaces.

Summary

  • Type Safety: The HostRequestHandlers map in packages/coding-agent/src/core/kernel/shared.ts provides a typed registry for routing requests from Python to TypeScript.
  • Python API: Skills use rlm.host_request(type, payload) where the type string identifies the handler and the payload is a JSON-serializable dictionary.
  • Async Communication: All host requests are asynchronous, returning promises on the TypeScript side and coroutines on the Python side.
  • Handler Pattern: Host-side implementations follow the HostRequestHandler type signature, accepting Record<string, unknown> and returning Promise<Record<string, unknown>>.
  • Bridge Implementation: The IPython bridge in packages/coding-agent/src/core/tools/ipython.ts manages serialization and event transmission between the Python REPL and the JavaScript kernel.

Frequently Asked Questions

What happens if a Python skill requests an unregistered host request type?

If the rlm.host_request() call specifies a type string that does not exist in the HostRequestHandlers map, the kernel will fail to find a matching handler and return an error response to the Python skill. The skill should handle this case by catching exceptions or checking for error keys in the response dictionary.

Can Python skills pass complex objects like NumPy arrays through host requests?

No, payloads must be JSON-serializable. Complex objects like NumPy arrays, Pandas DataFrames, or custom class instances cannot pass directly through rlm.host_request(). Skills should convert such objects to primitive types (lists, dictionaries, strings) before making the request, or use alternative data sharing mechanisms provided by the framework.

How does the host handle concurrent requests from multiple Python skills?

The host request system is fully asynchronous. Each request from Python generates a unique event that the kernel processes independently. TypeScript handlers defined in the HostRequestHandlers map can execute concurrently using standard JavaScript async patterns, and the bridge ensures that responses are routed back to the correct awaiting Python coroutine without blocking the IPython REPL.

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 →