🐝Swarm Tools
Packagesswarm-mail

Swarm Mail

Event-sourced messaging system for multi-agent coordination

                                  _.------._
                                .'   .--.   '.        🐝
                               /   .'    '.   \    🐝
                              |   /   __   \   |      🐝
    🐝                        |  |   (  )   |  |  🐝
         🐝    _  _           |  |   |__|   |  |
              ( \/ )           \  '.      .'  /    🐝
    🐝    ____/    \____        '.  '----'  .'
        /    \    /    \         '-._____.-'           🐝
       /  ()  \  /  ()  \
      |   /\   ||   /\   |     ███████╗██╗    ██╗ █████╗ ██████╗ ███╗   ███╗
      |  /__\  ||  /__\  |     ██╔════╝██║    ██║██╔══██╗██╔══██╗████╗ ████║
       \      /  \      /      ███████╗██║ █╗ ██║███████║██████╔╝██╔████╔██║
    🐝  '----'    '----'       ╚════██║██║███╗██║██╔══██║██╔══██╗██║╚██╔╝██║
                               ███████║╚███╔███╔╝██║  ██║██║  ██║██║ ╚═╝ ██║
          🐝                   ╚══════╝ ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝
                 🐝
    🐝                         ███╗   ███╗ █████╗ ██╗██╗
                               ████╗ ████║██╔══██╗██║██║         🐝
         🐝                    ██╔████╔██║███████║██║██║
                               ██║╚██╔╝██║██╔══██║██║██║    🐝
    🐝        🐝               ██║ ╚═╝ ██║██║  ██║██║███████╗
                               ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝╚══════╝       🐝
              🐝
                          ⚡ Actor-Model Primitives for Agent Coordination ⚡

Overview

Swarm Mail is an embedded, event-sourced messaging system for multi-agent coordination. Built on Durable Streams primitives with Effect-TS, it provides actor-model communication without external server dependencies.

What Problem Does It Solve?

When multiple AI agents work on the same codebase in parallel, they need to:

  • Coordinate file access - prevent edit conflicts via reservations
  • Exchange messages - async communication for status, blockers, handoffs
  • Request/response - synchronous-style RPC for data queries
  • Resume after crashes - positioned consumption with checkpointing
  • Audit all actions - full event history for debugging and learning

Traditional solutions require external servers (Redis, Kafka, NATS). Swarm Mail is embedded - just libSQL (embedded SQLite) + Effect-TS.

Key Features

  • Local-first - No external servers, no network dependencies
  • Event-sourced - Full audit trail of all agent actions
  • Resumable - Checkpointed cursors for exactly-once processing
  • Type-safe - Effect-TS with full type inference
  • Actor-model - Mailboxes, envelopes, distributed promises
  • File safety - CAS-based locks for mutual exclusion
  • Semantic memory - Vector embeddings for persistent agent learning

Architecture Stack

Swarm Mail is built in 3 tiers - primitives, patterns, and coordination layers.

┌─────────────────────────────────────────────────────────────────────────────┐
│                              SWARM MAIL STACK                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   TIER 3: COORDINATION                                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  ask<Req, Res>() - Request/Response over Streams (RPC-style)        │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                      │                                      │
│   TIER 2: PATTERNS                   ▼                                      │
│   ┌───────────────────────┐    ┌───────────────────────┐                    │
│   │    DurableMailbox     │    │     DurableLock       │                    │
│   │  Actor Inbox + Reply  │    │  CAS Mutual Exclusion │                    │
│   └───────────────────────┘    └───────────────────────┘                    │
│              │                           │                                  │
│   TIER 1: PRIMITIVES                     ▼                                  │
│   ┌───────────────────────┐    ┌───────────────────────┐                    │
│   │    DurableCursor      │    │   DurableDeferred     │                    │
│   │  Checkpointed Reader  │    │  Distributed Promise  │                    │
│   └───────────────────────┘    └───────────────────────┘                    │
│              │                           │                                  │
│   MEMORY                                 ▼                                  │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  Semantic Memory - Vector embeddings (pgvector) + Ollama            │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                      │                                      │
│   STORAGE                            ▼                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │              libSQL (Embedded SQLite) + Migrations                  │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Quick Start

Installation

npm install swarm-mail

Initialize Agent

import { Effect } from "effect";
import { DurableAskLive } from "swarm-mail/streams/effect/layers";
import {
  initSwarmAgent,
  sendSwarmMessage,
  reserveSwarmFiles,
} from "swarm-mail";

