Skip to main content

Protobuf API Reference

Complete reference for all CitadelMesh Protobuf message types


Overview

CitadelMesh uses Protocol Buffers (Protobuf) for all internal communication. This provides:

  • Type safety: Strongly typed messages across languages
  • Performance: 10x smaller and faster than JSON
  • Versioning: Built-in schema evolution
  • Language agnostic: Python ↔ .NET ↔ TypeScript seamlessly

All Protobuf schemas are located in: proto/citadel/v1/


Schema Files

events.proto - Event Messages

Security Events:

message SecurityIncident {
string incident_id = 1;
string location = 2;
string description = 3;
IncidentSeverity severity = 4;
google.protobuf.Timestamp timestamp = 5;
IncidentStatus status = 6;
string assigned_to = 7;
}

enum IncidentSeverity {
SEVERITY_UNSPECIFIED = 0;
LOW = 1;
MEDIUM = 2;
HIGH = 3;
CRITICAL = 4;
}

enum IncidentStatus {
STATUS_UNSPECIFIED = 0;
OPEN = 1;
INVESTIGATING = 2;
RESOLVED = 3;
CLOSED = 4;
}

HVAC Events:

message HVACEvent {
string zone_id = 1;
double temperature_f = 2;
double setpoint_f = 3;
HVACMode mode = 4;
google.protobuf.Timestamp timestamp = 5;
}

enum HVACMode {
MODE_UNSPECIFIED = 0;
OFF = 1;
HEATING = 2;
COOLING = 3;
AUTO = 4;
}

Occupancy Events:

message OccupancyEvent {
string zone_id = 1;
int32 occupant_count = 2;
bool is_occupied = 3;
google.protobuf.Timestamp timestamp = 4;
}

commands.proto - Control Commands

Door Control:

message DoorCommand {
string door_id = 1;
DoorAction action = 2;
int32 duration_seconds = 3;
string reason = 4;
string requested_by = 5;
google.protobuf.Timestamp timestamp = 6;
}

enum DoorAction {
ACTION_UNSPECIFIED = 0;
UNLOCK = 1;
LOCK = 2;
STATUS_QUERY = 3;
}

HVAC Control:

message HVACCommand {
string zone_id = 1;
double setpoint_f = 2;
HVACMode mode = 3;
string reason = 4;
string requested_by = 5;
google.protobuf.Timestamp timestamp = 6;
}

telemetry.proto - System Metrics

message AgentHealth {
string agent_id = 1;
AgentStatus status = 2;
google.protobuf.Timestamp last_heartbeat = 3;
int32 events_processed = 4;
double cpu_usage_percent = 5;
int64 memory_usage_bytes = 6;
}

enum AgentStatus {
STATUS_UNSPECIFIED = 0;
HEALTHY = 1;
DEGRADED = 2;
UNHEALTHY = 3;
OFFLINE = 4;
}

Usage Examples

Python

Import generated code:

from citadel.v1 import events_pb2, commands_pb2
from google.protobuf.timestamp_pb2 import Timestamp

Create a security incident:

incident = events_pb2.SecurityIncident(
incident_id="INC-2025-001",
location="Lobby Main Door",
description="Unauthorized access attempt",
severity=events_pb2.IncidentSeverity.MEDIUM,
timestamp=Timestamp().GetCurrentTime(),
status=events_pb2.IncidentStatus.OPEN
)

# Serialize to bytes
data = incident.SerializeToString()

# Deserialize from bytes
incident2 = events_pb2.SecurityIncident()
incident2.ParseFromString(data)

Create a door command:

command = commands_pb2.DoorCommand(
door_id="DOOR_LOBBY_01",
action=commands_pb2.DoorAction.UNLOCK,
duration_seconds=30,
reason="Authorized by security officer",
requested_by="security-agent",
timestamp=Timestamp().GetCurrentTime()
)

TypeScript

Import generated code:

import { SecurityIncident, IncidentSeverity, IncidentStatus } from './generated/events';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';

Create a security incident:

const incident = new SecurityIncident({
incidentId: 'INC-2025-001',
location: 'Lobby Main Door',
description: 'Unauthorized access attempt',
severity: IncidentSeverity.MEDIUM,
timestamp: Timestamp.fromDate(new Date()),
status: IncidentStatus.OPEN
});

