The coordination layer for multi-agent systems
Dispatch work, share state, observe decisions, and gate actions - on the same infrastructure that powers chat, notifications, and live dashboards. Build with our MCP server from your IDE.
Multi-agent systems need coordination infrastructure
Most teams build it from scratch on top of Redis, Kafka, or raw WebSockets. NoLag provides the patterns - task dispatch, shared state, approval gates, observability - so you can focus on agent logic instead of plumbing.
Build with AI, for AI
NoLag ships a full Model Context Protocol (MCP) server. Connect Claude Desktop, Cursor, or any MCP-compatible AI assistant and let it manage your entire agent infrastructure - create apps, rooms, actors, dispatch tasks, and query state using natural language.
- 35 tools for apps, rooms, actors, scopes, messaging, and agent observability
- Let your AI assistant scaffold entire agent workflows from a prompt
- Dispatch tasks, read blackboard state, and monitor agents - all from your IDE
{
"mcpServers": {
"nolag": {
"url": "https://api.nolag.app/mcp/sse",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}Then ask: "Create an agents app with a research workflow room and 3 worker actors"
Six coordination primitives
Handoff
Dispatch tasks to workers by capability tags. Built-in pooling, routing, and result collection.
const handoff = new Handoff(room);
const result = await handoff.dispatch(
"summarize",
{ url },
{ waitForResult: true },
);Inbox
Direct actor-to-actor messaging. Route messages to specific agents by ID without broadcasting.
const inbox = new Inbox(room, agents.agentId);
inbox.send("agent-42", {
type: "review",
content: draft,
});Blackboard
Shared key-value state, retained so late joiners get it. Each write carries a version; the last writer wins.
const board = new Blackboard(room, agents.agentId);
board.set("plan", {
steps: ["research", "draft", "review"],
currentStep: 0,
});Observe
Real-time event stream for monitoring. Agents emit what matters; dashboards and supervisors watch it live.
const observe = new Observe(room, "monitor");
observe.on((event) => {
log(event.category, event.emittedBy, event.payload);
});Approve
Human-in-the-loop gating. Pause agent workflows until a human approves, rejects, or defers.
const approve = new Approve(room, agents.agentId);
const approval = await approve.request(
"send-email",
{ draft: emailContent },
);
if (approval.decision === "approved") { /* ... */ }Tools
Remote tool invocation and response. Let agents call tools hosted by other agents or services.
const tools = new Tools(room, agents.agentId);
const { result } = await tools.invoke(
"web-search",
{ query: "latest AI news" },
);Multi-Tenant Isolation
Automatic per-tenant communication isolation. Assign actors to access scopes and all topics are partitioned - zero code changes, zero room duplication.
// Create a scope for each tenant
const scope = await api.scopes.create({
slug: "client-acme",
name: "Acme Corporation",
});
// Assign actors: isolation is automatic
await api.actors.update(actorTokenId, {
accessScopeId: scope.accessScopeId,
});Compose with other Blueprints
Agents Blueprint composes naturally with Chat, Notify, Track, and other Blueprints via cross-app actor access. Build an agentic chatbot by connecting an agents app with a chat app - shared actors bridge the two.
Read the composition guide →End-to-end coordination
Dispatch research to a capable worker, collect results, request human approval, then hand off to a publisher agent. All state changes are observable in real time.
- Tag-based capability routing
- Shared blackboard for workflow state
- Human-in-the-loop approval gates
- Full observability on every event
import { NoLag } from "@nolag/js-sdk";
import { NoLagAgents, Blackboard, Handoff, Approve, Inbox, Observe } from "@nolag/agents";
const client = NoLag(ORCHESTRATOR_TOKEN);
const agents = new NoLagAgents({ client, appName: APP_SLUG, agentId: "orchestrator" });
await client.connect();
await agents.ready();
const room = agents.room("default-workflow");
const board = new Blackboard(room, agents.agentId);
const handoff = new Handoff(room);
const approve = new Approve(room, agents.agentId);
const inbox = new Inbox(room, agents.agentId);
const observe = new Observe(room, agents.agentId);
// 1. Set shared state (retained, so late joiners get it)
board.set("goal", {
topic: "Quarterly revenue analysis",
sources: ["SEC filings", "earnings calls"],
});
// 2. Dispatch research to a worker that advertises the capability
const result = await handoff.dispatch("research", board.get("goal"), {
waitForResult: true,
timeout: 60_000,
});
// 3. Ask a human before publishing
if (result) {
const approval = await approve.request("publish-report", result.payload);
if (approval.decision === "approved") {
inbox.send("publisher-agent", { type: "publish", report: result.payload });
}
}
// 4. Observe what the agents emit
observe.on((event) => {
console.log(`[${event.emittedBy}] ${event.category}:`, event.payload);
});NoLag vs building it yourself
| Capability | DIY | NoLag |
|---|---|---|
| Worker pooling & routing | Build on Redis/Kafka | Tag-based dispatch built in |
| Durable task delivery | Configure message broker | Load-balanced worker groups with replay |
| Shared state | Redis/custom store | Blackboard pattern |
| Audit trail | Custom logging | Observe pattern + event stream |
| Presence & heartbeats | Custom health checks | Built-in presence API |
| Access control | Custom auth layer | Per-topic ACL |
Ready to coordinate your agents?
Start free. No credit card required. Ship your first agent workflow in minutes.