const program = Effect.gen(function* () {
  // 1. Initialize agent
  const { agentName, projectKey } = yield* Effect.promise(() =>
    initSwarmAgent({
      projectPath: "/abs/path",
      taskDescription: "bd-123.2: Auth service",
    }),
  );

  console.log(`Agent: ${agentName}`); // e.g., "DarkStone"

  // 2. Reserve files
  const { granted, conflicts } = yield* Effect.promise(() =>
    reserveSwarmFiles({
      projectPath: projectKey,
      agentName,
      paths: ["src/auth/**"],
      reason: "bd-123.2: Auth service",
      exclusive: true,
    }),
  );

  if (conflicts.length > 0) {
    console.warn("File conflicts detected:", conflicts);
  }

  // 3. Report progress
  yield* Effect.promise(() =>
    sendSwarmMessage({
      projectPath: projectKey,
      fromAgent: agentName,
      toAgents: ["coordinator"],
      subject: "Progress: bd-123.2",
      body: "Reserved files, starting work",
      threadId: "bd-123",
      importance: "normal",
    }),
  );

  // 4. Do work...
  yield* Effect.sleep("5 seconds");

  // 5. Report completion
  yield* Effect.promise(() =>
    sendSwarmMessage({
      projectPath: projectKey,
      fromAgent: agentName,
      toAgents: ["coordinator"],
      subject: "Complete: bd-123.2",
      body: "Auth service implemented",
      threadId: "bd-123",
      importance: "high",
    }),
  );
});

Effect.runPromise(program.pipe(Effect.provide(DurableAskLive)));

Event Sourcing Architecture

Swarm Mail is fully event-sourced. All state changes are events first, materialized views second.

Event Flow

┌─────────────┐
│   Action    │  Agent calls API (e.g., sendMessage)
└──────┬──────┘


┌─────────────┐
│   Create    │  createEvent("message_sent", {...})
│   Event     │  Returns: { type, timestamp, ...payload }
└──────┬──────┘


┌─────────────┐
│   Append    │  appendEvent() → INSERT INTO events
│   to Log    │  Gets auto-increment id + sequence
└──────┬──────┘


┌─────────────┐
│   Update    │  updateProjections() triggers based on event type
│   Views     │  - message_sent → INSERT messages, UPDATE agent read status
└──────┬──────┘  - file_reserved → INSERT reservations
       │         - message_read → UPDATE message read flags

┌─────────────┐
│   Query     │  getInbox(), getMessage(), getReservations()
│   Views     │  Fast queries on materialized tables
└─────────────┘

Event Types

Event TypeTriggerProjections Updated
agent_registeredAgent initagents table
message_sentsendMessage()messages, message_recipients
message_readreadMessage(markAsRead=true)messages.read_by JSONB
message_ackedacknowledgeMessage()messages.acked_by JSONB
file_reservedreserveFiles()reservations
file_releasedreleaseFiles()reservations (DELETE expired)

Why Event Sourcing?

  • Full audit trail - every agent action is logged forever
  • Time travel - replay events to reconstruct past state
  • Debugging - when agents conflict, trace exact sequence of events
  • Learning - analyze event patterns to improve swarm strategies
  • Resumability - cursors checkpoint position, replay from there on crash

Comparison to Agent Mail