// Serialize to bytes
const bytes = incident.serialize();

// Deserialize from bytes
const incident2 = SecurityIncident.deserialize(bytes);

.NET (C#)

Import generated code:

using Citadel.V1;
using Google.Protobuf.WellKnownTypes;

Create a security incident:

var incident = new SecurityIncident
{
IncidentId = "INC-2025-001",
Location = "Lobby Main Door",
Description = "Unauthorized access attempt",
Severity = IncidentSeverity.Medium,
Timestamp = Timestamp.FromDateTime(DateTime.UtcNow),
Status = IncidentStatus.Open
};

// Serialize to bytes
byte[] data = incident.ToByteArray();

// Deserialize from bytes
var incident2 = SecurityIncident.Parser.ParseFrom(data);

Schema Evolution Rules

Backward Compatible Changes ✅

Safe to add:

  • New message types
  • New fields (always assign new field numbers)
  • New enum values
// Version 1
message DoorCommand {
string door_id = 1;
DoorAction action = 2;
}

// Version 2 (backward compatible)
message DoorCommand {
string door_id = 1;
DoorAction action = 2;
string reason = 3; // NEW: Optional field
int32 duration_seconds = 4; // NEW: Optional field
}

Breaking Changes ❌

Never do:

  • Change field numbers
  • Change field types
  • Remove required fields
  • Rename message types
// BAD: Breaking change
message DoorCommand {
string door_id = 1;
int32 action = 2; // Changed from enum to int32 ❌
}

CloudEvents Integration

All Protobuf messages are wrapped in CloudEvents envelopes:

{
"specversion": "1.0",
"type": "citadel.security.incident",
"source": "spiffe://citadel.mesh/security-agent",
"id": "a7b3c9d4-e8f2-4a5b-9c7d-1e3f5a8b2c6d",
"time": "2025-10-01T14:23:45Z",
"datacontenttype": "application/protobuf",
"data": "<base64-encoded SecurityIncident>"
}

Python example:

from cloudevents.http import CloudEvent
from citadel.v1 import events_pb2
import base64

# Create Protobuf message
incident = events_pb2.SecurityIncident(...)

# Wrap in CloudEvent
event = CloudEvent({
"type": "citadel.security.incident",
"source": "spiffe://citadel.mesh/security-agent",
"datacontenttype": "application/protobuf",
"data": base64.b64encode(incident.SerializeToString()).decode()
})

Code Generation

Python

# Install tools
pip install grpcio-tools

# Generate code
python -m grpc_tools.protoc \
--python_out=src/generated \
--grpc_python_out=src/generated \
--proto_path=proto \
proto/citadel/v1/*.proto

Generated files:

  • events_pb2.py - Message types
  • events_pb2_grpc.py - gRPC services (if defined)

TypeScript

# Install tools
npm install --save-dev @bufbuild/protoc-gen-es

# Generate code
npx protoc \
--es_out=src/generated \
--es_opt=target=ts \
--proto_path=proto \
proto/citadel/v1/*.proto

Generated files:

  • events_pb.ts - Message types and serialization

.NET (C#)

Add to .csproj:

<ItemGroup>
<Protobuf Include="proto/citadel/v1/*.proto" GrpcServices="Client" />
<PackageReference Include="Grpc.Tools" Version="2.62.0" PrivateAssets="All" />
<PackageReference Include="Google.Protobuf" Version="3.26.0" />
</ItemGroup>

Generated automatically during build:

  • Events.cs - Message types
  • EventsGrpc.cs - gRPC services (if defined)

Validation

Field Constraints

Use buf for validation:

# buf.yaml
version: v1
lint:
use:
- DEFAULT
enum_zero_value_suffix: _UNSPECIFIED
rpc_allow_same_request_response: false

Runtime Validation

Python with Pydantic:

from pydantic import BaseModel, validator

class DoorCommandModel(BaseModel):
door_id: str
action: int
duration_seconds: int

@validator('duration_seconds')
def validate_duration(cls, v):
if v < 0 or v > 300:
raise ValueError('duration must be 0-300 seconds')
return v

See Also


🏰 Use Protobuf for type-safe, efficient communication across CitadelMesh.

Last updated: October 2025