Skip to content

Latest commit

 

History

3,622 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Omni — One API, Every Channel

Apache 2.0 License Bun v2.260908.13 11 channels NATS JetStream

Universal event-driven omnichannel messaging platform

One API to send, receive, route, and automate messages across WhatsApp, Discord, Slack, Telegram, and more.
CLI-first. Event-driven. Built for AI agents.

InstallQuick StartAI AgentsCLIAPISDKsDevelopment


Think of Omni as a deep-sea octopus. Each channel is a tentacle reaching into a different messaging ecosystem. Events are nerve impulses flowing through NATS JetStream. The core is the brain: identity resolution, event routing, and a unified API that lets you treat every channel as one system.

Why Omni?

🔌 One API, every channel Send WhatsApp, Discord, Slack, Telegram, and other channel messages with one interface
Event-driven Every action produces an event. Subscribe, replay, automate
🧬 Identity graph Resolve the same person across channels and instances
🤖 AI-native Provider bindings, response gates, session strategies, automations, and agent dispatch
🔧 Plugin architecture Build channels and integrations with the Channel SDK
📦 SDKs TypeScript SDK, plus generated Python/Go clients for API consumers

Channels

Channel Status Highlights
WhatsApp (Baileys) ✅ Stable QR/phone pairing, media, reactions, groups, contacts, presence
WhatsApp Cloud API (Meta) ✅ Available Embedded Signup OAuth, templates HSM, webhook (HMAC-SHA256), media, location, reactions
Discord ✅ Stable Bots, embeds, polls, buttons, threads, slash commands, voice channels
Slack ✅ Available Socket Mode or HTTP, bot & user (xoxp) token modes, threads, scheduled messages, permalinks, pins, message search
Telegram ✅ Available Bot API, inline keyboards, groups, channels, threads, polls
A2A ✅ Available Agent-to-agent channel integrations
Gupshup ✅ Available Custom Integration webhook support
H3rmes (Mutant) ✅ Available Brazilian WhatsApp gateway — JWT auth, media, templates, interactive, Pix-ready webhook shapes
ASC Brazil ✅ Available Brazilian WhatsApp BSP — Cloud API mirror, Meta-format webhooks, typing indicator, templates, interactive
ASC Flow ✅ Available Brazilian BSP via the ASC platform Flow — REST callbacks, URA buttons/lists, Genesys handoff
Twilio WhatsApp ✅ Available Twilio sender, webhook, and signature validation support

Also in the box: Harness (--channel harness), an E2E agent-testing channel that captures outgoing messages verbatim so you can drive and assert on agent conversations from tests, and an internal channel used for agent-to-agent routing.

Install

Global CLI package

bun add -g @automagik/omni
omni install              # bootstrap the local server/runtime with PM2

Migrating from @omni/cli? Run bun remove -g @omni/cli first.

Via install script

curl -fsSL https://raw.githubusercontent.com/automagik-dev/omni/main/install.sh | bash

Full server from source

curl -fsSL https://raw.githubusercontent.com/automagik-dev/omni/main/install.sh | bash -s -- --server

Supported script modes: CLI only (--cli) and Full server (--server).

Non-interactive & manual install
# CLI only
curl -fsSL https://raw.githubusercontent.com/automagik-dev/omni/main/install.sh | bash -s -- --cli

# Full server
curl -fsSL https://raw.githubusercontent.com/automagik-dev/omni/main/install.sh | bash -s -- --server

# Connect the CLI to a remote server after install
omni auth login --api-url https://your-omni-server.example.com --api-key <your-api-key>

Manual:

git clone https://github.com/automagik-dev/omni.git && cd omni
make setup    # install deps, create .env, start services

API runs at http://localhost:8882 · Swagger docs at /api/v2/docs · API key is printed in the startup banner.

Quick Start

# Authenticate
omni auth login --api-key <your-api-key>

# WhatsApp — scan QR
omni instances create --name "my-whatsapp" --channel whatsapp-baileys
omni instances qr <id> --watch