Swarm Mail is inspired by Agent Mail (SST's multi-agent coordination layer) but built from scratch with different trade-offs.

AspectAgent Mail (SST)Swarm Mail (This Plugin)
ArchitectureMCP server (external process)Embedded (libSQL in-process)
StorageSQLite filelibSQL (SQLite-compatible)
DependenciesRequires MCP server runningZero external deps, just npm install
Effect-TSNoYes (full Effect integration)
Event SourcingNo (CRUD operations)Yes (append-only event log)
CursorsNo (queries are one-shot)Yes (resumable positioned consumption)
Distributed PromisesNoYes (DurableDeferred)
Type SafetyMCP JSON-RPC (strings)Full TypeScript + Zod validation
Local-FirstRequires serverTrue local-first (no network)
Learning SystemNoYes (eval records, pattern maturity)

When to Use Agent Mail:

  • You're already using OpenCode with MCP infrastructure
  • You need cross-project coordination (multiple repos)
  • You want battle-tested SST ecosystem integration

When to Use Swarm Mail:

  • You want embedded, zero-config coordination
  • You're building Effect-TS applications
  • You need event sourcing and audit trails
  • You want resumable cursors for exactly-once semantics
  • You're using this plugin's learning/swarm features

Database Schema

Swarm Mail uses libSQL (SQLite-compatible embedded database). Schema is managed via migrations.

Core Tables

events - Append-Only Event Log

CREATE TABLE events (
  id SERIAL PRIMARY KEY,
  sequence SERIAL,              -- Auto-increment, never gaps
  type TEXT NOT NULL,           -- Event type (message_sent, file_reserved, etc.)
  timestamp BIGINT NOT NULL,    -- Unix timestamp in ms
  payload JSONB NOT NULL,       -- Event-specific data
  project_key TEXT NOT NULL,
  agent_name TEXT
);
CREATE INDEX idx_events_sequence ON events(sequence);
CREATE INDEX idx_events_type ON events(type);
CREATE INDEX idx_events_project ON events(project_key);

All state changes flow through this table. Other tables are materialized views.

See the Primitives documentation for detailed schema of each primitive's tables.


Effect-TS Integration

Swarm Mail is built with Effect - a functional effect system for TypeScript.

Why Effect?

  • Composability - combine primitives into patterns without callback hell
  • Type inference - full TypeScript inference for errors and dependencies
  • Retries - built-in retry schedules with exponential backoff
  • Resource safety - Effect.ensuring guarantees cleanup (like try/finally)
  • Dependency injection - Layers for services, no globals

Services and Layers

Each primitive is an Effect Service (via Context.Tag):

// Define service interface
export class DurableCursor extends Context.Tag("DurableCursor")<
  DurableCursor,
  DurableCursorService
>() {}

// Implement service
export const DurableCursorLive = DurableCursor.of({
  create: createCursorImpl,
});

// Use service in Effect
const program = Effect.gen(function* () {
  const cursor = yield* DurableCursor; // Service dependency
  const consumer = yield* cursor.create({ stream: "..." });
  // ...
});

// Provide service implementation
Effect.runPromise(program.pipe(Effect.provide(DurableCursorLive)));

Layers compose - higher-level services depend on lower-level ones:

// DurableMailbox depends on DurableCursor
const MailboxLayer = Layer.mergeAll(CursorLayer, DurableMailboxLive);

// Ask pattern depends on Mailbox + Deferred
export const DurableAskLive = Layer.mergeAll(DurableDeferredLive, MailboxLayer);

// Use in program
const program = Effect.gen(function* () {
  const mailbox = yield* DurableMailbox;
  const response = yield* ask({ mailbox, to: "worker-2", payload: {...} });
});

Effect.runPromise(program.pipe(Effect.provide(DurableAskLive)));

Error Handling

Effect has typed errors - errors are part of the Effect signature:

// Effect<Success, Error, Requirements>
type MyEffect = Effect.Effect<number, LockError | TimeoutError, DurableLock>;

// Handle specific error types
yield *
  lockService.acquire("resource").pipe(
    Effect.catchTag("LockTimeout", () => Effect.succeed(null)),
    Effect.catchTag("LockContention", () => Effect.fail(new MyError())),
  );

Credits and Inspiration

  • Kyle Matthews (Founder/CPO @ Electric SQL) - The Durable Streams protocol and the insight that composable primitives can build powerful actor systems. Original tweet
  • Agent Mail - Multi-agent coordination layer for OpenCode (SST). Swarm Mail's API surface is heavily inspired by Agent Mail's design.
  • Electric SQL - Real-time sync engine for Postgres. The cursor pattern and positioned consumption ideas come from Electric's sync protocol.
  • Effect-TS - Functional effect system powering the implementation. Effect's composability and type safety make the primitives ergonomic.

What's Next?

Swarm Mail is production-ready but has room for optimization:

Performance Improvements

  • Connection pooling - reuse libSQL connections instead of opening new ones
  • Batch inserts - batch multiple events into one transaction
  • Index tuning - add covering indexes for hot queries

Features

  • Message priorities - priority queue for urgent messages
  • Dead letter queue - failed messages go to DLQ for retry
  • Message TTL - auto-expire old messages
  • Broadcast channels - pub/sub for topic-based routing
  • Saga pattern - distributed transactions with compensations

Developer Experience

  • DevTools UI - web UI for inspecting events, cursors, locks
  • CLI tools - swarm-mail inspect, swarm-mail replay
  • Metrics - Prometheus metrics for message latency, lock contention
  • Tracing - OpenTelemetry spans for distributed tracing

    *    *  🐝  *    *
  *    *    *    *    *
    🐝   SHIP IT   🐝
  *    *    *    *    *
    *    *  🐝  *    *

On this page