Core Protobuf contracts (generic, reusable message types) shared across Feather gRPC services — packaged for both .NET and PHP.
This repository is the single source of truth for the low-level, domain-agnostic contracts used across Feather. The Protobuf schema in proto/feather/contracts/core/v1/core.proto is compiled into:
- a .NET library published as the
Feather.ContractsNuGet package, - a PHP package (
feather/contracts) with generated message, client and RoadRunner server classes undergen/php/, and - a Protobuf module published to the Buf Schema Registry (
buf.build/feathertools/contracts).
It is designed to be consumed in three ways:
- As a .NET dependency in the
Feather.Grpclibrary, providing the core message types. - As a PHP dependency in the PHP contracts library, providing the same core types.
- Directly in other
.protofiles, by depending on the BSR modulebuf.build/feathertools/contractsand referencing thefeather.contracts.core.v1types.
All messages live in the feather.contracts.core.v1 package (proto/feather/contracts/core/v1/core.proto):
| Message | Purpose |
|---|---|
Error |
Structured error with a name and message. |
CorrelationId |
Request/trace correlation identifier. |
Timestamp |
Unix timestamp in milliseconds. |
Spot |
A zone + bucket location pair. |
Instance |
A single instance identifier. |
Box |
An Instance bound to a Spot. |
SerializedForChunking |
Wrapper (bytes content) for chunking large payloads in streaming gRPC calls. |
Generated namespaces (derived by Buf managed mode from the feather.contracts.core.v1 package):
- .NET:
Feather.Contracts.Core.V1 - PHP:
Feather\Contracts\Core\V1(messages) andFeather\Contracts\Core\V1\GPBMetadata(metadata)
dotnet add package Feather.Contractsopen Feather.Contracts.Core.V1
let error = Error(Name = "NotFound", Message = "Instance not found")Not published to Packagist — consume it as a git VCS repository. Add the repository to your composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/FeatherTools/grpc.contract.core.git"
}
]
}Then require it (use the tag/branch you need):
composer require feather/contracts:dev-mainuse Feather\Contracts\Core\V1\Error;
$error = (new Error())->setName('NotFound')->setMessage('Instance not found');Add the BSR module as a dependency in your buf.yaml:
version: v2
deps:
- buf.build/feathertools/contractsThen import and reference the feather.contracts.core.v1 types:
syntax = "proto3";
import "feather/contracts/core/v1/core.proto";
message Envelope {
feather.contracts.core.v1.CorrelationId correlation_id = 1;
feather.contracts.core.v1.Error error = 2;
}dotnet tool restore
dotnet tool run paket install
./build.sh
composer installThe build is driven by FAKE via build.sh:
./build.sh # default target
./build.sh -t tests no-lint # run tests
./build.sh -t publish no-lint # pack & publish the NuGet packageCommon flags: no-lint, no-clean to skip the respective steps.
proto/feather/contracts/core/v1/core.proto is the source of truth. After editing it:
-
Lint the schema:
buf lint
-
.NET and PHP classes are regenerated with Buf using the remote plugins in
buf.gen.yaml:buf generate
This produces C# under
gen/csharp/(namespaceFeather.Contracts.Core.V1, compiled byContracts.csproj) and PHP message, client and RoadRunner server classes undergen/php/(namespaceFeather\Contracts\Core\V1); both are committed to the repository.buf buildonly compiles the schema to an in-memory image; usebuf generateto emit code.Before opening a PR, run
buf generateand commit the regeneratedgen/files so they stay in sync with the schema in git. -
Publish the module to the Buf Schema Registry:
buf registry login # first time only buf push # publishes buf.build/feathertools/contracts
Buf can decide the generated namespaces two ways, controlled in buf.gen.yaml:
- Managed mode ON (used here) — namespaces are derived from the Protobuf package and injected at generation time, so the
.protostays free of language-specific options. This is Buf's idiomatic default and the right choice when the package (feather.contracts.core.v1) already maps cleanly onto the desired namespaces (Feather.Contracts.Core.V1,Feather\Contracts\Core\V1). - Managed mode OFF — namespaces come from
optionlines written inside the.proto(or plain package-derived protoc defaults). Choose this only when you need a namespace scheme the package can't produce (e.g. aContext.Contracts.Systemlayout that intentionally differs from the package path).
This repository uses managed mode ON with a single override: php_metadata_namespace is pinned to the standard protoc convention GPBMetadata\<Package> (rather than managed mode's <php_namespace>\GPBMetadata default). This keeps the PHP metadata class name compatible with downstream contracts that import core.proto and are generated without managed mode. Any project reusing these contracts should follow the same idea: prefer managed mode on, and only add overrides when a name must interoperate with an external convention.
- File name:
lower_snake_case; messages:UpperCamelCase; fields:lower_snake_case; enum values:UPPER_SNAKE_CASE. - Keep types generic and domain-agnostic — this library holds only reusable primitives.
- Enforced by Buf's
STANDARDlint rule set (seebuf.yaml).
proto/feather/contracts/core/v1/core.proto # Source-of-truth Protobuf schema
buf.yaml # Buf module (buf.build/feathertools/contracts), lint & breaking config
buf.gen.yaml # Buf code generation (managed mode, remote plugins)
Contracts.csproj # .NET package (Feather.Contracts), compiles gen/csharp
composer.json # PHP package (feather/contracts), autoloads gen/php
gen/csharp/ # Generated C# classes (committed, compiled by Contracts.csproj)
gen/php/ # Generated PHP classes (committed, autoloaded by composer)
build/ # FAKE build project (F#)
.github/workflows/ # CI: net-tests, php-tests, proto-lint, net-publish, bsr-publish, pr-check
Publishing the NuGet package is triggered by pushing a semver tag (MAJOR.MINOR.PATCH), which runs the .NET Publish workflow. Update CHANGELOG.md and the <Version> in Contracts.csproj before tagging. Publish the Protobuf module to the BSR with buf push.
