vgi-rpc logo

vgi-rpc

Transport-agnostic RPC built on Apache Arrow

Define typed interfaces. No code generation. One protocol across pipes, subprocesses, shared memory, and HTTP.

What is vgi-rpc?

vgi-rpc is an RPC framework where you define services as typed interfaces — the framework automatically derives Apache Arrow schemas from your type annotations and handles all serialization.

There are no .proto files, no code generation step, and no IDL to learn. Write a Protocol class in Python (or the equivalent interface in Go, TypeScript, or C++), and you get a fully typed RPC service.

The same interface works across every transport: in-process pipes, subprocess stdin/stdout, Unix sockets, shared memory (zero-copy, 29 GB/s), and HTTP. Switch transports without changing a line of service code.

vgi-rpc supports unary calls, producer streams (server pushes data), and exchange streams (lockstep bidirectional), with built-in error propagation, logging, introspection, and OpenTelemetry tracing.

Define a service — no code generation needed
from typing import Protocol

class MathService(Protocol):
    def add(self, a: float, b: float) -> float: ...
    def multiply(self, a: float, b: float) -> float: ...

# Use it over any transport
with connect(MathService, ["python", "worker.py"]) as proxy:
    result = proxy.add(a=1.0, b=2.0)  # Fully typed!

Why vgi-rpc?

Built for developers who want typed RPC without the ceremony.

Zero Code Generation

Define services with native type annotations. No .proto files, no IDL, no compile step. Your Protocol class is the interface.

🔌

Transport-Agnostic

Pipe, subprocess, Unix socket, shared memory, HTTP — same service code, just swap the transport. Add custom transports too.

🎯

Apache Arrow Native

Columnar serialization with zero-copy potential. Efficient for scalar values and massive DataFrames alike.

🌊

Streaming Built-in

Producer streams for server-push data and exchange streams for lockstep bidirectional communication. Headers supported.

🌐

Multi-Language

Python (reference), TypeScript, Go, and C++ implementations sharing the same wire protocol. True cross-language RPC.

🔍

Runtime Introspection

Built-in __describe__ method returns machine-readable service metadata — method signatures, schemas, and types.

Five Transports, One Interface

Your service code stays the same. Only the transport setup changes.

Pipe

~5 μs

In-process, bidirectional byte stream. Lowest latency — ideal for tests and embedded use.

Testing, demos

Subprocess

~50 μs

Spawn a worker process, communicate over stdin/stdout. Process isolation with low overhead.

Isolated workers, CLI tools

Unix Socket

~30 μs

Kernel-mediated local IPC. Long-lived connections with per-client threading support.

Local services, daemons

Shared Memory

~5 μs

Zero-copy Arrow batch transfer via memory-mapped segments. Only pointers cross the pipe.

Large batches, co-located

HTTP

~500 μs

Stateless HTTP transport with signed state tokens for streaming. Works with any WSGI server.

Network services, browsers

Framework Comparison

How vgi-rpc compares to other RPC frameworks.

Framework Serialization IDL Required Streaming Typed Proxies Transports
vgi-rpc Arrow IPC No (Protocol classes) Producer + Exchange Yes (mypy strict) Pipe, subprocess, Unix socket, shm, HTTP
Arrow Flight Arrow IPC + gRPC No (fixed API) get/put/exchange No (generic client) gRPC (HTTP/2)
gRPC Protobuf Yes (.proto) All 4 patterns Partial HTTP/2
Apache Thrift Thrift binary/compact Yes (.thrift) No No TCP, HTTP
ConnectRPC Protobuf Yes (.proto) All 4 patterns Yes HTTP/1.1 + HTTP/2
Cap'n Proto Cap'n Proto Yes (.capnp) Promise pipelining No TCP
JSON-RPC JSON No No No HTTP

See the detailed comparison for an in-depth analysis of each framework.

Performance

Apache Arrow's columnar format combined with transport flexibility delivers exceptional throughput.

Unary Call Latency (Python)

Pipe (in-process) 5.2 μs
Shared Memory 5.8 μs
Unix Socket 33 μs
Subprocess 52 μs
HTTP (in-process) 520 μs

Lower is better. Measured on Apple M-series, Python 3.12.

Streaming & Throughput

Shared Memory Throughput 29 GB/s

100 MB segment, batch transfer

Producer (pipe) 48,000 batches/s

1K-row Arrow batches

Exchange (pipe) 32,000 round-trips/s

Lockstep bidirectional

Serialization (primitive) 0.8 μs

Single float64 column

Serialization (complex) 12 μs

Nested dataclass with lists

Language Implementations

One wire protocol, multiple languages. All implementations interoperate via subprocess transport.

Python logo

Python

Reference Implementation

The original implementation with full feature support. Strict mypy typing, all transports, streaming, introspection, shared memory, and OpenTelemetry.

pip install vgi-rpc
TypeScript logo

TypeScript

In Development

TypeScript/Bun implementation with subprocess transport support. Arrow IPC serialization via apache-arrow npm package.

Go logo

Go

In Development

Go implementation using apache/arrow-go. Subprocess transport with conformance testing against the Python reference.

C++ logo

C++

In Development

C++20 server framework with pipe/subprocess transport. All RPC patterns (unary, producer, exchange), introspection, error propagation, client logging, and stream headers. Conformance-tested against the Python reference.

Capability Matrix

Feature support across all implementations. Updated automatically via CI.

Transports

Transport PythonTypeScriptGoC++
Pipe
Subprocess
Unix Socket
Shared Memory
HTTP
Worker Pool

RPC Patterns

Pattern PythonTypeScriptGoC++
Unary
Unary (void)
Producer
Producer + Header
Exchange
Exchange + Header

Features

Feature PythonTypeScriptGoC++
Introspection
Client Logging
Error Propagation
Complex Types
Optional Types
Dataclass Types
Annotated Types
Authentication
External Storage
OpenTelemetry

Last updated: February 22, 2026

Get Started

Install in your language and define your first service in minutes.

Python logo Python Docs →
pip install vgi-rpc
TypeScript logo TypeScript Docs →
bun add vgi-rpc-typescript
go get github.com/Query-farm/vgi-rpc-go
git clone https://github.com/Query-farm/vgi-rpc-cpp.git
Complete Python example
from typing import Protocol
from vgi_rpc import connect, run_server

# 1. Define your interface
class Calculator(Protocol):
    def add(self, a: float, b: float) -> float: ...
    def greet(self, name: str) -> str: ...

# 2. Implement it
class CalculatorImpl:
    def add(self, a: float, b: float) -> float:
        return a + b
    def greet(self, name: str) -> str:
        return f"Hello, {name}!"

# 3. Use it (subprocess transport)
with connect(Calculator, ["python", "worker.py"]) as calc:
    print(calc.add(a=2.0, b=3.0))    # 5.0
    print(calc.greet(name="World"))  # Hello, World!