How the Public Daemon Protocol v4 Handles Schema Revisions: Backward Compatibility via Hello Handshake

The public daemon protocol v4 handles schema revisions through an initial hello handshake where client and daemon exchange schemaRevision values and negotiate the effective revision using Math.min(), ensuring backward compatibility while rejecting obsolete versions below the minimum supported threshold.

The PrimeIntellect-ai/prime-agent repository implements a robust versioning mechanism in its public daemon protocol v4 that prevents communication failures during software updates. By embedding schema revision metadata directly into the connection handshake, the protocol enables seamless interoperability between clients and daemons running different release versions without breaking existing functionality.

The Hello Envelope: Exposing Schema Capabilities

When a client connects to the daemon, both parties immediately transmit a hello envelope that declares their protocol capabilities. This JSON structure contains the critical fields that drive revision negotiation.

In packages/coding-agent/src/modes/daemon/daemon-protocol.ts, the protocol defines the constant DAEMON_SCHEMA_REVISION which represents the current schema version. The hello payload structure follows this pattern:

import { DAEMON_PROTOCOL_VERSION, DAEMON_SCHEMA_REVISION } from "./daemon-protocol";

const helloPayload = {
  protocol: { 
    name: "prime-agent.daemon", 
    version: DAEMON_PROTOCOL_VERSION  // e.g., 4 in the public release
  },
  schemaRevision: DAEMON_SCHEMA_REVISION,  // monotonically increasing integer
  schemaId: `protocol-${DAEMON_PROTOCOL_VERSION}-schema-${DAEMON_SCHEMA_REVISION}-${digest}`,
  // ... additional metadata
};

The schemaId field encodes both the protocol version and schema revision into a canonical string format, enabling quick validation without parsing complex objects. The digest component provides integrity checking for the schema definition itself.

The Negotiation Algorithm: Minimum Revision Selection

The core compatibility logic resides in the daemon's handshake handler, located in packages/coding-agent/src/modes/daemon/daemon-mode.ts. Upon receiving a client's hello message, the daemon calculates the effective schema revision by taking the minimum of the two declared values:

function negotiateRevision(clientHello: HelloMessage): number {
  const clientRev = clientHello.schemaRevision;
  const daemonRev = DAEMON_SCHEMA_REVISION;
  
  // Negotiate to the highest revision both parties understand
  const effectiveRevision = Math.min(clientRev, daemonRev);
  
  if (clientRev < MINIMUM_SUPPORTED_REVISION) {
    throw new Error(`Unsupported schema revision ${clientRev}. Minimum supported: ${MINIMUM_SUPPORTED_REVISION}`);
  }
  
  return effectiveRevision;
}

This Math.min() approach guarantees that both sides operate using the newest schema features available in the older participant's implementation. If the client supports revision 24 but the daemon only supports revision 20, the effective revision becomes 20, and the client must disable features requiring revision 21-24.

Compatibility Guards and Validation

The protocol implements strict boundaries to prevent undefined behavior. The daemon validates the handshake through two primary mechanisms defined in the protocol implementation.

Minimum Revision Enforcement: The daemon maintains a MINIMUM_SUPPORTED_REVISION constant (typically set to 6 in current implementations) and rejects any client advertising a lower value. This prevents connections from obsolete clients that lack critical security patches or protocol fixes.

Schema ID Verification: After computing the effective revision, the daemon reconstructs the expected schemaId string and compares it against the client's declared value. A mismatch indicates schema tampering or version skew, triggering an immediate connection termination.

const expectedSchemaId = `protocol-${DAEMON_PROTOCOL_VERSION}-schema-${effectiveRevision}-${digest}`;
if (clientHello.schemaId !== expectedSchemaId) {
  throw new ProtocolError(`Schema ID mismatch: expected ${expectedSchemaId}, received ${clientHello.schemaId}`);
}

Client-Side Implementation Details

The packages/coding-agent/src/modes/daemon/daemon-client.ts file implements the client-side perspective of this negotiation. When initiating a connection, the client constructs its hello message using the local DAEMON_SCHEMA_REVISION constant, then processes the daemon's response to determine which features remain active.

// Client-side handshake initialization
const envelope = {
  type: "hello",
  payload: {
    protocol: { name: "prime-agent.daemon", version: DAEMON_PROTOCOL_VERSION },
    schemaRevision: DAEMON_SCHEMA_REVISION,
    schemaId: generateSchemaId(DAEMON_PROTOCOL_VERSION, DAEMON_SCHEMA_REVISION)
  }
};

socket.send(JSON.stringify(envelope));

// Processing the daemon's reply
function handleDaemonHello(daemonHello: HelloMessage) {
  const negotiatedRevision = Math.min(
    DAEMON_SCHEMA_REVISION, 
    daemonHello.schemaRevision
  );
  
  // Store for use in subsequent message serialization
  this.activeSchemaRevision = negotiatedRevision;
}

All subsequent command and event processing uses this.activeSchemaRevision to determine field serialization strategies. Newer fields added in later schema revisions are omitted when negotiatedRevision falls below the feature's introduction version.

Summary

  • Schema revisions are exchanged via the hello handshake immediately upon connection establishment in daemon-protocol.ts.
  • Effective revision is calculated using Math.min() between client and daemon values, ensuring both parties use the highest mutually supported version.
  • Daemons enforce minimum revision boundaries to reject obsolete clients that might cause protocol errors or security vulnerabilities.
  • Schema ID strings provide integrity validation by encoding the negotiated protocol version and revision in a canonical format.
  • Implementation spans four key files: daemon-protocol.ts defines constants, daemon-client.ts handles client-side negotiation, daemon-mode.ts implements server-side validation, and daemon-protocol.test.ts verifies compatibility logic.

Frequently Asked Questions

What happens if a client sends a higher schema revision than the daemon supports?

The daemon caps the effective revision to its own DAEMON_SCHEMA_REVISION using Math.min(). The client detects this lower value in the daemon's hello response and must disable any features requiring the newer schema revision. This forward-compatible design allows newer clients to connect to older daemons by gracefully falling back to older behavior.

How does the daemon validate the schema ID during the handshake?

The daemon reconstructs the expected schemaId using the negotiated revision and a precomputed digest of the schema definition located in packages/coding-agent/src/modes/daemon/daemon-protocol.ts. If the client-provided schema ID does not match the reconstructed value, the daemon throws a ProtocolError and terminates the connection, preventing communication with modified or corrupted schema definitions.

Where are the protocol version constants defined in the codebase?

The constants DAEMON_PROTOCOL_VERSION and DAEMON_SCHEMA_REVISION are exported from packages/coding-agent/src/modes/daemon/daemon-protocol.ts. These values are imported by both daemon-client.ts and daemon-mode.ts to ensure consistent versioning across the handshake implementation. The test suite in packages/coding-agent/test/daemon-protocol.test.ts references these constants to verify correct negotiation behavior.

Does the protocol support forward compatibility with future schema revisions?

Yes, the protocol supports forward compatibility through the minimum-based negotiation. When a newer client connects to an older daemon, the effective revision defaults to the daemon's lower value. The client implementation checks the negotiated revision before accessing newer schema features, effectively ignoring unknown fields that would otherwise cause parsing errors. This design pattern is enforced by the test suite covering version skew scenarios.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →