Time-boxed autonomous agent sprints — self-assembly, voting, parallel execution, and review.
Sprint Protocol
The Sprint Protocol coordinates groups of agents through a structured work cycle: assemble around a goal, propose approaches, vote on the best plan, execute in parallel with millisecond deadlines, and review results. The entire cycle can complete in under a second.
Why Sprints
Swarm execution gives you scale. But scale without coordination is chaos — 100 agents all writing to the same file, proposing conflicting approaches, or duplicating work.
The Sprint Protocol adds democratic structure. Agents don't just execute — they propose, debate, agree, then execute. This produces higher-quality output because the approach is vetted before any work begins.
Sprint Phases
assembling → proposing → voting → executing → reviewing → completeEvery phase has a configurable millisecond deadline. If a deadline expires, the sprint auto-advances or fails depending on the phase.
1. Assembling
Agents join the sprint until minAgents is reached or assemblyDeadlineMs expires:
const sprint = sprints.create({
goal: 'Migrate authentication to JWT',
projectId: 'my-app',
initiatorId: 'user-1',
minAgents: 10,
maxAgents: 50,
consensusThreshold: 0.5,
assemblyDeadlineMs: 60_000,
votingDeadlineMs: 60_000,
executionDeadlineMs: 300_000,
reviewDeadlineMs: 60_000,
});
// Agents join
sprints.join(sprint.id, {
agentId: 'agent-1',
name: 'JWT Specialist',
role: 'coder',
capabilities: ['typescript', 'authentication'],
});2. Proposing
Each agent proposes an approach with subtasks, time estimate, and confidence:
sprints.propose(sprint.id, 'agent-1', {
approach: 'Implement JWT with RS256, refresh tokens, and middleware',
subtasks: ['jwt-utils', 'login-endpoint', 'middleware', 'tests'],
estimatedMs: 120_000,
confidence: 0.85,
});3. Voting
Agents vote on proposals. The default strategy approves the highest-confidence proposal:
sprints.vote(sprint.id, 'agent-1', {
proposalId: 'proposal-abc',
decision: 'approve', // approve | reject | conditional
reasoning: 'RS256 approach is most secure',
});Consensus is reached when the approval ratio meets consensusThreshold.
4. Executing
The winning proposal's subtasks are decomposed into tasks and assigned round-robin to participants:
// Tasks are auto-created from the winning proposal's subtasks
// Each task has: id, description, assignedTo, status, output, tokensUsed
// Agents execute their assigned tasks
sprints.updateTask(sprint.id, 'agent-1', 'task-1', { status: 'active' });
// ... agent does the work ...
sprints.updateTask(sprint.id, 'agent-1', 'task-1', {
status: 'done',
output: { files: ['src/jwt.ts'] },
tokensUsed: 500,
});When all tasks complete, the sprint auto-advances to reviewing.
5. Reviewing
Agents inspect the collective output. The sprint can be completed, failed, or sent back for another round.
sprints.complete(sprint.id);
// or
sprints.fail(sprint.id, 'Tests did not pass');AgentParticipant
The AgentParticipant class wraps mesh + sprint into a single autonomous unit. Call start() and the agent self-drives through every phase:
import { AgentParticipant } from '@codmir/server/gateways/sprint';
const agent = new AgentParticipant(mesh, sprints, {
identity: {
agentId: 'agent-1',
name: 'Backend Dev',
role: 'coder',
capabilities: ['typescript', 'api'],
},
socketId: 'sock-1',
onExecuteTask: async (task, sprint) => {
// This is the agent's "brain" — call an LLM, run code, etc.
const result = await callClaude(task.description);
return {
output: result,
tokensUsed: result.usage.totalTokens,
artifacts: [{ type: 'code', content: result.files }],
};
},
});
agent.start(sprint.id);
// Tick-based execution (each tick handles one phase action)
const result = await agent.tick();
// { state: 'proposing', sprintPhase: 'proposing', action: 'proposed', tokensUsed: 0 }
// Or let it run autonomously
agent.startLoop(); // ticks every 50ms until completeCustom Proposal and Voting
Override the default proposal and voting logic:
const agent = new AgentParticipant(mesh, sprints, {
// ...identity and execution config...
onPropose: async (sprint) => ({
approach: 'My custom strategy based on codebase analysis',
subtasks: ['analyze', 'implement', 'test'],
estimatedMs: 60_000,
confidence: 0.9,
}),
onVote: async (sprint, proposals) => {
const best = proposals.find(p => p.confidence > 0.8);
return {
proposalId: best?.id ?? proposals[0].id,
decision: 'approve',
reasoning: 'High confidence approach',
};
},
});Event Stream
Every sprint action emits events through the SprintService event system:
const unsubscribe = sprints.onEvent(sprint.id, (event) => {
console.log(event.type, event.agentId, event.data);
});Event types include: sprint:created, sprint:agent_joined, sprint:proposal_submitted, sprint:vote_cast, sprint:consensus_reached, sprint:task_started, sprint:task_completed, sprint:completed, and more.
Surface Bridge
The SprintBridgeService relays all sprint events to the NestJS EventEmitter, making them available to every gateway:
// Any gateway can listen
@OnEvent('sprint.task_completed')
handleTaskCompleted(event: SprintEvent) {
// Forward to connected clients via Socket.IO
this.server.to(event.sprintId).emit('sprint:task_completed', event);
}
// Or catch all sprint events
@OnEvent('sprint.event')
handleAnySprintEvent(event: SprintEvent) {
this.dashboardClients.emit('sprint:event', event);
}This means desktop IDE, web app, VS Code extension, CLI, and mobile all see sprint activity in real-time without any surface-specific code.
Scaling to 100 Agents
The sprint protocol is tested with 100 concurrent agents:
- 100 agents join in one tick cycle
- 100 proposals submitted in parallel
- 100 votes cast with consensus check
- 99 tasks distributed and executed via
Promise.all - Auto-advance through all phases
- Total tokens tracked per agent with quantized tiers
See Quantized Execution for how to run 100 agents at 75% lower cost.
Next Steps
- Agent Mesh — the communication fabric underneath sprints
- Quantized Execution — layered cost optimization
- Swarm Execution — higher-level swarm coordination via Cortex