Multi-agent coordination — create swarms, recruit agents, track budgets, merge results.
SwarmProtocol
The SwarmProtocol coordinates multiple agents working on a single task. It handles swarm creation, agent recruitment, task assignment, file locking (to prevent 10,000 agents from editing the same file), budget tracking, progress monitoring, and task decomposition. All state is persisted to swarm.crtx via CortexIO.
import { SwarmProtocol, Timeline, CortexIO } from '@codmir/cortex';Constructor
new SwarmProtocol(io: CortexIO, timeline: Timeline)| Parameter | Type | Description |
|---|---|---|
io | CortexIO | The CortexIO instance for file operations |
timeline | Timeline | Timeline instance for recording swarm events |
const io = new CortexIO('/home/dev/my-project');
await io.init();
const timeline = new Timeline(io);
const swarm = new SwarmProtocol(io, timeline);Swarm Lifecycle
create()
Creates a new swarm with a task decomposition, strategy, budget, and merge policy. Writes the manifest to swarm.crtx and records a delegation entry in the timeline.
async create(opts: {
task: string;
coordinatorId: string;
strategy: SwarmStrategy;
maxAgents?: number;
maxTokens?: number;
maxCostUsd?: number;
maxDurationMs?: number;
mergePolicy?: Partial<MergePolicy>;
decomposition: TaskNode;
}): Promise<SwarmManifest>| Parameter | Type | Description |
|---|---|---|
opts.task | string | High-level task description |
opts.coordinatorId | string | Agent ID of the coordinator |
opts.strategy | SwarmStrategy | Coordination strategy |
opts.maxAgents | number (optional) | Max agents (default: 10000) |
opts.maxTokens | number (optional) | Max total tokens (default: 100000000) |
opts.maxCostUsd | number (optional) | Max total cost in USD (default: 50) |
opts.maxDurationMs | number (optional) | Max duration in ms (default: 3600000) |
opts.mergePolicy | Partial<MergePolicy> (optional) | Merge and conflict resolution policy |
opts.decomposition | TaskNode | Root task node with children |
const manifest = await swarm.create({
task: 'Build authentication system',
coordinatorId: 'coordinator_1',
strategy: 'hierarchical',
maxAgents: 100,
maxCostUsd: 10,
decomposition: SwarmProtocol.decompose(
'Build authentication system',
[
'Implement JWT token generation',
'Build login/register endpoints',
'Add threat detection middleware',
'Write integration tests',
],
'parallel'
),
});get()
Returns the current swarm manifest, or null if no swarm is active.
async getSwarm(): Promise<SwarmManifest | null>disband()
Disbands the active swarm. Records a decision entry in the timeline with the final agent count and cost, then deletes swarm.crtx.
async disband(): Promise<void>Agent Management
recruit()
Adds an agent to the swarm. Throws if the swarm has reached its maxAgents budget.
async recruit(
agentId: string,
role: string,
expertise: string[]
): Promise<SwarmAgent>| Parameter | Type | Description |
|---|---|---|
agentId | string | Unique agent identifier |
role | string | Agent's role (e.g., 'backend', 'tester') |
expertise | string[] | Agent's areas of expertise |
const agent = await swarm.recruit('agent_1', 'backend', ['TypeScript', 'NestJS', 'auth']);
console.log(agent.status); // 'idle'assign()
Assigns a task to an agent. Sets the agent status to 'working' and marks the task as 'active'.
async assign(agentId: string, taskId: string): Promise<void>| Parameter | Type | Description |
|---|---|---|
agentId | string | Agent to assign |
taskId | string | Task node ID from the decomposition |
await swarm.assign('agent_1', manifest.decomposition.children[0].id);complete()
Marks a task as complete for an agent. Updates token and cost tracking. If the agent has no remaining assigned tasks, its status becomes 'done'.
async complete(
agentId: string,
taskId: string,
tokensUsed: number,
costUsd: number,
output?: unknown
): Promise<void>| Parameter | Type | Description |
|---|---|---|
agentId | string | Agent that completed the task |
taskId | string | Task node ID |
tokensUsed | number | Tokens consumed |
costUsd | number | Cost in USD |
output | unknown (optional) | Task output to store in the decomposition |
await swarm.complete('agent_1', taskId, 15000, 0.045, {
files: ['src/auth/jwt.ts'],
summary: 'JWT generation with RS256 signing',
});fail()
Marks a task as failed for an agent. Records a failure entry in the timeline.
async fail(agentId: string, taskId: string, reason: string): Promise<void>| Parameter | Type | Description |
|---|---|---|
agentId | string | Agent that failed |
taskId | string | Task node ID |
reason | string | Why the task failed |
await swarm.fail('agent_2', taskId, 'Rate limited by OpenAI API after 50 requests');File Locking
Prevents multiple agents from editing the same file simultaneously.
lock()
Acquires a file lock. Throws if the path is exclusively locked by another agent.
async lock(
agentId: string,
path: string,
type?: 'exclusive' | 'shared',
ttlMs?: number
): Promise<SwarmLock>| Parameter | Type | Description |
|---|---|---|
agentId | string | Agent acquiring the lock |
path | string | File or directory path to lock |
type | string (optional) | Lock type (default: 'exclusive') |
ttlMs | number (optional) | Lock TTL in ms (default: 300000 / 5 minutes) |
const lock = await swarm.lock('agent_1', 'src/auth/jwt.ts');
// ... edit the file ...
await swarm.unlock('agent_1', 'src/auth/jwt.ts');unlock()
Releases a file lock held by the specified agent.
async unlock(agentId: string, path: string): Promise<void>isLocked()
Checks if a path is currently locked. Returns the active lock or null.
async isLocked(path: string): Promise<SwarmLock | null>Budget and Progress
isOverBudget()
Checks whether any budget limits have been exceeded.
async isOverBudget(): Promise<{ over: boolean; details: string[] }>const budget = await swarm.isOverBudget();
if (budget.over) {
console.log('Budget exceeded:', budget.details);
// ['Cost: $10.50/$10.00', 'Tokens: 105000000/100000000']
}progress()
Returns task completion progress across the decomposition tree.
async progress(): Promise<{
total: number;
done: number;
active: number;
failed: number;
pending: number;
percent: number;
}>const p = await swarm.progress();
console.log(`${p.percent}% complete (${p.done}/${p.total} tasks)`);Static Helpers
SwarmProtocol.createTask()
Creates a single task node with defaults.
static createTask(
description: string,
opts?: Partial<TaskNode>
): TaskNode| Parameter | Type | Description |
|---|---|---|
description | string | Task description |
opts | Partial<TaskNode> (optional) | Override defaults (priority, estimatedTokens, etc.) |
Default values: status: 'pending', priority: 5, estimatedTokens: 1000, dependencies: [], children: [].
const task = SwarmProtocol.createTask('Implement rate limiting', {
priority: 8,
estimatedTokens: 5000,
});SwarmProtocol.decompose()
Creates a root task node with children generated from a list of subtask descriptions. Supports parallel (independent) or sequential (dependency chain) strategies.
static decompose(
root: string,
subtasks: string[],
strategy?: 'parallel' | 'sequential'
): TaskNode| Parameter | Type | Description |
|---|---|---|
root | string | Root task description |
subtasks | string[] | Subtask descriptions |
strategy | string (optional) | 'parallel' (default) or 'sequential' |
In sequential mode, each child depends on the previous child's ID.
// Parallel decomposition — all subtasks can run simultaneously
const parallel = SwarmProtocol.decompose(
'Build REST API',
['Users CRUD', 'Projects CRUD', 'Auth endpoints', 'Webhook handlers'],
'parallel'
);
// Sequential decomposition — each subtask depends on the previous
const sequential = SwarmProtocol.decompose(
'Database migration',
['Create schema', 'Seed data', 'Run migration', 'Verify integrity'],
'sequential'
);Types
SwarmManifest
interface SwarmManifest {
id: string;
task: string;
created: number;
coordinator: string;
strategy: SwarmStrategy;
agents: SwarmAgent[];
locks: SwarmLock[];
decomposition: TaskNode;
mergePolicy: MergePolicy;
budget: SwarmBudget;
}SwarmStrategy
type SwarmStrategy =
| 'parallel' // all agents work independently, merge at end
| 'pipeline' // sequential, each agent's output feeds the next
| 'hierarchical' // queen delegates to workers
| 'consensus' // agents vote on approach before executing
| 'competitive'; // multiple agents solve same task, best winsSwarmAgent
interface SwarmAgent {
id: string;
role: string;
expertise: string[];
assignedTasks: string[];
status: 'idle' | 'working' | 'blocked' | 'done' | 'failed';
startedAt?: number;
completedAt?: number;
tokensUsed: number;
costUsd: number;
}TaskNode
interface TaskNode {
id: string;
description: string;
assignedTo?: string;
status: 'pending' | 'active' | 'done' | 'failed' | 'skipped';
priority: number;
estimatedTokens: number;
actualTokens?: number;
dependencies: string[];
children: TaskNode[];
output?: unknown;
}SwarmBudget
interface SwarmBudget {
maxAgents: number;
maxTokens: number;
maxCostUsd: number;
maxDurationMs: number;
spent: {
agents: number;
tokens: number;
costUsd: number;
durationMs: number;
};
}MergePolicy
interface MergePolicy {
strategy: 'auto' | 'voting' | 'coordinator_review' | 'human_review';
conflictResolution: 'last_write' | 'highest_confidence' | 'coordinator_decides' | 'vote';
minAgreePercent?: number;
requireHumanApproval: boolean;
}SwarmLock
interface SwarmLock {
path: string;
agentId: string;
type: 'exclusive' | 'shared';
acquiredAt: number;
expiresAt: number;
reason: string;
}Example
import { CortexIO, Timeline, SwarmProtocol } from '@codmir/cortex';
const io = new CortexIO('/home/dev/my-project');
await io.init();
const timeline = new Timeline(io);
const swarm = new SwarmProtocol(io, timeline);
// Create a swarm for a feature build
const manifest = await swarm.create({
task: 'Build real-time collaboration feature',
coordinatorId: 'queen',
strategy: 'hierarchical',
maxAgents: 100,
maxTokens: 50_000_000,
maxCostUsd: 25,
decomposition: SwarmProtocol.decompose(
'Real-time collaboration',
[
'WebSocket gateway with rooms',
'Presence tracking service',
'Conflict resolution (CRDT)',
'UI cursors and selections',
'Integration tests',
],
'parallel'
),
mergePolicy: {
strategy: 'coordinator_review',
conflictResolution: 'coordinator_decides',
requireHumanApproval: false,
},
});
// Recruit agents
await swarm.recruit('agent_ws', 'backend', ['WebSocket', 'NestJS']);
await swarm.recruit('agent_crdt', 'backend', ['CRDT', 'distributed-systems']);
await swarm.recruit('agent_ui', 'frontend', ['React', 'Canvas']);
await swarm.recruit('agent_test', 'qa', ['Jest', 'Playwright']);
// Assign tasks
const tasks = manifest.decomposition.children;
await swarm.assign('agent_ws', tasks[0].id);
await swarm.assign('agent_ws', tasks[1].id);
await swarm.assign('agent_crdt', tasks[2].id);
await swarm.assign('agent_ui', tasks[3].id);
await swarm.assign('agent_test', tasks[4].id);
// Lock files before editing
await swarm.lock('agent_ws', 'apps/server/src/gateways/collab.gateway.ts');
// Complete a task
await swarm.complete('agent_ws', tasks[0].id, 25000, 0.075, {
files: ['apps/server/src/gateways/collab.gateway.ts'],
});
// Check progress
const progress = await swarm.progress();
console.log(`${progress.percent}% complete`);
// Check budget
const budget = await swarm.isOverBudget();
if (budget.over) {
console.log('Over budget:', budget.details);
await swarm.disband();
}