Skip to content

Standard Library: Remote

The std::core::remote module provides transparent remote execution for Shape functions. It handles wire protocol encoding, transport, and response decoding automatically — letting you run functions on remote shape serve instances as if they were local.

from std::core::remote use { @remote }
use std::core::remote
from std::core::intrinsics use { HashMap, Ok, Err, Result }

Import @remote explicitly when you want the bare annotation form. Use the module namespace for low-level APIs such as remote::execute.

The primary API is the @remote annotation. When applied to a function, calling that function transparently executes it on the specified remote server instead of locally.

@remote("worker:9527")
fn compute(data) {
data.map(|x| x * 2)
}
// Looks like a normal call — executes on worker:9527
let result = compute([1, 2, 3])
// result: Ok([2, 4, 6])

The @remote annotation’s before hook intercepts the call and returns { result: result } where result is the Result value from the wire call — Ok(value) on success, Err(message) on transport or execution failure.

The @remote annotation uses Shape’s annotation system with a before hook that short-circuits local execution:

  1. The caller invokes the function normally
  2. The before hook intercepts the call, serializes the function and arguments via the wire protocol, and sends them to the remote shape serve node
  3. The remote node reconstructs the function from content-addressed blobs, executes it, and returns the result
  4. The before hook returns the result directly — the function body never runs locally

@remote works with all Shape value types as arguments and return values:

// Integer parameters (no heap allocation)
@remote("127.0.0.1:9527")
fn add(a, b) { a + b }
assert add(10, 32) == Ok(42)
// Array parameters
@remote("127.0.0.1:9527")
fn first(arr) { arr[0] }
assert first([10, 20, 30]) == Ok(10)
// String parameters
@remote("127.0.0.1:9527")
fn greet(name) { f"Hello, {name}!" }
assert greet("World") == Ok("Hello, World!")
// Closures and higher-order functions
@remote("127.0.0.1:9527")
fn double_all(arr) { arr.map(|x| x * 2) }
assert double_all([1, 2, 3]) == Ok([2, 4, 6])

@remote also works on foreign function definitions. The function is compiled and executed on the remote server using its language runtime:

@remote("gpu-worker:9527")
async fn python matrix_multiply(a: Array<Array<number>>, b: Array<Array<number>>) -> Result<Array<Array<number>>, string> {
import numpy as np
a_np = np.array(a)
b_np = np.array(b)
return (a_np @ b_np).tolist()
}
let result = matrix_multiply([[1, 2], [3, 4]], [[5, 6], [7, 8]])
// Executes Python on gpu-worker:9527

Execute Shape source code on a remote server. The server compiles and runs the code string, returning the structured result.

let r = remote::execute("localhost:9527", "fn add(a, b) { a + b }\nadd(10, 32)")
match r {
Ok(result) => print(f"Value: {result["value"]}") // 42
Err(e) => print(f"Failed: {e}")
}

Parameters:

  • addr: string — Server address as host:port
  • code: string — Shape source code to execute

Returns: Result<HashMap<string, _>, string> with fields value, stdout, error.

Check connectivity and get server info.

match remote::ping("localhost:9527") {
Ok(info) => print(f"Server v{info["shape_version"]}")
Err(e) => print(f"Server down: {e}")
}

Returns: Result<HashMap<string, _>, string> with shape_version and wire_protocol.

Low-level function call transport. This is the builtin used internally by the @remote annotation. Serializes the function and arguments via the wire protocol and sends them to the remote node.

fn square(x) { x * x }
let result = remote::__call("localhost:9527", square, [7])
// result: Ok(49)

Parameters:

  • addr: string — Server address
  • fn_ref — Function reference to call remotely
  • args: Array<_> — Arguments to pass

Returns: Ok(value) or Err(message).

Remote calls use the same wire protocol as shape serve:

  • Content-addressed blobs: Functions are identified by SHA-256 hash. Only blobs the server doesn’t have are transmitted.
  • Blob negotiation: Persistent connections cache blobs, so repeated calls to the same function only transmit arguments.
  • Compression: All frames are zstd-compressed when beneficial.
  • Sidecar splitting: Large arguments (> 1 MB) are sent as parallel sidecar messages.

See Wire Protocol for full details.

All remote calls return Result values:

@remote("unreachable:9527")
fn work(x) { x * 2 }
match work(42) {
Ok(v) => print(f"Got: {v}")
Err(e) => print(f"Remote error: {e}")
}

Errors include transport failures (connection refused, timeout), server-side compilation errors, and runtime exceptions.