# Discord — connect bot
omni instances create --name "my-discord" --channel discord --discord-token <discord-bot-token>
omni instances connect <id>

# Telegram — connect bot
omni instances create --name "my-telegram" --channel telegram --telegram-token <telegram-bot-token>
omni instances connect <id>

# Send messages
omni send --to "+15555550100" --text "Hello from the deep 🐙"

# Browse conversations
omni chats list --unread --sort unread

AI Agents

Connect an agent provider and your instances can respond to messages, react to events, and route conversations across channels.

Message received → NATS event → Agent Dispatcher → Provider → Response gate → Channel reply
# Create a provider
omni providers create \
  --name "my-agent" \
  --schema webhook \
  --base-url "https://agent.example.com/webhook" \
  --api-key <provider-api-key>

# Bind it to an instance
omni instances update <id> --agent-provider <provider-id>

Provider schemas: agno · webhook · openclaw · ag-ui · claude-code · a2a · nats-genie

Trigger When Use Case
DM Direct message Always reply
Mention @bot in group Respond to mentions
Reply Reply to bot's message Continue thread
Reaction Emoji on message Approvals, priority, lightweight workflows

Built-in: message debouncing · per-user rate limits · access control · response gates · smart chunking · typing presence · cross-channel identity · self-chat detection

Automations & event-driven workflows
# Auto-reply
omni automations create --name "welcome" \
  --trigger "message.received" \
  --action send_message --action-config '{"text":"Got it! 🐙"}'

# Webhook on connection
omni automations create --name "notify" \
  --trigger "instance.connected" \
  --action webhook --action-config '{"url":"https://your-app.example.com/hook"}'

# Route important senders to a dedicated agent
omni automations create --name "priority-route" \
  --trigger "message.received" \
  --condition '{"field":"payload.from","op":"in","value":["+15555550100"]}' \
  --action call_agent --agent-id "priority-handler" --provider-id <provider-id>

Event Backbone

Every state change lands in a total-ordered PostgreSQL journal and is published over NATS. The journal is the source of truth — you can filter it, trace it, wait on it, and consume it durably:

omni events list --type "message.*" --since 2h        # trailing-* glob type filters
omni events types --since 7d                          # what's flowing: volume, schema status, subscribers
omni events stream --pretty --exclude "custom.chat.*" # live tail, one line per event, minus the noise
omni events trace <event-id>                          # causation chain, rendered as a tree
omni events wait --type "custom.github.*" --timeout 60  # block until a matching event arrives

# Durable named consumers — resumable cursors over the journal
omni events consumers create deploy-watcher --type "custom.github.*"
omni events follow --consumer deploy-watcher          # at-least-once, acks as it goes

Webhook sources turn external systems into event emitters with configuration only — no code: raw-body signature verification (HMAC-SHA256/SHA1 or token match), per-source idempotency key templates, event-type mapping to custom.<source>.<event>, optional strict schema validation, and heartbeat-based connector liveness (system.connector.stalled / recovered). Working recipes: GitHub and ClickUp.

Event schemas are registered once (omni events schema register) and enforced at webhook ingress and automation emit_event — invalid payloads dead-letter instead of entering the journal.

Agent manifests declare what each agent consumes and publishes (omni agents manifest apply, omni agents graph): the publishes list is enforced at emission time, and accepts compiles into managed routing automations. Automations can also buffer their emitted events and flush them in order only when the whole run succeeds (--transactional-emissions).

Deep dives: event system · durable consumers · agent publish governance

Architecture

┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│  WhatsApp   │  │   Discord   │  │    Slack    │  │  Telegram   │  Tentacles
└──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘
       └────────────────┴────────────────┴────────────────┘
                         ┌─────────▼─────────┐
                         │   NATS JetStream  │             Nerve system
                         └─────────┬─────────┘
                         ┌─────────▼─────────┐
                         │     Omni Core     │             Brain
                         └─────────┬─────────┘
              ┌────────────────────┼────────────────────┐
        ┌─────▼─────┐        ┌─────▼─────┐        ┌─────▼─────┐
        │  REST API │        │    CLI    │        │ Dashboard │ Interfaces
        └───────────┘        └───────────┘        └───────────┘
