Contract tool
The Inhumate contract tool generates language-specific bindings from an Inhumate contract. The generated code contains the contract’s Protobuf message types, channel names, and shared constants, giving applications written in different languages a common interface for exchanging data.
The tool can generate TypeScript, Python, C#, and C++. It downloads the appropriate Protobuf compiler when necessary, so you do not normally need to install protoc separately.
If Node.js is available, the simplest way to run the tool is with npx:
npx inhumate-contract --help
Standalone executables are also available from the contract tool releases and Inhumate Downloads.
A minimal custom contract
A contract is a directory containing a contract.yml file and, when it defines Protobuf messages, a directory of .proto files. For example:
vehicle-contract/
├── contract.yml
└── proto/
└── VehicleState.proto
The contract.yml identifies the contract and connects channel names to message types:
id: example.vehicle
name: Vehicle
protobuf:
root: proto
channels:
vehicleState:
name: vehicle/state
type: VehicleState
The corresponding proto/VehicleState.proto defines the data carried by the channel:
syntax = "proto3";
package example.vehicle.proto;
option csharp_namespace = "Example.Vehicle.Proto";
message VehicleState {
string id = 1;
double speed = 2;
bool lights_on = 3;
}
This small contract says that vehicle/state carries a VehicleState message. Generated bindings let applications refer to both the channel and its message type using names appropriate for their language, rather than duplicating the channel string and serialization setup in every application.
Contracts can also declare constants, untyped channels, and imports of other contracts. Start with the definitions applications genuinely need to share; the contract can evolve as the integration grows.
Add the contract to a project
Create an inhumate-contract.yml in the root of each consuming project. It tells the tool where the contract comes from, which language to generate, and where the generated files belong. A source may be a local path, a Git URL, or a released Inhumate contract such as inhumate:gensim@1.0.0.
The examples below assume that vehicle-contract is next to the application project. Adjust source and output to match your layout.
# inhumate-contract.yml
generate:
- source: ../vehicle-contract
language: python
output: src/vehicle_contract
Run generation before packaging or starting the application. A minimal Makefile target could be:
generate:
npx inhumate-contract
build: generate
python -m build
The output directory is a Python package containing the generated message types and constants.
# inhumate-contract.yml
generate:
- source: ../vehicle-contract
language: typescript
output: src/generated/vehicle
Install the tool as a development dependency and run it before the normal build:
npm install --save-dev inhumate-contract
{
"scripts": {
"generate": "inhumate-contract",
"prebuild": "npm run generate",
"build": "tsc"
}
}
# inhumate-contract.yml
generate:
- source: ../vehicle-contract
language: csharp
output: src/Generated
Run the tool before compilation with a target in the application’s .csproj file:
<Target Name="GenerateContract" BeforeTargets="BeforeCompile">
<Exec Command="npx inhumate-contract" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
SDK-style .NET projects include generated .cs files under the project directory automatically.
# inhumate-contract.yml
generate:
- source: ../vehicle-contract
language: cpp
output: generated
protobufVersion: 3.11.2
The generated C++ must use the same Protobuf version as the runtime linked by the application. Set protobufVersion accordingly, then invoke generation from CMake before compiling your target:
add_custom_target(generate_contract
COMMAND npx inhumate-contract
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
add_dependencies(my_application generate_contract)
target_include_directories(my_application PRIVATE generated)
Add the generated .pb.cc files to the target and link the matching Protobuf runtime as part of the normal C++ build.
Generation and versioning
Running inhumate-contract with no arguments processes the project’s inhumate-contract.yml. The operation is idempotent: an inhumate-contract.lock file records the inputs and outputs, and later runs do nothing while the generated files and configuration remain current. This makes it safe to place generation directly before compilation.
For a contract stored in Git, its version comes from its Git tag rather than from contract.yml. Consumers should pin a released version, for example inhumate:gensim@1.0.0, and update that version deliberately when they are ready to adopt changes to the shared interface.
Use inhumate-contract sync --force when you intentionally need to regenerate all configured outputs. For the complete command and contract format reference, see the contract tool repository.