Protocol Versioning
The protocolVersion field in every ANCP message enables the platform to evolve its message format over time without breaking nodes or agents that have not yet been updated.
The protocolVersion Field
Every ANCP envelope carries a protocolVersion string in the header. This field tells the receiving router and handler which version of the ANCP specification this message conforms to. Routers use it to select the correct deserializer and to decide whether a compatibility shim is needed.
{
"id": "msg-uuid",
"type": "Command",
"protocolVersion": "1.0", // ← always present, always a string
// ... other fields ...
}
Version Format
ANCP uses a MAJOR.MINOR versioning scheme:
| Component | When it increments | Backward compatible? |
|---|---|---|
| MAJOR | A breaking change is introduced — required fields added, field semantics changed, or a type is removed. | No — consumers must be updated before accepting new MAJOR messages. |
| MINOR | A non-breaking addition — new optional fields, new optional message types, or additive changes to the payload convention. | Yes — consumers that read only the fields they know about continue to work correctly. |
All messages in the current BizFirstGO platform use "protocolVersion": "1.0". ANCP 1.1 (adding optional message signing) is planned. ANCP 2.0 would be a major version with advance deprecation notice of at least 6 months.
Version History
| Version | Released | Status | Changes |
|---|---|---|---|
1.0 | 2026-01 | Current | Initial release. Core envelope, four message types, addressing scheme, tenant isolation. |
1.1 | Planned Q3 2026 | Planned | Optional Ed25519 message signing (signature field). Backward compatible — unsigned messages remain valid. |
2.0 | TBD | Future | Breaking changes TBD. Will carry 6-month deprecation window for 1.x. |
Router Behaviour for Received Messages
Known Version (exact match)
The router deserializes and processes the message using the matching specification.
Known MAJOR, Higher MINOR
The router applies forward compatibility: it reads the fields it knows about and ignores unknown fields. This is safe for MINOR version increments because they only add optional fields.
// Router logic (pseudocode)
if (message.protocolVersion.major === SUPPORTED_MAJOR) {
// Safe to process — ignore unknown fields
processWithKnownFields(message);
} else {
// Unknown major version — reject with explanation
rejectWithVersion(message, SUPPORTED_MAJOR);
}
Unknown MAJOR
If the MAJOR version is not supported by the router, the message is rejected with a PROTOCOL_VERSION_UNSUPPORTED error returned to the sender (if the sender is reachable via a Response). The sender must downgrade or the router must be updated.
Sender Responsibility
Message producers must always set protocolVersion to the version they are targeting. Do not omit it, do not default it dynamically at runtime — set it explicitly in the message construction code so upgrades are intentional and visible in code review.
// TypeScript — building an ANCP envelope
const envelope: AncpEnvelope = {
id: generateUuid(),
type: 'Command',
source: AncpAddress.node({ tenantId, flowId, nodeId }),
destination: AncpAddress.node({ tenantId, flowId, nextNodeId }),
tenantId: tenantId,
timestamp: new Date().toISOString(),
protocolVersion: '1.0', // ← explicit, never computed
payload: { action: 'proceed', data: outputData }
};
Migration Strategy for Breaking Changes
When ANCP 2.0 (or any future MAJOR version) is released, the platform runs both versions in parallel during a transition window. The router is updated first to accept both MAJOR versions. Nodes and agents are then updated incrementally. Only after all producers and consumers have migrated is support for the old MAJOR version removed.
Announce + Release New MAJOR
6-month deprecation notice. Release 1.x compatibility window alongside 2.0.
Update Router
Router accepts both old and new MAJOR. Applies compatibility shims for old messages if needed.
Update Producers
All message-sending nodes and agents upgraded to emit new MAJOR. Old consumers still work via shim.
Update Consumers
All message-receiving nodes and agents upgraded to accept new MAJOR natively.
Remove Old MAJOR Support
After all producers and consumers are on the new MAJOR, the router stops accepting old MAJOR messages.
Detecting Version in Handlers
Handler code that needs to branch on version should read protocolVersion from the envelope and handle explicitly:
// C# — version-aware handler
public async Task HandleAsync(AncpEnvelope envelope)
{
var version = Version.Parse(envelope.ProtocolVersion);
if (version.Major == 1)
{
await HandleV1Async(envelope);
}
else
{
_logger.LogWarning("Unsupported ANCP major version {Version}", version.Major);
// Return a Response with error status rather than throwing
await SendErrorResponseAsync(envelope, "UNSUPPORTED_VERSION");
}
}
Read the version from a configuration or constant — never scatter "1.0" literals through routing and handler code. When the platform version changes, you want a single place to update, not a grep-and-replace across dozens of files.