Project structure
packages/
├── core/                    # Events, identity, schemas
├── db/                      # Drizzle ORM + PostgreSQL
├── api/                     # Hono + tRPC + OpenAPI
├── channel-sdk/             # Plugin SDK
├── channel-whatsapp/        # WhatsApp Baileys
├── channel-whatsapp-business/ # WhatsApp Cloud API (Meta)
├── channel-discord/         # Discord
├── channel-slack/           # Slack
├── channel-telegram/        # Telegram
├── channel-gupshup/         # Gupshup
├── channel-hermes/          # H3rmes (Brazilian WhatsApp gateway)
├── channel-twilio-whatsapp/ # Twilio WhatsApp
├── channel-a2a/             # A2A channel
├── channel-asc/             # ASC Brazil (ASCWhats GW, Cloud API mirror)
├── channel-asc-flow/        # ASC platform Flow (Brazilian BSP)
├── channel-harness/         # E2E agent-testing channel
├── channel-internal/        # In-process agent-to-agent routing
├── cli/                     # `omni` command
├── media-processing/        # Media sync and extraction
├── plugin-openclaw/         # Omni as a channel inside OpenClaw
├── voice-client/            # Voice transport/codec library (Discord voice)
├── sdk/                     # TypeScript SDK
├── sdk-go/                  # Go SDK
└── sdk-python/              # Python SDK
apps/
└── ui/                      # React + Vite + Tailwind dashboard

CLI Reference

Core commands — send, chats, messages, instances, persons

send — Send messages

omni send --to "+15555550100" --text "Hello!"
omni send --to "+15555550100" --media ./photo.jpg --caption "Check this out"
omni send --to "+15555550100" --reaction "👍" --message <message-id>
omni send --to "+15555550100" --sticker ./sticker.webp
omni send --to "+15555550100" --contact --name "Example User" --phone "+15555550101"
omni send --to "+15555550100" --location --lat 37.7749 --lng -122.4194 --address "San Francisco"
omni send --to "discord-channel-id" --poll "Favorite color?" --options "Red,Blue,Green"
omni send --to "discord-channel-id" --embed --title "Alert" --description "Server rebooting" --color "#ff0000"
omni send --to "+15555550100" --presence typing

chats — Manage conversations

omni chats list --unread --sort unread
omni chats messages <chat-id> --limit 20 --rich
omni chats archive <chat-id>
omni chats participants <chat-id> --add "+15555550100"

messages — Search and manage

omni messages search "meeting tomorrow" --instance <id> --limit 10
omni messages read --chat <chat-id> --instance <id>

instances — Channel connections

omni instances list
omni instances create --name "work-whatsapp" --channel whatsapp-baileys
omni instances qr <id> --watch
omni instances create --name "ops-slack" --channel slack --slack-bot-token <bot-token> --slack-app-token <app-token>
omni instances connect <id>
omni instances sync <id> --type all --depth 30
omni instances contacts <id> --limit 50
omni instances groups <id>

Run omni instances --help for the full channel-specific command list.

persons — Contact directory

omni persons search "Example User"
omni persons get <id>
omni persons presence <id>
Management — keys, providers, automations, access, webhooks, schedule, tenants

keys — API key management

omni keys create --name "agent-key" --scopes "messages:*,instances:read"
omni keys list --status active
omni keys revoke <id> --reason "Compromised"

providers — AI/agent providers

omni providers create --name "webhook-agent" --schema webhook --base-url "https://agent.example.com" --api-key <provider-api-key>
omni providers list
omni providers test <id>

Schemas: agno · webhook · openclaw · ag-ui · claude-code · a2a · nats-genie

automations — Event-driven workflows

omni automations create --name "Auto-reply" --trigger "message.received" \
  --action send_message --action-config '{"text":"Got it!"}'
omni automations list --enabled
omni automations test <id> --event <event-id>   # dry-run against a real journaled event: condition verdicts, no side effects

