Mandible is a stigmergy framework for autonomous agents. Agents coordinate by reading from and writing to a shared environment — not by talking to each other.
No orchestrator. No message broker. Complex workflows emerge from simple rules.
Sense
Agents observe environment signals
Match
Signals match agent capabilities
Claim
Agent claims work atomically
Act
Agent performs the task
Deposit
New signals left in environment
Repeat
Other agents sense the new signals
Mandible borrows coordination patterns from ant colonies and other swarm systems.
Agents leave typed, structured signals in the environment. Signals have concentration that decays over time — stronger signals get processed first.
Filesystem, database, GitHub, Kubernetes — any shared substrate becomes a coordination layer. Observable, debuggable, and persistent.
Groups of identical agents with shared rules. Stateless and replaceable. Scale by increasing concurrency — no rewiring required.
Each colony uses the minimum LLM it needs. Full coding agents for complex work, structured output for judgment, shell commands for mechanics.
Signals weaken and evaporate over time. No stale work, no unbounded queues. The system naturally recovers from abandoned tasks.
Self-healing, load balancing, quality convergence — none of it is programmed. It arises from simple colonies following simple rules.
Stop building fragile pipelines. Let coordination emerge from the environment.
Minimal API
Define colonies inline or as reusable modules. They self-organize through signals.
// Three colonies. Zero coordination code.
const host = await mandible('code-pipeline')
.environment(env)
.colony('shaper', c => c
.sense('task:ready', { unclaimed: true })
.do('shape', withClaudeCode({
model: 'sonnet',
prompt: (s) => `Implement ${s.payload.title} on branch ${s.payload.branch}`,
allowedTools: ['Read', 'Edit', 'Bash'],
output: (_, s) => ({ type: 'artifact:shaped', payload: s.payload }),
}))
.concurrency(3)
.claim('lease', 120_000))
.colony('critic', c => c
.sense('artifact:shaped', { unclaimed: true })
.do('review', withStructuredOutput({
model: 'sonnet',
prompt: (s) => `Review the change on ${s.payload.branch}`,
route: (r, s) => r.approved
? { type: 'review:approved', payload: s.payload }
: { type: 'review:changes-needed', payload: r },
})))
.colony('keeper', c => c
.sense('review:approved', { unclaimed: true })
.do('open-pr', withBash({
command: (s) => `gh pr create --head ${s.payload.branch} --fill`,
output: { type: 'pr:opened' },
}))
.claim('exclusive'))
.start();// Reusable colony module — export and compose anywhere.
import type { ColonyBuilder } from '@mandible-ai/mandible';
export function worker() {
return (c: ColonyBuilder) => c
.sense('task:ready', { unclaimed: true })
.do('process', async (signal, ctx) => {
ctx.log(`processing ${signal.id}`);
await ctx.deposit('task:done', signal.payload, {
causedBy: [signal.id],
});
await ctx.withdraw(signal.id);
})
.concurrency(1)
.claim('exclusive');
}
// Then run it in a container, from mandible.config.ts:
await mandible('my-colony')
.environment(env)
.host(docker())
.colony('worker', {
module: './worker.ts',
export: 'worker',
})
.start();Same framework, managed infrastructure. Push your mandible config and we handle orchestration, isolation, and observability.
Each colony runs in a hardware-isolated microVM. No shared kernels, no container escapes.
Watch signals flow between colonies live. Signal graph, concentration decay, colony stats.
Pay nothing when idle. Colonies spin up on demand and shut down when the signal queue is empty.