plexus-rpc
One dependency. Schema-driven RPC for distributed systems in Rust + Haskell.
plexus-rpc is the umbrella crate for the Plexus RPC framework. Add one line to your Cargo.toml and you get the verified-compatible set: dispatch core, procedural macros, sealed identity / credential / tenant / audit primitives, and the WebSocket / HTTP / stdio server runtime.
[]
= "0.1"
Define methods in plain Rust. The macro extracts JSON Schema from your signatures and rustdoc, registers handlers, and lets synapse discover the whole surface at runtime. No route tables, no schema files, no codegen step.
Hello, plexus
A working server in one file. Run it; talk to it from the synapse CLI.
// examples/echo.rs
use stream;
use Stream;
use DynamicHub;
use TransportServer;
use JsonSchema;
use ;
use Arc;
;
async
Note: the DynamicHub import resolves through plexus_core directly (as the shipped examples/echo.rs does). Macro-emitted code expects direct plexus_core / plexus_macros dependencies in scope, so the umbrella plexus_rpc::core::plexus re-export path does not work for that hub type.
In another terminal:
The default synapse registry sits at localhost:4444 — start your backend on that port and the CLI discovers it automatically.
Installing synapse
Synapse is the CLI client that derives commands, help, and validation from your backend's schema. Install it from Hackage:
Or build from source:
&&
With the binary on your PATH:
What's in the box
The umbrella re-exports four crates as namespaced modules:
| Re-export | Source crate | Contents |
|---|---|---|
plexus_rpc::auth_core |
plexus-auth-core |
AuthContext, Principal, sealed Credential<T>, Tenant + TenantResolver, ForwardPolicy, AuditRecord + AuditSink, BackendAuthCapabilities |
plexus_rpc::core |
plexus-core |
DynamicHub, Activation trait, MethodSchema, credential wire envelope, ChildRouter, hub builders (with_auth_capabilities, with_forward_policy) |
plexus_rpc::macros |
plexus-macros |
#[activation], #[method], #[child], #[derive(Credentials)], #[from_auth] |
plexus_rpc::transport |
plexus-transport (default-on feature transport) |
TransportServer, WebSocket / HTTP / stdio server runtime |
Drop the transport feature when you're building ahead-of-time codegen / embedded / WASM consumers that only need the type and dispatch surface:
= { = "0.1", = false }
The doc-comment-first method shape
Doc comments on the function and each parameter feed the JSON Schema description automatically:
If you need to override (e.g. to differ from the rustdoc you want shown to library users), the explicit attribute syntax still works and wins when set:
Auth, credentials, tenancy (one-line summary each)
The umbrella ships the AUTHZ wave-2 primitives. Each is opt-in — your existing backends keep working unchanged.
- Auth capability advertisement —
DynamicHub::with_auth_capabilities(...)makes_infodescribe your supported mechanisms (Bearer / Cookie / OIDC / Anonymous) so generic clients can discover them. - Sealed identity —
AuthContext,Principal,VerifiedUserare sealed at the crate boundary; activation code receives references, never constructs them. - Credentials as return values — a method can return
Credential<T>from any response struct. The framework intercepts at the serialization boundary, replaces the value with a{"$credential": "<id>"}sentinel, routes the real value through a sidecar, and (withattach_as = "cookie:<name>", e.g.attach_as = "header:authorization") projects it to aSet-Cookie/ response header. Generated TypeScript/Rust clients auto-store and auto-attach. - Tenant isolation —
Tenantis a sealed identity primitive;ClaimTenantResolverderives it from a JWT claim;Tenanted<S>+Scoped<'a, S>wrap your storage in a tenant boundary the type system enforces. - Forwarding policy —
DynamicHub::with_forward_policy(namespace, policy)declares how the caller's identity propagates on cross-boundary calls (IdentityOnly,PassThrough,Anonymous, or your own). - Audit —
AuditRecord+AuditSinktrait +TracingAuditSinkdefault sink emits to theplexus::audittracing target.
Capability manifest
Backends embed plexus_rpc::CAPABILITIES in their _info response so generic clients negotiate features instead of guessing from version strings.
let info = json!;
CAPABILITIES.features is a stable list of named flags ("credentials", "forward_policy", "tenant", etc.). Tooling branches on flags, not versions.
Code generation
synapse --emit-ir <backend> produces a structured IR JSON. hub-codegen consumes it to produce typed TypeScript and Rust clients with:
- Method signatures derived 1:1 from the backend
- Auto-storage of returned credentials on a
SessionRegistry - Auto-attach on methods declaring
requires_credential - Streaming responses surfaced as
AsyncIterable(TS) /impl Stream(Rust) ///doc comments threaded into the generated docstrings
See synapse-cc for the orchestrator that wires synapse + hub-codegen into one cargo-style build flow.
Examples
The examples/ directory has a runnable server:
examples/echo.rs— the minimal hello-world above
It binds to 127.0.0.1:4444 by default so the bare synapse invocation finds it.
What plexus-rpc is NOT
- Not a routing framework for HTTP REST. This is JSON-RPC streaming over WebSocket / stdio / MCP HTTP. The optional REST gateway in
plexus-transportis for adapting REST callers; the canonical surface is JSON-RPC. - Not a code generator for the server side. Server code IS the schema. The codegen story is on the client side (TypeScript, Rust SDK consumers).
- Not an auth provider. The framework defines the primitives (
AuthContext,Principal,Credential<T>,Tenant) and the wire envelopes; you bring your own JWT validator, OIDC client, or whatever — and it plugs in as aSessionValidatorimplementation.
License
MIT. See LICENSE.
Status
Pre-1.0. APIs are stable in shape but subject to additive change. Each subcrate carries its own changelog; the umbrella's Capabilities.features is the canonical "what shipped in this release" reference.