Actions: webhook · send_message · emit_event · log · call_agent

access — Access control

omni access create --type deny --instance <id> --phone "+15555550100" --action block
omni access list --instance <id>
omni access check --instance <id> --user "+15555550100"

Modes: disabled · blocklist · allowlist

webhooks — External event sources

omni webhooks create --name "github-events" \
  --signature-algorithm hmac-sha256 --signature-header "X-Hub-Signature-256" --signature-prefix "sha256=" \
  --signature-secret-env GITHUB_WEBHOOK_SECRET \
  --event-type-mapping '{"source":"header","header":"X-GitHub-Event"}' \
  --idempotency-key-template "github:{headers.x-github-delivery}"
omni webhooks heartbeat github-events            # connector liveness check-in
omni webhooks trigger --type "custom.event" --payload '{"key":"value"}'

Sources receive on the public POST /api/v2/webhooks/ingress/:source endpoint (signature required). See the GitHub and ClickUp recipes.

schedule — Scheduled messages

omni schedule send <instance> <chat-id> "Stand-up in 10" --at 2h   # ISO timestamp or 30m/2h/3d
omni schedule list <instance>
omni schedule cancel <id>

Delivery is native where the channel supports it (Slack, text-only); everywhere else a local sweeper sends at the scheduled time.

tenants — Platform tenant control plane

omni tenants create --slug acme --name "Acme" --max-key-ttl 7776000 --max-key-rate 100 --max-key-budget 1000 --reason "onboarding"
omni tenants keys issue-root <tenant-id> --principal <uuid> --membership <uuid> --role tenant-owner \
  --name root --scopes "tenant:*" --expires 2026-12-01 --rate-limit 100 --budget 1000 --reason "bootstrap"
omni multitenancy status

Requires a PLATFORM-class credential and OMNI_MULTITENANCY_ENABLED=true; every command takes an audited --reason. Omni runs single-tenant by default — see platform credential bootstrap.

System — update, status, doctor, auth, config, events, logs
omni update -y                                  # update CLI; restart only services that were already online
omni update -y --no-restart                     # update CLI only; skip restarts and API-port health check
omni status                                     # verify runtime health
omni doctor                                     # diagnose embedded runtime issues
omni doctor --fix                               # repair safe runtime drift in-place
omni auth login --api-key <your-api-key>        # authenticate
omni config set defaultInstance <id>            # CLI settings
omni events list --type "message.*" --since 2h  # event history (trailing-* globs)
omni events types                               # observed event types: volume, schema, subscribers
omni events stream --pretty                     # live tail, one colored line per event
omni events trace <event-id>                    # causation chain
omni events wait --type "custom.x.*" --timeout 60  # block until a matching event
omni events schema register <type> --file s.json   # register a payload schema
omni events schema validate <type> --file p.json   # dry-run a payload, no event emitted
omni events consumers create <name> --type "custom.x.*"  # durable cursor
omni events follow --consumer <name>            # durable tail
omni events replay --start --since 2024-01-01   # replay events
omni journey show <correlation-id>              # per-message latency timeline
omni batch create --instance <id> --type targeted_chat_sync --chat <chat-id>
omni resync --instance <id>                     # history backfill
omni logs list --level error --limit 50         # server logs
omni dead-letters list --limit 20               # failed events

omni update can exit non-zero after install only when restart runs (services were already online): in that path it checks API health on the configured API port and fails on restart or health-check errors.

omni doctor --fix never deletes database data. It repairs safe runtime drift such as PM2 state, stored env, and CLI config; destructive cleanup remains manual.

REST API

Base URL http://localhost:8882/api/v2
Docs /api/v2/docs (Swagger UI)
OpenAPI /api/v2/openapi.json
Auth x-api-key header

Main API groups include: /auth, /instances, /messages, /chats, /events (plus /events/schemas, /events/consumers, and per-event /trace), /persons, /access, /settings, /providers, /automations, /webhooks, /scheduled-messages, /keys, /logs, /batch-jobs, /dead-letters, /media, /metrics, /event-ops, /payloads, /agents, /agent-state, /agent-tasks, /conversations, /context, /turns, /trust, /voice, /follow-up, /handoffs, /journeys, /instances/:id/whatsapp-templates, and /platform (multitenancy control plane, flag-gated).

