proto is the canonical home for cross-service protobuf definitions in the
EvalOps ecosystem.
It holds .proto files for the shared contracts that multiple services depend
on, generates type-safe Go and TypeScript packages from those definitions, and
enforces schema compatibility through CI. Services import the generated
packages instead of maintaining their own hand-written struct copies.
- Provide a single source of truth for cross-service API types.
- Generate Go, TypeScript, and Python packages from one set of definitions.
- Catch breaking contract changes at compile time, not in production.
- Keep wire encoding efficient with protobuf binary format.
- Support Connect-RPC service definitions for typed cross-service calls.
- This repo does not hold service-internal types that never cross a service boundary.
- This repo does not define the external REST/OpenAPI surface of any service.
- This repo does not own service implementation or business logic.
- This repo does not replace service-local proto definitions for internal RPC (e.g. gate's proxy protocol protos or chat's conversation streaming protos).
| Package | Description | Consumers |
|---|---|---|
identity/v1 |
Token introspection, organizations, members, API keys, sessions | gate, chat, llm-gateway, service-runtime, identity |
meter/v1 |
Usage recording, querying, cost attribution | llm-gateway, chat, platform |
audit/v1 |
Audit event recording, actors, resources, querying, export | llm-gateway, chat, gate, platform |
memory/v1 |
Semantic memory storage, recall, embeddings, consolidation | chat, ensemble, platform |
approvals/v1 |
Approval workflows, policies, decisions, habits, escalation | approvals, ensemble, maestro, chat, objectives |
config/v1 |
Shared runtime config snapshots and feature-flag state | deploy, llm-gateway, maestro, gate |
connectors/v1 |
Integration connections, health, source-of-truth, capabilities | connectors, pipeline, parker, entities, objectives |
entities/v1 |
Canonical entity resolution, search, links, correlation graph | entities, pipeline, parker, connectors, ensemble |
governance/v1 |
Safety evaluation, PII detection, retention, legal holds | governance, approvals, objectives, ensemble, chat |
notifications/v1 |
Notification delivery, preferences, channels, status | notifications, approvals, objectives, pipeline, parker |
objectives/v1 |
Objective lifecycle, wake scheduling, provenance, mutations | objectives, approvals, governance, pipeline, parker |
skills/v1 |
Shared skill registry, versions, search, import/export | skills, chat, ensemble, maestro, pipeline |
events/v1 |
Shared NATS event envelope and change journal payloads | service-runtime, pipeline, parker |
tap/v1 |
Normalized tap webhook payloads and field-level diffs | ensemble-tap, pipeline |
prompts/v1 |
Prompt versioning, deployment tracking, eval linkage, resolution | prompts, llm-gateway, fermata, maestro, ensemble |
flowchart TD
Proto[evalops/proto]
Identity[identity]
Meter[meter]
Audit[audit]
Memory[memory]
Approvals[approvals]
Connectors[connectors]
Entities[entities]
Governance[governance]
Notifications[notifications]
Objectives[objectives]
Skills[skills]
Gateway[llm-gateway]
Chat[chat]
Gate[gate]
Ensemble[ensemble]
SRT[service-runtime]
Proto -->|identity/v1| Identity
Proto -->|identity/v1| Gateway
Proto -->|identity/v1| Chat
Proto -->|identity/v1| Gate
Proto -->|identity/v1| SRT
Proto -->|meter/v1| Meter
Proto -->|meter/v1| Gateway
Proto -->|meter/v1| Chat
Proto -->|audit/v1| Audit
Proto -->|audit/v1| Gateway
Proto -->|audit/v1| Chat
Proto -->|audit/v1| Gate
Proto -->|memory/v1| Memory
Proto -->|memory/v1| Chat
Proto -->|memory/v1| Ensemble
Proto -->|approvals/v1| Approvals
Proto -->|approvals/v1| Chat
Proto -->|approvals/v1| Ensemble
Proto -->|approvals/v1| Objectives
Proto -->|connectors/v1| Connectors
Proto -->|connectors/v1| Pipeline
Proto -->|connectors/v1| Parker
Proto -->|connectors/v1| Entities
Proto -->|entities/v1| Entities
Proto -->|entities/v1| Pipeline
Proto -->|entities/v1| Parker
Proto -->|entities/v1| Ensemble
Proto -->|governance/v1| Governance
Proto -->|governance/v1| Approvals
Proto -->|governance/v1| Objectives
Proto -->|governance/v1| Chat
Proto -->|notifications/v1| Notifications
Proto -->|notifications/v1| Approvals
Proto -->|notifications/v1| Objectives
Proto -->|objectives/v1| Objectives
Proto -->|objectives/v1| Approvals
Proto -->|objectives/v1| Governance
Proto -->|skills/v1| Skills
Proto -->|skills/v1| Chat
Proto -->|skills/v1| Ensemble
Proto -->|skills/v1| Maestro[maestro]
Proto -->|events/v1| SRT
Proto -->|events/v1| Parker[Parker]
Proto -->|events/v1| Pipeline[Pipeline]
Proto -->|tap/v1| EnsembleTap[ensemble-tap]
Proto -->|tap/v1| Pipeline
Proto -->|prompts/v1| Prompts[prompts]
Proto -->|prompts/v1| Gateway
Proto -->|prompts/v1| Fermata[fermata]
Proto -->|prompts/v1| Maestro[maestro]
Proto -->|prompts/v1| Ensemble
flowchart LR
subgraph Before
GW1[llm-gateway\nhand-written IntrospectionResult\n6 fields]
SRT1[service-runtime\nhand-written IntrospectionResult\n11 fields]
Chat1[chat\nhand-written issueServiceTokenResponse]
end
subgraph After
Proto2[evalops/proto\nidentity/v1/tokens.proto\nIntrospectResponse\n15 fields]
GW2[llm-gateway\nimports identityv1]
SRT2[service-runtime\nimports identityv1]
Chat2[chat\nimports identityv1]
Proto2 --> GW2
Proto2 --> SRT2
Proto2 --> Chat2
end
import (
identityv1 "github.com/evalops/proto/gen/go/identity/v1"
meterv1 "github.com/evalops/proto/gen/go/meter/v1"
auditv1 "github.com/evalops/proto/gen/go/audit/v1"
memoryv1 "github.com/evalops/proto/gen/go/memory/v1"
promptsv1 "github.com/evalops/proto/gen/go/prompts/v1"
)
// Use generated types directly
req := &meterv1.RecordUsageRequest{
TeamId: "team-platform",
AgentId: "agent_writer",
Surface: "maestro",
EventType: "llm.completion",
Model: "claude-opus-4.6",
Provider: "anthropic",
InputTokens: 1250,
OutputTokens: 340,
TotalCostUsd: 0.0423,
RequestId: "req_789",
}
// Resolve the active prompt version at inference time
resolveReq := &promptsv1.ResolveRequest{
Name: "sdr-outreach",
Surface: "ensemble",
Env: "production",
}import (
meterv1connect "github.com/evalops/proto/gen/go/meter/v1/meterv1connect"
"connectrpc.com/connect"
)
client := meterv1connect.NewMeterServiceClient(
http.DefaultClient,
"https://meter.internal",
)
resp, err := client.RecordUsage(ctx, connect.NewRequest(req))import { RecallRequest } from "@evalops/proto/memory/v1/memory_pb";
import { CloudEventSchema } from "@evalops/proto/events/v1/cloudevent_pb";proto also publishes the generated TypeScript contract surface from the repo
root as @evalops/proto.
Current package surface:
- protobuf-es message modules like
@evalops/proto/memory/v1/memory_pb - metering contracts like
@evalops/proto/meter/v1/meter_pb - shared event contracts like
@evalops/proto/events/v1/cloudevent_pb
The generated _connect descriptors remain checked into the repo, but the
published package currently exports the stable _pb modules only. That keeps
the registry surface aligned with the protobuf-es runtime shape we validate in
CI today.
CI validates the package on pull requests, and the NPM Publish workflow packs
and publishes it automatically on main when Artifact Registry or
NPM_PUBLISH_NPMRC publish credentials are configured.
events/v1.CloudEvent is the canonical typed envelope for the shared internal
bus.
- Set
subjectto the actual bus subject when the transport has one. This keeps NATS routing context visible without forcing consumers to infer it fromtype. - Keep
dataas a typed message packed ingoogle.protobuf.Any; do not fall back to service-local ad hoc payload blobs. - Prefer
data_content_type=application/protobuffor the canonical envelope. Some services still emit structured CloudEvents JSON withspecversion/datacontenttypeand JSONdatawhile they migrate. Consumers should tolerate both shapes until the bus converges, but new typed contracts should start fromevents/v1.CloudEvent. - Use
github.com/evalops/proto/eventhelpersto build and unpack canonical envelopes instead of re-implementingAnypacking, protojson marshaling, and type assertions in each service. The package exportsNewCloudEvent,NewChange,MarshalProtoJSON,UnpackChange, andUnpackTapEventData.NewCloudEventalso stampsextensions.dataschema=buf.build/evalops/proto/<message>so published envelopes stay self-describing across service boundaries. - Use
config/v1.FeatureFlagSnapshotwhen a repo needs a shared on-disk or over-the-wire representation for lightweight runtime config or feature flags. The initial production deploy bundle publishes that schema as canonical protojson instead of a repo-local YAML shape.
Prerequisites:
- buf v1.50+
- Go 1.22+
# Lint proto files
make lint
# Check for breaking changes against main
make breaking
# Regenerate Go and TypeScript packages
make generate
# Run contract tests for generated packages
make test
# Clean and regenerate from scratch
make clean generateFixture-backed contract examples live alongside the owning proto package under
proto/<service>/v1/testdata/. Keep those JSON examples aligned with the
canonical protojson field names because make test unmarshals them through the
generated types.
High-risk boundary fixtures belong there too. The current catalog includes
canonical events/v1.CloudEvent examples for pipeline.changes.activity.create
with outcome=replied and parker.changes.work_relationship.update with
status=terminated. It also includes a Tap -> Pipeline boundary fixture for
ensemble.tap.hubspot.deal.updated with a qualified stage change and a real
UUID tenant, so downstream consumers can pin the semantics they depend on
instead of only the wire shape.
Go consumers can import those fixtures directly from
github.com/evalops/proto/contractfixtures instead of copying JSON into each
repo. For example, contractfixtures.Read(contractfixtures.EventPipelineActivityCreateReplied)
returns the canonical protojson fixture bytes that service-side tests can decode
and compare against their own publisher or consumer behavior.
For typed helpers, use contractfixtures.LoadChangeFixture(...) or
contractfixtures.LoadTapFixture(...) to unpack the canonical
events/v1.CloudEvent envelope and its typed payload in one call.
- Create
proto/<service>/v1/<file>.proto. - Set the Go package option:
option go_package = "github.com/evalops/proto/gen/go/<service>/v1;<service>v1";
- Run
make lintto validate. - Run
make generateto produce Go and TypeScript packages. - Commit the
.protofile and generated code together. - After merge, consumers can import the new package immediately.
buf breaking runs on every PR against main. If your change breaks wire
compatibility (renaming a field, changing a field number, removing a field),
the PR will fail CI.
To make a safe change:
- Add new fields with new field numbers. Old consumers ignore unknown fields.
- Deprecate fields with
[deprecated = true]instead of removing them. - If a field must be removed, reserve its number:
reserved 5;
buf.yaml buf module configuration
buf.gen.yaml codegen plugin configuration
proto/ source .proto files
identity/v1/ token introspection, orgs, members, sessions
meter/v1/ usage recording and cost attribution
audit/v1/ audit event recording and querying
memory/v1/ semantic memory storage and recall
testdata/ canonical protojson fixtures for contract tests
approvals/v1/ approval workflows, policies, decisions, habits
config/v1/ runtime config snapshots and feature-flag state
connectors/v1/ integration lifecycle, health, source-of-truth
entities/v1/ canonical entity resolution and search
governance/v1/ safety evaluation, PII detection, retention
notifications/v1/ multi-channel delivery, preferences, status
objectives/v1/ objective lifecycle, provenance, wake scheduling
skills/v1/ shared skill registry and version history
events/v1/ CloudEvent envelope and change journal payloads
testdata/ typed event fixtures for cross-service contracts
tap/v1/ normalized provider event payloads
prompts/v1/ prompt versioning, deployment, eval linkage
gen/ generated code (committed)
go/ Go protobuf + Connect-RPC packages
ts/ TypeScript protobuf-es + Connect-ES packages
.github/workflows/ CI: lint, breaking, generate, build
The CI pipeline runs on every push to main and every PR:
buf lint— validates proto files against the STANDARD rule set.buf breaking— checks for wire-incompatible changes againstmain(PRs only).buf generate— regenerates code and fails if the committed code is stale.go test— verifies the generated Go packages and contract tests pass.
- #1 — bootstrap tracking issue
- evalops/platform#9110 — cross-service protobuf coordination
- evalops/identity#56 — adopt identity proto types
- evalops/meter#30 — adopt meter proto types
- evalops/audit#23 — adopt audit proto types
- evalops/memory#32 — adopt memory proto types
- evalops/service-runtime#24 — shared protobuf event schemas