praxis-remote
praxis-remote is a standalone gRPC transport package for policy inference. It
does not depend on Praxis training code or benchmark environments. It defines a
small generic contract:
- A client sends a batch of observations.
- A server-side policy handler returns an action tensor.
- Optional
episode_idslet stateful policies keep vectorized rollout lanes independent. - Optional
policy_kwargscarry request-level inference options.
The package is intentionally about transport and serialization only. Application-specific observation semantics and policy adaptation live in the caller.
Install
Install from PyPI:
pip install praxis-remote==0.1.1
Observation Contract
An observation is a mapping from string keys to supported values:
{
"task": "put the mug on the plate",
"observation.images.front": front_rgb,
"observation.state": proprio,
"metadata.episode_index": 7,
}
Supported observation values:
numpy.ndarraystrboolintfloat- numpy scalar values
Policy kwargs support None, booleans, integers, floats, strings, numpy scalar
values, lists, and dictionaries composed from those types.
Supported tensor dtypes:
float32float64int32int64uint8bool
The transport preserves keys exactly after string conversion. The caller and policy adapter are responsible for agreeing on the meaning of those keys.
Serving a Policy
Implement the PolicyHandler protocol and pass it to PolicyServer:
import numpy as np
from praxis_remote import PolicyServer
class MyHandler:
def predict_action(self, observations, *, policy_kwargs=None, episode_ids=None):
del policy_kwargs, episode_ids
return np.zeros((len(observations), 7), dtype=np.float32)
def reset(self, episode_ids=None):
del episode_ids
def model_info(self):
return "my-policy"
PolicyServer(MyHandler(), host="0.0.0.0", port=50051).serve()
PolicyServer serializes requests, validates basic transport shape, and guards
policy calls with a lock so one handler instance is not called concurrently.
Use separate server processes if your policy stack needs independent workers.
host="0.0.0.0" binds the server on all network interfaces. This is useful when
another process, container, or node needs to connect to it. Use
host="127.0.0.1" when the server should accept only same-machine connections.
Calling a Policy
Use PolicyClient.predict_action for an explicit observation batch:
from praxis_remote import PolicyClient
with PolicyClient(host="127.0.0.1", port=50051, timeout=30.0) as client:
action = client.predict_action(
[
{
"task": "pick up the cube",
"observation.state": state,
}
],
episode_ids=["env-0"],
policy_kwargs={"temperature": 0.0},
)
127.0.0.1 is correct when the client runs on the same machine as the server,
or when a remote server is exposed through an SSH tunnel or port-forward. If the
server is running on another reachable host, pass that hostname or IP address
instead.
Use predict_action_from_parts for a single common image/state/text
observation:
action = client.predict_action_from_parts(
state=state,
images={"front": front_rgb, "wrist": wrist_rgb},
task_description="pick up the cube",
episode_id="env-0",
)
Check server readiness:
ready, model_info = client.health_check()
Reset all policy state or selected rollout lanes:
client.reset()
client.reset(episode_ids=["env-0", "env-1"])
Using with praxis-eval
praxis-eval exposes
RemotePolicy, which wraps PolicyClient behind its generic eval policy
protocol:
from praxis_eval import EvalConfig, RemotePolicy, evaluate
result = evaluate(
"libero",
policy=RemotePolicy("127.0.0.1:50051", timeout=30.0),
config=EvalConfig(
task="libero_spatial",
num_eval_per_task=10,
output_dir="eval/libero_spatial",
),
)
The remote server does not need to import praxis-eval unless the policy
adapter chooses to reuse its types. It only needs to implement
PolicyHandler.predict_action.
Protocol
The gRPC schema is in src/praxis_remote/proto/policy_service.proto. Generated
Python files are committed so users do not need protoc for normal installs.
Service methods:
Predict: batch observations plus policy kwargs to one action tensor.Reset: reset all state or selectedepisode_ids.HealthCheck: readiness and short model information string.
The default gRPC send and receive message limit is 64 MiB. Keep image batches and rollout parallelism sized accordingly, or run multiple servers for larger throughput.
Repository Structure
src/praxis_remote/
client.py # PolicyClient
server.py # PolicyServer and gRPC servicer
protocol.py # PolicyHandler protocol
serialization.py # observation, kwarg, and numpy tensor codecs
proto/
policy_service.proto # source gRPC schema
*_pb2*.py # generated protobuf/grpc modules
tests/ # serialization and client/server tests
Development Checks
Run the same checks as CI:
uv run --extra dev pre-commit run check-license-headers --all-files
uv run --extra dev ruff check .
uv run --extra dev ruff format --check .
uv run --extra dev pytest --strict-markers -m "not manual"
uv build --sdist --wheel
Regenerate protobuf files after changing policy_service.proto:
uv run python -m grpc_tools.protoc \
-Isrc/praxis_remote/proto \
--python_out=src/praxis_remote/proto \
--pyi_out=src/praxis_remote/proto \
--grpc_python_out=src/praxis_remote/proto \
src/praxis_remote/proto/policy_service.proto
License and Attribution
praxis-remote is licensed under Apache-2.0. Redistribution must preserve the
license, copyright notices, and NOTICE file. If this package supports your
research or product work, please cite the repository using CITATION.cff.
Metadata
Release files for praxis-remote 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| praxis_remote-0.1.1.tar.gz | 24.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| praxis_remote-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.1 kB
Release files / praxis_remote-0.1.1.tar.gz
| Download URL | praxis_remote-0.1.1.tar.gz |
|---|---|
| Size | 24.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c4414c69285d244c5e86821d4436d07ca2158ad3c3714b127134f0aaae634f16
|
|
BLAKE2b-256 checksum How to use checksums |
e3f6c872b8165f43399ce262227bf1f5c8c5466aea39a627b8d902321c3198c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 22, 2026.
Transparency logRelease files / praxis_remote-0.1.1-py3-none-any.whl
| Download URL | praxis_remote-0.1.1-py3-none-any.whl |
|---|---|
| Size | 22.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
da8dc358d47928bfd9fb3d8b06e9078bd0453c7ff9e5919ad6a5942d92197176
|
|
BLAKE2b-256 checksum How to use checksums |
ed0a1a7aedf564bcd6afa44b29bf87f94929eac6a162ea09c156fda265de56ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 22, 2026.
Transparency log