SDKs

TypeScript

import { createOmniClient } from '@omni/sdk';

const omni = createOmniClient({
  baseUrl: 'http://localhost:8882',
  apiKey: '<your-api-key>',
});

await omni.messages.send({
  instanceId: '<instance-id>',
  to: '+15555550100',
  text: 'Hello from SDK!',
});

Python and Go

Generated Python and Go clients live in packages/sdk-python and packages/sdk-go. They are useful for API consumers, but the TypeScript SDK is the primary maintained SDK for this release.

Regenerate SDKs after API changes:

make sdk-generate

Web Dashboard

make dev-ui    # Dev → http://localhost:5173
make build-ui  # Prod → served by API on :8882

Pages: Dashboard · Instances · Chats · Chat View · Contacts · Persons · Providers · Automations · Access Rules · Batch Jobs · Dead Letters · Events · Logs · Voices · Settings

🔐 API Keys & Security

API key is generated on first boot and shown once in the startup banner.

omni keys create --name "admin" --scopes "*"
omni keys create --name "reader" --scopes "messages:read,chats:read"
omni keys create --name "channel-only" --scopes "messages:*" --instances "uuid1,uuid2"

Scopes use the namespace:action pattern: messages:*, instances:read, * for full access.

Namespaces include: messages, chats, instances, persons, events, access, settings, providers, automations, webhooks, keys, logs, and batch.

⚙️ Configuration & environment
Variable Default Description
API_PORT 8882 API server port
DATABASE_URL postgresql://...localhost:8432/omni PostgreSQL
NATS_URL nats://localhost:4222 NATS connection
OMNI_API_KEY (auto) Override primary key

Set *_MANAGED=false for external services. Full list: .env.example.

Service PM2 Name (installer / source checkout) Port
API omni-api / omni-v2-api 8882
NATS omni-nats / omni-v2-nats 4222
PostgreSQL autopg-server (canonical pgserve, managed by omni install) 8432

Development

make dev           # Start all services + API
make dev-ui        # Start dashboard dev server
make test          # Run test suite
make typecheck     # TypeScript checks
make lint          # Biome lint
make sdk-generate  # Regenerate SDKs from OpenAPI
Configuration and environment
Variable Default Description
API_PORT 8882 API server port
DATABASE_URL postgresql://user:password@localhost:8432/omni PostgreSQL connection
NATS_URL nats://localhost:4222 NATS connection
OMNI_API_KEY auto-generated Override primary API key

Set *_MANAGED=false for external services. Full list in .env.example.

Service PM2 Name (installer / source checkout) Port
API omni-api / omni-v2-api 8882
NATS omni-nats / omni-v2-nats 4222
PostgreSQL autopg-server (canonical pgserve, managed by omni install) 8432

Channel SDK

import { BaseChannelPlugin } from '@omni/channel-sdk';
import type { InstanceConfig, OutgoingMessage } from '@omni/channel-sdk';

export class MyPlugin extends BaseChannelPlugin {
  readonly id = 'my-channel';
  readonly name = 'My Channel';
  readonly version = '1.0.0';
  readonly capabilities = { /* ... */ };

  async connect(instanceId: string, config: InstanceConfig) { /* ... */ }
  async disconnect(instanceId: string) { /* ... */ }
  async sendMessage(instanceId: string, message: OutgoingMessage) { /* ... */ }
}

Tech Stack

Runtime Bun
HTTP Hono
API tRPC + OpenAPI
DB PostgreSQL + Drizzle
Events NATS JetStream
Validation Zod
Frontend React + Vite + Tailwind
Monorepo Turborepo
Linter Biome

Apache-2.0 — do whatever you want, just don't blame the octopus. 🐙

About

Universal event-driven omnichannel platform for AI agents to communicate across any messaging platform

Topics

Resources

Security policy

Stars

36 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages