How Prime Agent Maintains Backward Compatibility with Its Daemon Protocol

Prime Agent guarantees backward compatibility through a versioned daemon protocol that uses protocol version stamps, per-command compatibility matrices, and runtime negotiation.

The prime-agent repository implements a sophisticated versioning system for its persistent coding agent daemon. This architecture allows independent evolution of client and daemon components without breaking existing deployments.

Protocol Versioning and Schema Revision

The foundation of compatibility lies in explicit version advertisement. In packages/coding-agent/src/modes/daemon/daemon-protocol.ts, the daemon exports two critical constants:

export const DAEMON_PROTOCOL_VERSION = 7;
export const DAEMON_SCHEMA_REVISION = 16;

These values serve as the contract between components. Protocol version indicates major compatibility requirements, while schema revision tracks incremental field additions that older daemons might not parse.

The Per-Command Compatibility Matrix

Every command type carries structured compatibility requirements through the DaemonCommandCompatibility interface (lines 24-32):

interface DaemonCommandCompatibility {
  minProtocol: number;
  minSchemaRevision?: number;  // optional, for field-level changes
  capability?: string;         // optional feature flag
}

The complete mapping lives in DAEMON_COMMAND_COMPATIBILITY (lines 53-52), which the daemon consults before executing any command. This design isolates breaking changes to specific command types rather than forcing global version bumps.

Runtime Negotiation Flow

The compatibility check operates through a six-step pipeline:

1. Client Envelope Construction

Clients stamp their supported protocol version using createDaemonCommandEnvelope:

const envelope = createDaemonCommandEnvelope(
  command,
  id,
  clientId,
  DAEMON_PROTOCOL_VERSION  // defaults to 7
);

The helper implementation (lines 773-785) embeds version metadata into every command envelope.

2. Daemon Compatibility Resolution

Upon receiving a command, the daemon calls getDaemonCommandCompatibilities() (lines 754-666). This function returns an array of compatibility entries and dynamically injects additional requirements for:

  • Telemetry policy features
  • Prompt admission capabilities

3. Version Comparison

The daemon validates hello.protocol.version from the client against each entry's minProtocol. A client sending version 6 against a command requiring version 7 triggers rejection.

4. Schema Revision Validation

For commands evolving their payload structure—such as mutate_queued_message requiring schema ≥ 15—the daemon checks minSchemaRevision before deserialization.

5. Capability Gating

Certain advanced features require explicit capability advertisement. The session_input_admission capability, for example, must be present before the daemon accepts related commands.

6. Graceful Error Handling

Incompatible commands receive explicit rejection:

// Daemon side rejection
throw new Error(`Unknown daemon command: ${command.type}`);

// Client side detection
if (isUnknownDaemonCommandError(err, envelope.command.type)) {
  // Implement fallback strategy
}

The isUnknownDaemonCommandError() helper (lines 998-1000 in daemon-client.ts) enables clients to distinguish protocol errors from other failure modes.

Code Examples

Creating a Command Envelope

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

const cmd = {
  type: "prompt",
  activeSessionId: "sess-1",
  message: "Refactor this function"
};

const envelope = createDaemonCommandEnvelope(
  cmd,
  "cmd-123",      // command ID
  "client-42"     // client identifier
);

Implementing Compatibility Checks

import { getDaemonCommandCompatibilities } from "./daemon-protocol";

function handleCommand(cmd: DaemonCommand, clientHello: HelloMessage): void {
  const compatList = getDaemonCommandCompatibilities(cmd);
  
  for (const { minProtocol, minSchemaRevision, capability } of compatList) {
    if (clientHello.protocol.version < minProtocol) {
      throw new Error(
        `Protocol version ${clientHello.protocol.version} below required ${minProtocol}`
      );
    }
    
    if (minSchemaRevision && clientHello.schemaRevision < minSchemaRevision) {
      throw new Error(`Schema revision incompatible`);
    }
    
    if (capability && !clientHello.capabilities.includes(capability)) {
      throw new Error(`Missing required capability: ${capability}`);
    }
  }
  
  // Execute command with validated compatibility
}

Handling Unknown Command Errors

import { isUnknownDaemonCommandError } from "./daemon-client";

async function sendWithFallback(envelope: DaemonCommandEnvelope): Promise<void> {
  try {
    await daemon.send(envelope);
  } catch (err) {
    if (isUnknownDaemonCommandError(err, envelope.command.type)) {
      // Degrade to legacy command format or notify user
      console.warn(`Daemon doesn't support ${envelope.command.type}, using fallback`);
      await sendLegacyCommand(envelope.command);
      return;
    }
    throw err;  // Re-throw non-compatibility errors
  }
}

Evolution Policy

The AGENTS.md documentation (line 39) establishes strict rules for protocol changes:

"Bump DAEMON_PROTOCOL_VERSION for incompatible changes"

This policy ensures:

  • Patch changes: Schema revision increments for additive fields
  • Minor changes: Backward-compatible capability additions
  • Major changes: Protocol version bump forcing coordinated upgrades

Key Implementation Files

File Responsibility
packages/coding-agent/src/modes/daemon/daemon-protocol.ts Constants, interfaces, createDaemonCommandEnvelope, getDaemonCommandCompatibilities
packages/coding-agent/src/modes/daemon/daemon-client.ts isUnknownDaemonCommandError, runtime version negotiation (line 304)
packages/coding-agent/test/daemon-protocol.test.ts Unit tests for version bump scenarios and compatibility edge cases
AGENTS.md Protocol evolution policy documentation

Summary

  • Explicit versioning: DAEMON_PROTOCOL_VERSION and DAEMON_SCHEMA_REVISION constants establish baseline compatibility
  • Command-level granularity: Per-command compatibility matrices isolate breaking changes
  • Dynamic negotiation: getDaemonCommandCompatibilities() adapts requirements based on feature context
  • Clear error contracts: isUnknownDaemonCommandError() enables client-side graceful degradation
  • Documented evolution policy: AGENTS.md mandates protocol version bumps for incompatible changes

Frequently Asked Questions

What happens when a newer client connects to an older daemon?

The daemon rejects unsupported commands with an "unknown command" error. The client detects this via isUnknownDaemonCommandError() and can either retry with reduced functionality or prompt for daemon upgrade.

When should developers bump DAEMON_PROTOCOL_VERSION versus DAEMON_SCHEMA_REVISION?

Bump schema revision for additive changes that older daemons can safely ignore (new optional fields). Bump protocol version for structural changes that would cause parsing failures or semantic misinterpretation.

How does the daemon handle commands requiring capabilities the client hasn't advertised?

The compatibility check fails at the capability validation stage. The command is rejected before execution, preventing partial or corrupted state modifications.

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 →