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
| Channel | Purpose |
|---|---|
/topic/messages | General system messages, broadcasts to all connected clients |
/topic/statuses | System status updates, workflow progress, health checks |
/topic/agents | Active agent registry, presence announcements |
/topic/agent-commands | Broadcast commands to all agents |
/topic/workflow-monitoring | Workflow execution events, metrics |
Private/Direct Channels
| Channel | Purpose |
|---|---|
/user/{principalId}/queue/private | Private messages for specific authenticated user |
/queue/agents/{instanceId}/commands | Direct commands to specific ValorIDE instance |
/user/{principalId}/queue/notifications | User-specific notifications |
/topic/workflow/{workflowId} | Workflow-specific updates |
Application Endpoints (Client → Server)
| Endpoint | Purpose |
|---|---|
/app/chat | Client sends messages to server |
/app/agent/register | Agent registration/heartbeat |
/app/agent/ack | Acknowledgment responses |
/app/agent/announce | Agent capabilities/status announcement |
Security & Access Control
- Authentication: WebSocket connections require JWT authentication (
?token=...orAuthorizationheader) - Private channels: Validate Principal ownership via Spring Security ACL
- Broadcast channels: Open to authenticated users
- Admin channels: Require
ROLE_ADMINorROLE_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
| Field | Type | Description |
|---|---|---|
id | UUID | Unique message identifier |
type | enum | command, response, broadcast, event, ack, or nack |
from | object | Sender identity (instanceId, type, principalId, username) |
to | object | Recipient identity |
timestamp | ISO 8601 | Message creation time (UTC) |
ackId | UUID | Reference to message being acknowledged |
payload.action | string | Operation to perform (e.g., "execute", "register") |
payload.data | object | Action-specific payload |
payload.metadata | object | Contextual IDs (workflow, session, correlation) |
security.signature | string | Optional HMAC-SHA256 integrity signature |
security.encrypted | boolean | Indicates if payload is encrypted |
ttl | number | Time-to-live in milliseconds (default 5 min) |
priority | enum | low, 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)
- Message Validation - Use
@Validannotations and custom validators - ACL Checks - Verify Principal ownership on private channels via
@PreAuthorize - Persistence - Store command history in DB for audit trail
- Retry Logic - Implement exponential backoff for failed deliveries
- Rate Limiting - Apply per-Principal rate limits on
/app/*endpoints
Client-Side (ValorIDE & Web)
- Message Normalization - Use shared TypeScript helper to encode/decode
- Ack Tracking - Maintain pending ack map with timeout handling
- Reconnection - Implement exponential backoff with jitter
- State Sync - Re-announce presence on reconnect
- 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
- Phase 1 - Add envelope support to existing messages (backward compatible)
- Phase 2 - Update SwarmRegistryService and ValorBroadcastService to use envelopes
- Phase 3 - Implement ValorIDEExecModule and client-side handlers
- Phase 4 - Migrate all WebSocket messages to unified envelope
- Phase 5 - Deprecate legacy message formats
References
- README_SWARM.md - ValorIDE SWARM quickstart
- WebSocketConfig.java - Server WebSocket configuration
- MothershipService.ts - ValorIDE client implementation
- SWARM_ORCHESTRATOR_PROMPT.md - System prompt for orchestration agent
✅ PRODUCTION READY