On this page:
4.1 RPCs, Events, State, Records, and Enums
define-rpc
define-record
record-ref
define-enum
enum-case
define-event
define-state
emit-event!
state?
state-ref
state-set!
4.2 Keel Schema Projection
backend-schema->app-schema
current-backend-app-schema
4.3 Serving an Embedded Connection
serve
serve-fds
current-rivet-diagnostic-sink
backend-schema
rpc-schema
event-schema
state-schema
record-schema
enum-schema
4.4 RVT1 Framing and the Value Codec
frame
write-frame
read-frame
encode-value
decode-value
protocol-version
max-frame-payload-size
max-value-depth
max-value-nodes
message:  hello
message:  request
message:  response
message:  error
message:  event
message:  cancel
message:  shutdown
4.5 Application Resources
current-resource-root
resource-root
resource-path

4 Application Backend🔗ℹ

 (require rivet) package: rivet

4.1 RPCs, Events, State, Records, and Enums🔗ℹ

State descriptors and the registry records behind RPCs, Events, Records, and Enums are intentionally opaque. Applications declare them with the forms in this section; code generators consume the immutable backend-schema snapshot instead of depending on mutable runtime representation.

The type names in declarations are schema grammar, not Racket variables or runtime descriptor values. They are interpreted only inside the declaration forms below. This keeps application code honest: use ordinary Racket predicates and contracts for runtime values, and use the generated Keel schema when a tool needs to inspect the application contract.

syntax

(define-rpc (name [arg : type] ... : result-type) body ...)

Defines a Racket procedure named name and registers it as an RPC for generated Swift, C++, and Kotlin clients. Supported schema types are String, Int64, Bool, Bytes, Void, Any, (List type), (Optional type), and names introduced by define-record or define-enum. The result is validated before it is placed on the wire.

syntax

(define-record name ([field : field-type] ...))

Defines a constructor named name and registers an ordered, typed Record schema. Records generate Swift and C++ structs plus Kotlin data classes and use an RVT1 List in field declaration order.

procedure

(record-ref value field) → any/c

  value : any/c
  field : (or/c symbol? string?)
Returns a named field from a value constructed by define-record.

syntax

(define-enum name (case ...))

Defines a constructor named name and registers a closed, ordered set of cases. The constructor accepts a case symbol or string. Generated Swift uses a raw-value enum; generated C++ uses enum class; generated Kotlin uses an enum class with the wire name; RVT1 carries the stable case name as a String.

procedure

(enum-case value) → symbol?

  value : any/c
Returns the case symbol from a value constructed by define-enum.

syntax

(define-event name : type)

Registers an event and defines name as a one-argument procedure that emits a validated event value while a Rivet server is active. Omitting the type uses Any. Event payloads cannot have type Void.

syntax

(define-state name : type initial-value)

Creates and registers a shared state value. Native clients can read and set the state through generated APIs, and successful changes emit Rivet’s reserved state event. State values cannot have type Void.

procedure

(emit-event! name value) → void?

  name : (or/c symbol? string?)
  value : any/c
Emits an already registered event value on the active server connection. The procedure reports an error when no server is active on the current thread.

procedure

(state? value) → boolean?

  value : any/c
Reports whether value is an opaque State descriptor produced by define-state.

procedure

(state-ref state) → any/c

  state : state?
Returns the current state value.

procedure

(state-set! state value) → void?

  state : state?
  value : any/c
Validates and atomically commits a state value, then admits its native event in the same update order.

(require rivet)
 
(define-rpc (greet [name : String] : String)
  (string-append "Hello, " name))
 
