Skip to main content

ValkyrAI Agentic SWARM Protocol

Unified messaging protocol for coordinating ValkyrAI workflows, ValorIDE agents, web clients, and distributed processes into a coherent multi-agent system.

Overview

The SWARM protocol enables real-time coordination between:

  • ValkyrAI Server - Spring Boot backend with WebSocket broker (STOMP over SockJS)
  • ValorIDE Instances - VSCode extension instances acting as autonomous agents
  • Web Clients - React SPAs with SageChat and ServerConsole
  • Workflow Engine - ValkyrAI workflow orchestration with ExecModules

Channel Topology

Public Broadcast Channels

ChannelPurpose
/topic/messagesGeneral system messages, broadcasts to all connected clients
/topic/statusesSystem status updates, workflow progress, health checks
/topic/agentsActive agent registry, presence announcements
/topic/agent-commandsBroadcast commands to all agents
/topic/workflow-monitoringWorkflow execution events, metrics

Private/Direct Channels

ChannelPurpose
/user/{principalId}/queue/privatePrivate messages for specific authenticated user
/queue/agents/{instanceId}/commandsDirect commands to specific ValorIDE instance
/user/{principalId}/queue/notificationsUser-specific notifications
/topic/workflow/{workflowId}Workflow-specific updates

Application Endpoints (Client → Server)

EndpointPurpose
/app/chatClient sends messages to server
/app/agent/registerAgent registration/heartbeat
/app/agent/ackAcknowledgment responses
/app/agent/announceAgent capabilities/status announcement

Security & Access Control

  • Authentication: WebSocket connections require JWT authentication (?token=... or Authorization header)
  • Private channels: Validate Principal ownership via Spring Security ACL
  • Broadcast channels: Open to authenticated users
  • Admin channels: Require ROLE_ADMIN or ROLE_SYSTEM

All channels enforce Spring Security policies.

Message Envelope

Standard Format

All messages follow this JSON schema:

{
"id": "uuid-v4",
"type": "command|response|broadcast|event|ack|nack",
"from": {
"instanceId": "valoride-abc123",
"type": "agent|server|workflow|user",
"principalId": "uuid-of-authenticated-principal",
"username": "john@example.com"
},
"to": {
"instanceId": "valoride-xyz789",
"type": "agent|server|broadcast",
"principalId": "uuid-target-principal"
},
"timestamp": "2025-10-27T12:34:56.789Z",
"ackId": "uuid-of-message-to-acknowledge",
"payload": {
"action": "execute|status|query|result",
"data": {
/* action-specific payload */
},
"metadata": {
"workflowId": "optional-workflow-uuid",
"sessionId": "optional-session-uuid",
"correlationId": "optional-correlation-uuid"
}
},
"security": {
"signature": "optional-hmac-sha256-signature",
"encrypted": false
},
"ttl": 300000,
"priority": "low|normal|high|urgent"
}

Field Reference

FieldTypeDescription
idUUIDUnique message identifier
typeenumcommand, response, broadcast, event, ack, or nack
fromobjectSender identity (instanceId, type, principalId, username)
toobjectRecipient identity
timestampISO 8601Message creation time (UTC)
ackIdUUIDReference to message being acknowledged
payload.actionstringOperation to perform (e.g., "execute", "register")
payload.dataobjectAction-specific payload
payload.metadataobjectContextual IDs (workflow, session, correlation)
security.signaturestringOptional HMAC-SHA256 integrity signature
security.encryptedbooleanIndicates if payload is encrypted
ttlnumberTime-to-live in milliseconds (default 5 min)
priorityenumlow, normal, high, or urgent

Message Flows

1. Agent Registration

ValorIDE instance registers with server and broadcasts to swarm:

// ValorIDE → Server (/app/agent/register)
{
"id": "reg-001",
"type": "command",
"from": {
"instanceId": "valoride-abc123",
"type": "agent",
"principalId": "user-uuid",
"username": "john@example.com"
},
"to": { "type": "server" },
"timestamp": "2025-10-27T12:34:56.789Z",
"payload": {
"action": "register",
"data": {
"capabilities": ["code-generation", "file-operations", "git-commands"],
"version": "1.2.3",
"role": "worker",
"status": "idle"
}
}
}

// Server → All Agents (/topic/agents)
{
"id": "reg-ack-001",
"type": "broadcast",
"from": { "type": "server" },
"to": { "type": "broadcast" },
"timestamp": "2025-10-27T12:34:57.000Z",
"payload": {
"action": "agent-list-updated",
"data": {
"agents": [
{
"instanceId": "valoride-abc123",
"principalId": "user-uuid",
"username": "john@example.com",
"status": "idle",
"lastSeen": "2025-10-27T12:34:56.789Z",
"capabilities": ["code-generation", "file-operations"]
}
]
}
}
}

2. Command Execution with Ack/Nack

Server sends command to agent and waits for acknowledgment:

// Server → Agent (/queue/agents/valoride-abc123/commands)
{
"id": "cmd-001",
"type": "command",
"from": { "type": "server", "principalId": "admin-uuid" },
"to": { "instanceId": "valoride-abc123", "type": "agent" },
"timestamp": "2025-10-27T12:35:00.000Z",
"payload": {
"action": "execute",
"data": {
"command": "generate-component",
"args": { "componentName": "UserProfile", "framework": "react" }
},
"metadata": {
"workflowId": "workflow-uuid-123",
"correlationId": "req-uuid-456"
}
},
"ttl": 60000,
"priority": "high"
}

// Agent → Server (/app/agent/ack)
{
"id": "ack-cmd-001",
"type": "ack",
"from": { "instanceId": "valoride-abc123", "type": "agent" },
"to": { "type": "server" },
"timestamp": "2025-10-27T12:35:01.000Z",
"ackId": "cmd-001",
"payload": {
"action": "acknowledged",
"data": { "status": "processing", "estimatedDuration": 5000 }
}
}

// Agent → Server (/app/chat) - Result
{
"id": "result-cmd-001",
"type": "response",
"from": { "instanceId": "valoride-abc123", "type": "agent" },
"to": { "type": "server" },
"timestamp": "2025-10-27T12:35:06.000Z",
"ackId": "cmd-001",
"payload": {
"action": "result",
"data": {
"success": true,
"filesCreated": [
"src/components/UserProfile.tsx",
"src/components/UserProfile.css"
],
"output": "Component generated successfully"
},
"metadata": {
"workflowId": "workflow-uuid-123",
"correlationId": "req-uuid-456"
}
}
}

3. Error Handling (Nack)

Agent cannot execute command and sends negative acknowledgment:

{
"id": "nack-cmd-002",
"type": "nack",
"from": { "instanceId": "valoride-abc123", "type": "agent" },
"to": { "type": "server" },
"timestamp": "2025-10-27T12:36:00.000Z",
"ackId": "cmd-002",
"payload": {
"action": "rejected",
"data": {
"error": "InsufficientPermissions",
"message": "Agent lacks file write permissions in target directory",
"code": "ERR_PERMISSION_DENIED"
}
}
}

4. Workflow Coordination

ValkyrAI workflow triggers ValorIDE agent:

{
"id": "wf-task-001",
"type": "command",
"from": { "type": "workflow", "principalId": "owner-uuid" },
"to": {
"instanceId": "valoride-abc123",
"type": "agent",
"principalId": "owner-uuid"
},
"timestamp": "2025-10-27T12:40:00.000Z",
"payload": {
"action": "execute-task",
"data": {
"task": "code-review",
"files": ["src/services/UserService.ts"],
"criteria": ["security", "performance", "maintainability"]
},
"metadata": {
"workflowId": "wf-uuid-789",
"taskId": "task-uuid-101"
}
}
}

Implementation

Server-Side (Spring Boot)

  1. Message Validation - Use @Valid annotations and custom validators
  2. ACL Checks - Verify Principal ownership on private channels via @PreAuthorize
  3. Persistence - Store command history in DB for audit trail
  4. Retry Logic - Implement exponential backoff for failed deliveries
  5. Rate Limiting - Apply per-Principal rate limits on /app/* endpoints

Client-Side (ValorIDE & Web)

  1. Message Normalization - Use shared TypeScript helper to encode/decode
  2. Ack Tracking - Maintain pending ack map with timeout handling
  3. Reconnection - Implement exponential backoff with jitter
  4. State Sync - Re-announce presence on reconnect
  5. Local Queue - Buffer messages during disconnect, replay on connect

ExecModule Pattern

Template for ValorIDE interaction ExecModule:

@Component("valorideExecModule")
@VModuleAware
public class ValorIDEExecModule extends VModule {

@Autowired
private SimpMessagingTemplate messagingTemplate;

@Autowired
private SwarmRegistryService swarmRegistry;

@Override
public Map<String, Object> execute(
Workflow workflow,
Task task,
ExecModule module,
Map<String, Object> input
) {
String targetInstanceId = (String) input.get("targetInstanceId");
String action = (String) input.get("action");
Map<String, Object> data = (Map) input.get("data");

// Build message envelope
Map<String, Object> message = Map.of(
"id", UUID.randomUUID().toString(),
"type", "command",
"from", Map.of("type", "workflow"),
"to", Map.of("instanceId", targetInstanceId, "type", "agent"),
"timestamp", Instant.now().toString(),
"payload", Map.of("action", action, "data", data)
);

// Send to agent
String destination = "/queue/agents/" + targetInstanceId + "/commands";
messagingTemplate.convertAndSend(destination, message);

return Map.of("status", "sent", "messageId", message.get("id"));
}
}

Migration Path

  1. Phase 1 - Add envelope support to existing messages (backward compatible)
  2. Phase 2 - Update SwarmRegistryService and ValorBroadcastService to use envelopes
  3. Phase 3 - Implement ValorIDEExecModule and client-side handlers
  4. Phase 4 - Migrate all WebSocket messages to unified envelope
  5. Phase 5 - Deprecate legacy message formats

References

PRODUCTION READY