Grand Diomande Research · Full HTML Reader

Agent Swarm

> Autonomous multi-agent task orchestration daemon — ingest work from GitHub, Linear, or internal queues and dispatch to Claude, Codex, or Gemini agents with workspace isolation, state machine tracking, and full audit trails.

Agents That Account for Themselves research note experiment writeup candidate score 40 .md

Full Public Reader

Agent Swarm

> Autonomous multi-agent task orchestration daemon — ingest work from GitHub, Linear, or internal queues and dispatch to Claude, Codex, or Gemini agents with workspace isolation, state machine tracking, and full audit trails.

---

Table of Contents

  • [Overview](#overview)
  • [Architecture](#architecture)
  • [Packages](#packages)
  • [Data Flow](#data-flow)
  • [Setup](#setup)
  • [Configuration](#configuration)
  • [Usage](#usage)
  • [API Reference](#api-reference)
  • [Workflows](#workflows)
  • [Database Schema](#database-schema)
  • [Development](#development)

---

Overview

Agent Swarm sits between your work item sources (GitHub Issues, Linear tickets, internal queues) and AI agents (Claude Code, Codex, Gemini CLI). It fully automates the loop:

1. Ingest — Poll or receive webhooks from GitHub / Linear / machine queue
2. Dispatch — Select the best available agent (by label hints, load, or metadata)
3. Execute — Isolate each task in its own workspace (git clone), render a Liquid prompt, run the agent subprocess
4. Track — Persist every state transition to Supabase for full audit trails
5. Notify — Post Discord messages + update source status (GitHub labels, Linear status) on completion

Tech stack: Bun + TypeScript monorepo (10 workspace packages), Supabase for state, Prometheus for metrics, NUMU Bus for cross-system events.

---

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         Source Providers                             │
│  ┌──────────────┐  ┌──────────────┐  ┌────────────────────────┐    │
│  │ GitHub Issues│  │Linear Tickets│  │  Machine Queue (Spore) │    │
│  │ (webhook +   │  │ (GraphQL     │  │  (Supabase polling)    │    │
│  │  polling)    │  │  polling)    │  │                        │    │
│  └──────┬───────┘  └──────┬───────┘  └──────────┬─────────────┘   │
└─────────┼─────────────────┼────────────────────── ┼────────────────┘
          │                 │                        │
          ▼                 ▼                        ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      swarm-daemon (services/)                        │
│                                                                      │
│  ┌─────────────────┐     ┌──────────────────────────────────────┐   │
│  │ webhook-server  │     │           orchestrator.ts            │   │
│  │ :9300           │────▶│  1. List queued work items           │   │
│  └─────────────────┘     │  2. selectAgent() (label/load)       │   │
│                           │  3. WorkspaceManager.create()        │   │
│  ┌─────────────────┐     │  4. OrbitBridge.enrich()             │   │
│  │ api-server      │     │  5. PromptRenderer.render()          │   │
│  │ :9301           │     │  6. AgentAdapter.startSession()       │   │
│  └─────────────────┘     │  7. Stream AgentEvents               │   │
│                           │  8. Transition state + notify        │   │
│  ┌─────────────────┐     └──────────────────────────────────────┘   │
│  │ metrics         │                       │                         │
│  │ :9302           │                       │                         │
│  └─────────────────┘                       ▼                         │
└────────────────────────────────────────────┼────────────────────────┘
                                             │
          ┌────────────────┬─────────────────┼─────────────────┐
          ▼                ▼                 ▼                   ▼
   ┌─────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
   │  Supabase   │  │ Agent CLI    │  │   Discord    │  │  NUMU Bus    │
   │ State + FSM │  │ Claude/Codex │  │ Notifications│  │ :7890 Events │
   │ Audit trail │  │ /Gemini/SSH  │  │              │  │              │
   └─────────────┘  └──────────────┘  └──────────────┘  └──────────────┘

State Machine

Work items flow through these states:

queued ──▶ preparing ──▶ running ──┬──▶ succeeded ✓
   └──▶ cancelled ✗          ├──▶ failed ✗
                              ├──▶ retrying ──▶ running
                              └──▶ waiting_approval ──▶ running

Every transition is written to `swarm_transitions` for a full audit trail.

---

Packages

The monorepo contains 10 packages under `packages/` plus the main daemon in `services/`:

PackageDescription
`@swarm/agent-adapters`Unified CLI wrappers for Claude Code, Codex, Gemini, SSH-Claude
`@swarm/state-machine`Pure FSM transition logic + Supabase store
`@swarm/source-providers`GitHub, Linear, and Machine Queue ingest adapters
`@swarm/prompt-renderer`Liquid template engine for workflow prompts
`@swarm/workspace-manager`Per-task filesystem isolation + git cloning
`@swarm/orbit-bridge`Orbit project context enrichment
`@swarm/numu-bridge`WebSocket client for NUMU Bus event publishing
`@swarm/discord`Discord message formatting and channel posting
`@swarm/metrics`Prometheus Counter, Gauge, Histogram exposition
`@swarm/logger`Structured JSON logger with sensitive-data redaction
`swarm-daemon` _(service)_Main daemon — bootstraps all servers and loops

---

Data Flow

GitHub Issue opened
        │
        ▼
webhook-server (:9300)
   HMAC verify → SourceProvider.handleWebhook()
        │
        ▼
WorkItem normalized (externalId, title, description, labels, git info)
        │
        ▼
SupabaseStore.create() → status: "queued"
        │
        ▼
Dispatch loop (every 30s)
   listByStatus("queued")
   selectAgent() ──► label hint? → metadata pref? → load balance
        │
        ▼
WorkspaceManager.createForIssue()
   mkdir [home-path]
   git clone --depth=1 <repo>
        │
        ▼
OrbitBridge.enrich() → inject project context
        │
        ▼
PromptRenderer.render(workflow, issue)
   pick template by labels (feature-impl.md, bug-fix.md, ios-build.md…)
   Liquid render with issue variables
        │
        ▼
AgentAdapter.startSession({ cwd, model, approvalMode, prompt })
   spawn: claude --dangerously-skip-permissions --output-format stream-json
        │
        ▼
Stream AgentEvents:
   text_delta → accumulate
   tool_start / tool_result → log
   approval_request → auto-approve or pause
   session_end
        │
        ▼
SupabaseStore.transition("running" → "succeeded" | "failed")
SourceProvider.updateStatus() → GitHub label, Linear status
Discord.postCompletion()
NUMUBridge.publish("swarm.task.complete", { ... })
WorkspaceManager.scheduleCleanup(hours)

---

Setup

Prerequisites

  • [Bun](https://bun.sh) v1.0+
  • A [Supabase](https://supabase.com) project
  • GitHub personal access token (or App installation token)
  • At least one agent CLI installed: `claude`, `codex`, or `gemini`

Install

bash
git clone https://github.com/Diomandeee/agent-swarm
cd agent-swarm
bun install

Database Migration

Apply the Supabase migration to create the required tables:

bash
# Via Supabase CLI
supabase db push --db-url "postgresql://..."

# Or manually in the Supabase SQL editor
cat migrations/001_swarm_work_items.sql | supabase sql

This creates:
- `swarm_work_items` — work item records with full metadata
- `swarm_transitions` — FSM audit log (every state change)

Environment

Copy and fill in the environment file:

bash
cp .env.example .env

See [Configuration](#configuration) for all available options.

---

Configuration

All configuration is via environment variables (or a `.env` file):

Required

VariableDescription
`SUPABASE_URL`Your Supabase project URL
`SUPABASE_SERVICE_KEY`Supabase service role key (bypasses RLS)

GitHub (required for GitHub source)

VariableDescription
`GITHUB_TOKEN`Personal access token or App token
`GITHUB_WEBHOOK_SECRET`Secret for HMAC webhook verification
`GITHUB_ORG`Organization name (e.g. `Diomandeee`)

Linear (optional)

VariableDefaultDescription
`LINEAR_API_KEY`Linear API key
`LINEAR_TEAM_KEYS`Comma-separated team keys to watch
`LINEAR_TRIGGER_LABELS``swarm,auto`Labels that trigger dispatch
`LINEAR_POLL_INTERVAL_MS``60000`How often to poll Linear (ms)

Ports

VariableDefaultDescription
`SWARM_WEBHOOK_PORT``9300`GitHub/Linear webhook receiver
`SWARM_API_PORT``9301`REST API + metrics endpoint
`SWARM_METRICS_PORT``9302`Dedicated Prometheus metrics port

Daemon Behavior

VariableDefaultDescription
`SWARM_POLL_INTERVAL_MS``30000`Dispatch loop poll interval
`SWARM_MAX_SESSIONS``3`Max concurrent agent sessions
`SWARM_APPROVAL_MODE``auto-all``auto-all`, `auto-edit`, `manual`
`SWARM_WORKSPACE_ROOT``[home-path]`Root dir for task workspaces
`SWARM_WORKSPACE_CLEANUP_HOURS``24`Hours to keep workspace after completion
`SWARM_GIT_DEPTH``1`Git clone depth

Notifications

VariableDefaultDescription
`DISCORD_ENABLED``false`Enable Discord notifications
`DISCORD_WEBHOOK_URL`Discord webhook URL
`DISCORD_OPS_CHANNEL`Channel ID for ops alerts

NUMU Bus

VariableDefaultDescription
`NUMU_HOST``localhost`NUMU Bus WebSocket host
`NUMU_PORT``7890`NUMU Bus WebSocket port

Logging

VariableDefaultDescription
`LOG_LEVEL``info``debug`, `info`, `warn`, `error`

---

Usage

Start the Daemon

bash
# Development (with hot reload)
bun run dev

# Production
bun build services/swarm-daemon/src/index.ts --outdir dist --target bun
bun dist/index.js

Register GitHub Webhook

In your GitHub repo/org settings, add a webhook pointing to:

https://your-host:9300/webhooks/github
  • Content type: `application/json`
  • [sensitive field redacted]`GITHUB_WEBHOOK_SECRET`
  • Events: `Issues`

Trigger a Task via Label

Add the `swarm` label to any GitHub issue. The daemon will:
1. Ingest the issue on next poll (or immediately via webhook)
2. Create a workspace, clone the repo
3. Render the appropriate workflow template
4. Dispatch to an available agent
5. Update the issue with a completion comment + label change

Manual Task via API

bash
curl -X POST http://localhost:9301/work-items \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Refactor auth module",
    "description": "Clean up the JWT validation logic in src/auth/",
    "source": "manual",
    "labels": ["refactor"],
    "gitRepoUrl": "https://github.com/Diomandeee/myapp",
    "gitBranch": "main"
  }'

Force a Specific Agent

Add labels to route to a specific agent:
- `agent:claude` — use Claude Code
- `agent:codex` — use Codex CLI
- `agent:gemini` — use Gemini CLI

Or set `agentKind` in the API payload.

Check Status

bash
# List all running tasks
curl http://localhost:9301/work-items?status=running

# Get Prometheus metrics
curl http://localhost:9301/metrics

# Check a specific item
curl http://localhost:9301/work-items/<uuid>

---

API Reference

`GET /work-items`

List work items, optionally filtered by status.

Query params:
- `status` — filter by state (`queued`, `running`, `succeeded`, `failed`, etc.)
- `limit` — max results (default: 50)
- `source` — filter by source kind (`github`, `linear`, `manual`, `machine_queue`)

Response:

json
[
  {
    "id": "uuid",
    "title": "Fix login bug",
    "status": "running",
    "agentKind": "claude",
    "source": "github",
    "externalId": "123",
    "url": "https://github.com/...",
    "createdAt": "2026-03-17T10:00:00Z",
    "updatedAt": "2026-03-17T10:05:00Z"
  }
]

`POST /work-items`

Manually enqueue a work item.

Body:

json
{
  "title": "string (required)",
  "description": "string",
  "source": "manual",
  "labels": ["string"],
  "agentKind": "claude | codex | gemini",
  "gitRepoUrl": "string",
  "gitBranch": "string",
  "priority": 0,
  "metadata": {}
}

`PATCH /work-items/:id/status`

Manually override work item status (admin use).

Body:

json
{ "status": "cancelled" }

`GET /metrics`

Prometheus exposition format. Key metrics:

MetricTypeDescription
`swarm_tasks_total`CounterTotal tasks by status/agent/source
`swarm_active_sessions`GaugeCurrently running agent sessions
`swarm_task_duration_seconds`HistogramTask execution time
`swarm_queue_depth`GaugeItems in queued state
`swarm_retries_total`CounterRetry events by reason

`POST /webhooks/github`

GitHub webhook receiver (HMAC-verified). Handles `issues.opened`, `issues.labeled`, `issues.edited`.

`POST /webhooks/linear`

Linear webhook receiver. Handles issue create/update events for watched teams.

---

Workflows

Liquid Markdown templates in `workflows/` define the instructions rendered for each task type. The daemon selects a template based on issue labels (first match wins):

TemplateTrigger LabelsAgentApproval
`feature-impl.md``feature`, `enhancement`claudeauto-all
`bug-fix.md``bug`, `fix`claudeauto-all
`refactor.md``refactor`, `cleanup`claudeauto-edit
`test-coverage.md``test`, `coverage`claudeauto-all
`security-audit.md``security`, `audit`claudemanual
`ios-build.md``ios`, `xcode`, `build`claudeauto-all
`app-evolution.md``evolution`, `evo`claudeauto-all
`default.md`_(fallback)_claudeauto-all

Writing a Custom Workflow

Create `workflows/my-task.md`:

markdown
---
name: My Custom Task
agent: claude
approval_mode: auto-all
max_retries: 2
timeout_seconds: 900
labels: [my-label]
---

# Task: {{ issue.title }}

## Context
Repository: {{ issue.gitRepoUrl }}
Branch: {{ issue.gitBranch | default: "main" }}
Workspace: {{ workspace.path }}

## Issue Description
{{ issue.description }}

{% if issue.labels %}
## Labels
{{ issue.labels | join: ", " }}
{% endif %}

## Instructions
1. Read the codebase in {{ workspace.path }}
2. Implement the requested changes
3. Ensure all tests pass
4. Create a summary of changes made

---

Database Schema

`swarm_work_items`

sql
CREATE TABLE swarm_work_items (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  external_id     TEXT,                    -- GitHub issue number, Linear ID
  identifier      TEXT UNIQUE,             -- e.g. "github/Diomandeee/myapp/123"
  title           TEXT NOT NULL,
  description     TEXT,
  source_kind     TEXT NOT NULL,           -- "github" | "linear" | "manual" | "machine_queue"
  project         TEXT,
  priority        INTEGER DEFAULT 0,
  labels          TEXT[] DEFAULT '{}',
  status          TEXT NOT NULL DEFAULT 'queued',
  agent_kind      TEXT,                    -- "claude" | "codex" | "gemini"
  session_id      TEXT,
  workspace_path  TEXT,
  retry_count     INTEGER DEFAULT 0,
  max_retries     INTEGER DEFAULT 3,
  git_repo_url    TEXT,
  git_branch      TEXT DEFAULT 'main',
  url             TEXT,
  metadata        JSONB DEFAULT '{}',
  created_at      TIMESTAMPTZ DEFAULT now(),
  updated_at      TIMESTAMPTZ DEFAULT now()
);

`swarm_transitions`

sql
CREATE TABLE swarm_transitions (
  id              BIGSERIAL PRIMARY KEY,
  work_item_id    UUID NOT NULL REFERENCES swarm_work_items(id),
  from_status     TEXT NOT NULL,
  to_status       TEXT NOT NULL,
  event_type      TEXT NOT NULL,
  event_data      JSONB DEFAULT '{}',
  created_at      TIMESTAMPTZ DEFAULT now()
);

---

Development

Project Structure

agent-swarm/
├── migrations/              # Supabase DDL (apply once)
├── packages/
│   ├── agent-adapters/      # Claude/Codex/Gemini/SSH adapter interfaces
│   ├── discord/             # Notification formatting
│   ├── logger/              # Structured logger
│   ├── metrics/             # Prometheus client
│   ├── numu-bridge/         # NUMU Bus WebSocket client
│   ├── orbit-bridge/        # Orbit context enrichment
│   ├── prompt-renderer/     # Liquid template engine
│   ├── source-providers/    # GitHub + Linear + Machine Queue
│   ├── state-machine/       # FSM + Supabase store
│   └── workspace-manager/   # Git workspace isolation
├── services/
│   └── swarm-daemon/
│       └── src/
│           ├── index.ts         # Bootstrap (servers + loops)
│           ├── orchestrator.ts  # Core dispatch loop
│           ├── dispatch.ts      # Agent selection logic
│           ├── api-server.ts    # REST API + metrics
│           ├── webhook-server.ts# GitHub/Linear receiver
│           └── config.ts        # Zod-validated config
├── workflows/               # 13 Liquid task templates
├── .env.example
└── package.json             # Bun workspaces manifest

Common Commands

bash
# Install all workspace dependencies
bun install

# Run daemon with hot reload
bun run dev

# Type check across all packages
bunx tsc --noEmit

# Run tests
bun test

# Build production binary
bun build services/swarm-daemon/src/index.ts --outdir dist --target bun

# Lint
bunx eslint packages/ services/

Adding a New Source Provider

1. Create `packages/source-providers/src/my-source.ts`
2. Implement the `SourceProvider` interface:

typescript
   export interface SourceProvider {
     initialize(): Promise<void>
     poll?(): Promise<SourceEvent[]>
     handleWebhook?(payload: unknown, headers: Headers): Promise<SourceEvent[]>
     updateStatus(item: StoredWorkItem, status: WorkItemStatus): Promise<void>
     postComment(item: StoredWorkItem, body: string): Promise<void>
     getWorkItem(externalId: string): Promise<WorkItem | null>
   }

3. Register in `services/swarm-daemon/src/index.ts`

Adding a New Agent Adapter

1. Create `packages/agent-adapters/src/my-agent.ts`
2. Implement the `AgentAdapter` interface:

typescript
   export interface AgentAdapter {
     startSession(config: SessionConfig): Promise<string>
     sendPrompt(sessionId: string, prompt: string): AsyncIterableIterator<AgentEvent>
     respondToApproval(sessionId: string, approved: boolean): Promise<void>
     interrupt(sessionId: string): Promise<void>
     endSession(sessionId: string): Promise<void>
     isAlive(sessionId: string): boolean
     shutdown(): Promise<void>
   }

3. Add to the factory in `packages/agent-adapters/src/factory.ts`

---

Integration with the Mesh

Agent Swarm integrates with the broader mesh infrastructure:

  • NUMU Bus (`:7890`) — Publishes `swarm.task.*` events for cross-system visibility
  • Supabase (`aaqbofotpchgpyuohmmz`) — Shares the same project with other mesh services
  • Orbit — Enriches task prompts with project context from the Orbit graph
  • Discord — Posts to ops channel on task completion / failure
  • Prometheus — Metrics scraped by Grafana dashboard (`:3000`)
  • Machine Queue — Accepts Spore dispatch events from `swarm_machine_queue` table

LaunchAgent (macOS)

The daemon runs as a macOS LaunchAgent (`com.swarm.daemon`) on Mac1:

bash
# Load
launchctl load [home-path]

# Status
launchctl list | grep swarm

# Logs
tail -f [home-path]

---

License

Private — internal tooling for the OpenClaw / Diomandeee portfolio.

Promotion Decision

Attach run IDs, datasets, metrics, and reproduction commands.

Source Anchor

projects/agent-swarm/README.md

Detected Structure

Method · Evaluation · References · Code Anchors · Architecture