What Erlang got right

In Erlang, communication does not change shape when it crosses a machine boundary. A process sends to a Pid, and whether the receiver lives in the same VM or on another node is not visible in the code. Handing that Pid to a third process is itself just a message, so communication paths form and dissolve as the program runs.

In most ecosystems this is different. As soon as communication crosses the machine boundary, what was a channel or a method call becomes a socket with a wire format and an RPC framework, and the natural in-process style is lost. Rust's actor and channel libraries largely stop at the process boundary too.

The same idea, with types

Remoc's channels work between processes and machines, and their endpoints are ordinary Serde values. Sending a channel's sender inside a message is the equivalent of sending a Pid: the receiver can now talk to whatever the sender belongs to, over the existing connection, with nothing to register or look up. Tasks reading from channels take the role of processes, and either side can push.

Two things are deliberately different from Erlang. Messages are typed: a channel carries one Serde type, the compiler checks what may be sent, and a trait carrying #[rtc::remote] gives an interface more precise than any receive clause. And channels are bounded: a slow receiver stalls only its own sender instead of accumulating an unbounded mailbox.

Sending a sender, like sending a Pid
use remoc::prelude::*;

#[derive(Serialize, Deserialize)]
struct Subscribe {
    topic: String,
    // The subscriber's address, travelling inside the message.
    events_tx: rch::mpsc::Sender<Event>,
}

What OTP has that Remoc does not

Remoc is a communication library, and OTP is an architecture; the honest comparison is between layers, not features. OTP additionally gives you supervision trees with declared restart strategies, node clustering with a global process registry, preemptive scheduling that isolates a runaway process, and hot code upgrades of a running system. With Remoc, failures surface as errors on channels and calls, and the recovery architecture is yours to design.

The ingredients for that architecture are available, though. Run each service as its own OS process and let a parent process supervise it over Remoc. The kernel then provides preemptive scheduling and memory isolation even stronger than that of BEAM processes. A crash becomes a child exit that the parent observes and answers with a restart, and since Postbag keeps message types compatible across versions, restarting a child with a newer binary takes the place of a hot upgrade. This is the let-it-crash approach, with the operating system providing the isolation. OTP ships this machinery ready-made; with Remoc you assemble it yourself.

What Rust adds in exchange are compile-time checked messages, no garbage collector, single static binaries and the performance of native code, in a general-purpose language: the parts of a system that are not message passing, be it numerics, embedded targets or a user interface, need not leave it. For keeping the connection itself alive across link failures and network changes, Aggligator provides a resilient transport underneath Remoc.

Questions

Is Remoc an actor framework?

No. Remoc is the communication layer: typed channels, remote functions and trait calls between two Rust programs. Tasks reading from channels give you actor-style patterns, but there is no actor runtime, no registry and no lifecycle management.

Does it have supervision trees like OTP?

Not ready-made. When a peer or connection fails, the error surfaces on the affected channels and calls, and what to do about it is your code. The pattern of running services as OS processes that a parent supervises and restarts over Remoc provides the ingredients of a supervision tree, with the kernel enforcing the isolation, but you assemble the restart logic yourself.

How do the messages differ from Erlang's?

They are typed and checked at compile time: a channel carries values of one Serde type, so a message of the wrong shape is a compile error rather than a term that sits in a mailbox until a receive clause fails to match. Channels are also bounded and apply backpressure, where Erlang mailboxes grow without limit, which is a classic failure mode of overloaded Erlang systems.

Can I form a cluster with a global process registry?

Not with Remoc alone. A Remoc connection is point-to-point between two peers, and channels belong to their connection. Node membership, discovery and a global registry are yours to build on top if you need them; distributed Erlang provides them out of the box.

What about hot code upgrades?

Running code is not replaced in place. However, since Remoc serializes with the Postbag codec, programs built from different versions of your message types keep understanding each other, so endpoints can be upgraded and restarted one at a time without stopping the system.

Where to go next

Channels between processes and machines shows the model in working code, and the channels example is complete and runnable. For request/response-shaped services, Remoc vs. other RPC libraries places the model next to tarpc, gRPC and Cap'n Proto.