Data exchange and contracts

Applications connected to the RTI exchange messages on named channels. The message payload can be as simple as plain text, structured as JSON, or encoded as a typed Protocol Buffers message. As an integration grows, an Inhumate contract can collect the message definitions, channel names, and other shared constants into one explicit, versioned agreement between applications.

Choosing a data format

There is no single format that is right for every channel. Choose the simplest format that makes the data sufficiently clear and reliable:

  • Plain text is useful for experiments, simple notifications, and data intended primarily for people to read.
  • JSON works well for structured data that is still evolving, or when interoperability and easy inspection are more important than strict typing.
  • Protocol Buffers (Protobuf) define a schema for the data. They are a good fit for stable application interfaces, efficient state updates, and communication between applications written in different languages.

Regardless of format, the channel name and the payload format form an agreement. Publishers and subscribers must agree on what a channel means, what data it carries, and how that data changes over time. A name such as vehicle/state is helpful, but on its own it does not say which fields are available, which units they use, or which message version a subscriber should expect.

Protobuf schemas

A .proto file describes the structure of a message: its fields, types, enumerations, and nested messages. From the same definition, Protobuf tooling creates language-specific types that producers and consumers can use to encode and decode the message.

This gives applications a shared vocabulary and makes many mismatches visible during development. It also lets a schema evolve compatibly, provided field numbers and changes are managed carefully. The Protobuf language guide describes the schema language and its compatibility rules.

A Protobuf schema defines the payload, but a complete data exchange agreement usually includes more:

  • Which channel carries the message?
  • Is the channel intended for state updates, events, requests, or responses?
  • Which channel names and other constants must every application use?
  • Which version of the shared definitions does an application implement?

Inhumate contracts

An Inhumate contract packages these related decisions as a reusable, versioned definition. A contract can contain:

  • Protobuf message definitions
  • channel names and the message type associated with each channel
  • shared constants and groups of constants
  • references to other contracts whose definitions it reuses

Language-specific bindings generated from a contract give applications the same message types, channel names, and constants. This reduces duplicated strings and hand-written mappings, and makes the interface between independently developed applications easier to discover, discuss, and review.

Contracts do not require every exchange to use Protobuf. Untyped channels can still carry text, JSON, binary data, or another agreed format. The purpose of a contract is to make the parts of the agreement that should be shared explicit and keep them together.

The Inhumate Suite itself is described using contracts. The RTI contract defines infrastructure communication such as clients, commands, measurements, and runtime control. The Gensim contract defines common simulation concepts such as entities, positions, geometry, events, and injects. These contracts are useful examples when designing a project-specific information model.

Designing an exchange

Start from the meaning and lifecycle of the data rather than from the available fields in one application. Decide who owns the information, who publishes it, who consumes it, and whether it represents current state or an event that occurred.

Keep data with different meanings or update rates in separate messages when that makes subscriptions clearer or avoids repeatedly sending slow-changing values. Choose channel names that describe their purpose, and document important semantics that a type alone cannot express, such as units, coordinate systems, ownership, update frequency, and request-response behavior.

Once several applications depend on those decisions, place the shared definitions in a contract and version it deliberately. The contract then becomes the common reference for the integration, while each application remains free to implement its internal model in the way that suits it best.


Copyright © Inhumate AB 2026