(define-event notification : String)
(define-state signed-in? : Bool #f)

4.2 Keel Schema Projection🔗ℹ

 (require rivet/keel) package: rivet

Keel is the transport-neutral application contract shared by Rivet and Glaze. These adapters expose the same application model without moving RVT1 framing, native client generation, embedding, or UI ownership out of Rivet.

procedure

(backend-schema->app-schema schema    
  #:id id    
  [#:revision revision]) → any/c
  schema : hash?
  id : string?
  revision : exact-nonnegative-integer? = 1
Converts an immutable backend-schema snapshot into a validated Keel app-schema?. Rivet Void maps to Keel Unit, Any to Value, and named Records and Enums to references. RVT1 v1 Error frames carry diagnostic strings rather than typed application errors, so projected commands intentionally publish an empty error-code list.

procedure

(current-backend-app-schema #:id id    
  [#:revision revision]) → any/c
  id : string?
  revision : exact-nonnegative-integer? = 1
Projects the declarations currently registered in the backend.

4.3 Serving an Embedded Connection🔗ℹ

procedure

(serve in    
  out    
  [#:max-pending-requests max-pending-requests    
  #:max-outgoing-frames max-outgoing-frames]) → void?
  in : input-port?
  out : output-port?
  max-pending-requests : exact-positive-integer? = 1024
  max-outgoing-frames : exact-positive-integer? = 64
Runs the RVT1 backend over binary ports. Requests execute concurrently within the configured bound, while outgoing responses and events use bounded backpressure.

procedure

(serve-fds input-fd    
  output-fd    
  [#:max-pending-requests max-pending-requests    
  #:max-outgoing-frames max-outgoing-frames]) → void?
  input-fd : exact-integer?
  output-fd : exact-integer?
  max-pending-requests : exact-positive-integer? = 1024
  max-outgoing-frames : exact-positive-integer? = 64
Adapts native file descriptors to binary ports and calls serve.

Receives each structured diagnostic record emitted by the backend. The default discards records: embedded desktop processes do not necessarily own a console, and the first stderr write from a Windows GUI-subsystem process can allocate a visible console window. Applications that want backend diagnostics install a sink backed by their structured logger; records use the rivet.diagnostic.v1 schema.

procedure

(backend-schema) → hash?

Returns one immutable, data-only snapshot with 'rpcs, 'events, 'states, 'records, and 'enums entries. This is the supported reflection boundary for code generation and tooling; registry structs and mutable State cells are private.

procedure

(rpc-schema) → list?

Returns the registered RPC schema used by code generation.

procedure

(event-schema) → list?

Returns the registered event schema.

procedure

(state-schema) → list?

Returns the registered state schema.

procedure

(record-schema) → list?

Returns the registered Record schema.

procedure

(enum-schema) → list?

Returns the registered Enum schema.

4.4 RVT1 Framing and the Value Codec🔗ℹ

 (require rivet/protocol) package: rivet

Applications normally reach the wire through serve and generated clients. This module is the framing layer underneath: it is public because debuggers, protocol fuzzers, and alternative transports consume exactly the same bytes, and because the transport limits are the contract between an application backend and its host.

Every frame carries the RVT1 magic, the protocol version, a message type, an unsigned 64-bit identifier, and a payload. Payloads use a small tagged value codec that covers the RVT1 value grammar; framing and the value codec are independent so later grammar revisions cannot change transport semantics.

struct

(struct frame (type id payload))

  type : exact-integer?
  id : exact-nonnegative-integer?
  payload : bytes?
#:transparent] { One wire frame. type is one of the message:hello through message:shutdown constants, and id ranges from 0 through 264-1.}

procedure

(write-frame f [out]) → void?

  f : frame?
  out : output-port? = (current-output-port)
Validates the message type, identifier, and payload length, then writes the frame. Overlong payloads and out-of-range identifiers are rejected before any bytes reach the port.

procedure

(read-frame [in]) → (or/c frame? eof-object?)

  in : input-port? = (current-input-port)
Reads exactly one frame, validating its version, type, identifier, and payload length. Returns eof at a clean stream boundary.

procedure

(encode-value value) → bytes?

  value : any/c
Encodes one value using the RVT1 tagged value codec. Depth, node count, and encoded size are bounded; use Bytes instead of huge Lists for bulk data, because a flat List inside one legal frame can still expand to far more memory as decoded objects.

procedure

(decode-value payload) → any/c

  payload : bytes?
Decodes bytes produced by encode-value. Malformed tags, excessive depth, and excessive node counts are rejected instead of allocating.

The RVT1 protocol version written into every frame and enforced on read.

The largest accepted frame payload: 64 MiB.

The maximum nesting depth accepted by the value codec.

The maximum number of value nodes, including the root, decoded or encoded per payload.

The host greeting message type.
A client request; the identifier correlates it with a response.
A successful reply to a message:request.
A failure reply carrying a diagnostic string.
A backend-pushed event.
Cancels a pending request by identifier.
Requests orderly backend shutdown.

4.5 Application Resources🔗ℹ

 (require rivet/resources) package: rivet

Locates the read-only application resource directory staged by the build. The same API answers for development layouts, installed .app bundles, MSI installs, and Linux prefix layouts, so backends never hardcode platform resource paths.

parameter

(current-resource-root) → (or/c #f path-string?)

(current-resource-root root) → void?
  root : (or/c #f path-string?)
Overrides resource discovery, for hosts with a non-standard layout. When unset, resource-root searches the locations derived from the current executable.

procedure

(resource-root) → path?

Returns the existing resource root, checking a configured or derived location. Raises when no candidate directory exists, so a mis-staged application fails at startup instead of at first use.

procedure

(resource-path piece ...) → path?

  piece : path-string?
Builds a path inside the resource root. Components must be relative and must not contain . or .. segments; traversal attempts are rejected.