βββββββ ββββ ββββ βββββββ
ββββββββββββββ ββββββββββββββ
βββ βββββββββββββββββ βββ
βββ βββββββββββββββββ βββ
ββββββββββββ βββ ββββββββββββ
βββββββ βββ βββ βββββββ
G A T E W A Y
High-performance, Zero-GC Discord Multiplexer Gateway for OMO (oh-my-openagent) in 100% Rust.
OMO Gateway is a dedicated, ultra-fast Rust gateway that bridges OMO (oh-my-openagent) directly to Discord.
It multiplexes thousands of concurrent channels, threads, and DMs with sub-millisecond routing, multi-bot sharding, scale-to-zero memory reclamation, and sandboxed tool execution.
OMO (oh-my-openagent) provides autonomous agent intelligence, deep planning, and subagent orchestration. However, running AI agents directly against Discord's WebSocket APIs creates operational bottlenecks:
- Heavy Idle Memory: Running individual Discord connections per agent consumes hundreds of megabytes.
- Concurrency & Rate Limits: Managing token streaming across many channels triggers Discord rate-limit bans without centralized debouncing.
- Multi-Bot Management: Running multiple bot identities requires running multiple redundant runtime instances.
OMO Gateway solves this by acting as a high-throughput, pure-Rust I/O multiplexer sitting between Discord and OMO.
[ Discord Ingress: DMs / Server Channels / Threads / Voice ]
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OMO GATEWAY (Pure Rust) β
β β
β βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β Session Multiplexer β β Delivery Ledger β β
β β (Lock-Free DashMap) β β (SQLite WAL Idempotent)β β
β ββββββββββββββ¬βββββββββββββ βββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Bounded Actor Worker Pool (tokio::task) β β
β β - Scale-to-Zero GC (Idle Session Eviction) β β
β β - Multi-Bot Sharding (N Bots in 1 Binary) β β
β ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OMO AGENT EXECUTION ENGINE β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β LLM Streaming & Tool-Call Loop (OpenAI/Anthropic/...)β β
β ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββ β
β β Native Tools: PTY Terminal / File CRUD / MCP / Web β β
β β Dedicated Workspace Isolation (~/.omon/workspace) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DISCORD RESPONSE EGRESS β
β - Live-Edit Debounced Streaming (800ms sliding window) β
β - Interactive Smart Approvals ([Approve] / [Reject] UI) β
β - Songbird Real-Time Voice Audio Pipeline (Opus / PCM) β
β - Scheduled Cron Event Push Dispatch β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- β‘ Lock-Free Session Multiplexing: Routes messages across servers, threads, and DMs using composite session keys
(platform, guild_id, channel_id, thread_id, user_id)with zero lock contention. - π€ Multi-Bot Parallel Sharding: Run and control multiple Discord bot identities simultaneously from a single compiled ~20MB binary.
- π Scale-to-Zero GC: Inactive sessions automatically flush their state to SQLite and evict worker tasks, reducing idle memory footprint to near zero.
- ποΈ Songbird Discord Voice: Stream bidirectional Opus/PCM audio directly in Discord voice channels.
- β° Autonomous Cron Engine: Persistent SQLite scheduler that triggers background agent prompt runs and command executions, pushing results directly to designated Discord channels.
- π οΈ Native Tool Suite:
- PTY Terminal: Execute commands in an isolated workspace (
~/.omon/workspace). - File Tools: Sandboxed file read, write, and directory inspection.
- Browser & Web: Chrome CDP control (port 9333), live web search, and text extraction.
- Model Context Protocol (MCP): Connect to external tools via stdio and SSE.
- PTY Terminal: Execute commands in an isolated workspace (
- π‘οΈ Smart Approval Guard: Interactively request user confirmation in Discord via button components before running dangerous shell commands.
omon-gateway migrate performs the shipped one-click migration from Hermes Agent to OMO Gateway. Run it from the gateway directory so the imported configuration is written to that directory's .env:
# Preview the complete migration without writing files, changing the database,
# signaling processes, or invoking launchctl.
cargo run -- migrate --dry-run
# Import configuration and cron jobs, then retire the Hermes cron stores and gateway.
cargo run -- migrateThe compiled binary accepts the same subcommand (omo-gateway migrate). The default flow runs in this order:
- Import Hermes configuration from
$HERMES_HOME(default:~/.hermes), including the root.env,config.yaml, and profile.envfiles. - Authoritatively rewrite the gateway
.env. If.envalready exists, its complete previous contents are first copied to.env.bak-<timestamp>. - Synchronize Hermes cron jobs into the gateway SQLite
cron_jobstable. - Verify each Hermes job exists in the gateway database, back up each non-empty
jobs.jsonasjobs.json.bak-omon-migration-<timestamp>, and atomically replace its job list with an empty list. - Stop live Hermes gateway processes recorded by the root and profile
gateway.lockfiles. On macOS, matching~/Library/LaunchAgents/ai.hermes.gateway*.plistservices are booted out withlaunchctland the plist files are renamed to.plist.disabledso launchd cannot restart them.
The backups and .disabled LaunchAgent files make the file cutover reversible; the original files are retained rather than deleted.
| Command | Behavior |
|---|---|
omo-gateway migrate |
Full import and cutover. Writes the authoritative .env, imports cron jobs, empties backed-up Hermes cron stores after verification, and stops/disables the Hermes gateway. |
omo-gateway migrate --dry-run |
Read-only projection of configuration, cron, process, and LaunchAgent changes. It performs zero writes and does not run cron synchronization or destructive side effects. |
omo-gateway migrate --no-cutover |
Import only. Writes the gateway .env and synchronizes cron jobs, but does not empty Hermes cron stores or stop/disable Hermes services. |
Use --no-cutover when Hermes must remain available during a staged migration. Do not run both gateways against the same bot tokens and cron schedules after the final cutover.
The command performs these mappings automatically; this table is a reference, not a manual copy-and-paste procedure.
| Hermes Location | Hermes Key | OMO Gateway .env Key |
Mapping behavior |
|---|---|---|---|
$HERMES_HOME/.env |
DISCORD_BOT_TOKEN |
DISCORD_BOT_TOKEN |
Preserves the primary token. |
$HERMES_HOME/profiles/*/.env |
DISCORD_BOT_TOKEN |
DISCORD_BOT_TOKENS |
Collects non-empty profile tokens in stable order and removes duplicates, including the primary token. |
$HERMES_HOME/.env or profile .env |
DISCORD_ALLOWED_USERS |
DISCORD_ALLOWED_USERS |
The root value wins; otherwise the first profile value is used. |
$HERMES_HOME/.env or profile .env |
DISCORD_FREE_RESPONSE_CHANNELS |
DISCORD_FREE_RESPONSE_CHANNELS |
The root value wins; otherwise the first profile value is used. |
$HERMES_HOME/.env or profile .env |
DISCORD_HOME_CHANNEL |
DISCORD_HOME_CHANNEL |
Preserved; the gateway also treats these as free-response channels at runtime. |
$HERMES_HOME/.env or config.yaml |
DISCORD_ALLOWED_CHANNELS or discord.allowed_channels |
DISCORD_ALLOWED_CHANNELS |
Preserves allowed channel filters. |
$HERMES_HOME/.env or config.yaml |
DISCORD_IGNORED_CHANNELS or discord.ignored_channels |
DISCORD_IGNORED_CHANNELS |
Preserves ignored channel filters. |
$HERMES_HOME/.env or config.yaml |
DISCORD_ALLOWED_ROLES or discord.allowed_roles |
DISCORD_ALLOWED_ROLES |
Preserves authorized Discord role IDs. |
$HERMES_HOME/config.yaml |
model.default / model.name / model.model |
DEFAULT_MODEL |
Preserves the configured model identifier. |
$HERMES_HOME/config.yaml |
model.base_url, model.api_key |
ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY |
Used when the default model name starts with claude. |
$HERMES_HOME/config.yaml |
model.base_url, model.api_key |
OPENAI_API_BASE, OPENAI_API_KEY |
Used for other model names. |
$HERMES_HOME/.env or config.yaml |
APPROVAL_MODE or approvals.mode |
APPROVAL_MODE |
The root .env value wins; otherwise the YAML approval mode is used. |
Unmapped target keys from an existing gateway .env are preserved during merge; backups are recorded before any modifications.
- Cron stores: Hermes jobs are read from
$HERMES_HOME/cron/jobs.jsonand$HERMES_HOME/profiles/*/cron/jobs.json.OMON_HERMES_PROFILEScan restrict the profiles synchronized by the runtime; when unset, the default store and profile directories are discovered automatically. Cron pre-run scripts default to an 1800s (30-minute) timeout, configurable globally viaOMON_CRON_SCRIPT_TIMEOUT_SECSor per job viatimeout_seconds/timeout. - Workspace & Authorized Roots: When
OMON_WORKSPACE_ROOTis unset, OMO Gateway isolates terminal and file tools under$HOME/.omon/workspace. Additional authorized directory paths can be configured viaOMON_TOOL_ROOTS(colon-separated absolute paths; defaults to$HOMEwhen unset; workspace is always allowed; approval policies and hardline command guards still apply). - Skills: OMO Gateway scans
$HERMES_HOME/skills(default:~/.hermes/skills) and~/.omon/skillsforSKILL.mdbundles.
# Clone the repository
git clone https://github.com/Indosaram/omon-gateway.git
cd omon-gateway
# Configure environment
cp .env.example .env
# Edit .env with your Discord bot tokens and LLM endpoint
# Build and run optimized release binary
cargo run --releasedocker compose up -d# Build release binary
cargo build --release --bin omon-gateway
# Install LaunchAgent
cp ai.omon.gateway.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/ai.omon.gateway.plist| Environment Variable | Default | Description |
|---|---|---|
DISCORD_BOT_TOKEN |
Required | Primary Discord Bot Token |
DISCORD_BOT_TOKENS |
Optional | Comma-separated tokens for Multi-Bot sharding |
DISCORD_ALLOWED_USERS |
Optional | Allowed Discord user IDs (empty allows all) |
DISCORD_ALLOWED_ROLES |
Optional | Comma-separated Discord role IDs allowed to interact with the bot |
DISCORD_ALLOW_ALL_USERS |
false |
When true, bypasses user/role allowlists and grants access to all users |
DISCORD_ALLOWED_CHANNELS |
Optional | Comma-separated channel IDs allowed to process messages (DMs exempt) |
DISCORD_IGNORED_CHANNELS |
Optional | Comma-separated channel IDs ignored completely |
DISCORD_FREE_RESPONSE_CHANNELS |
Optional | Channels where the bot responds without @mention |
DISCORD_AUTO_THREAD |
false |
When true, @mentions in guild text channels auto-create a public thread and route responses there |
DISCORD_THREAD_SESSIONS_PER_USER |
true |
When false, all users in a thread share the same conversation session |
DISCORD_THREAD_REQUIRE_MENTION |
false |
When true, requires an @-mention to respond even in active bot threads |
DISCORD_ALLOW_BOTS |
none |
Bot handling policy: none (default), mentions (respond only when @-mentioned), all |
DISCORD_CHANNEL_CONTEXT |
false |
When true, @mentions in guild channels backfill recent channel history as conversation context |
DISCORD_CHANNEL_CONTEXT_LIMIT |
10 |
Maximum preceding messages to backfill when channel context is enabled (clamped to <= 25) |
DISCORD_CHANNEL_TOPIC_CONTEXT |
false |
When true, fetches channel topic and forum parent description as prompt context |
DISCORD_CHANNEL_PROMPTS |
Optional | JSON object mapping channel IDs to custom system_prompt and skills |
DISCORD_PROCESSING_REACTIONS |
true |
When true, adds π reaction when processing starts, swapping to β on success or β on failure |
DISCORD_CHUNK_PAGINATION |
true |
When true, adds (i/N) pagination indicator headers to messages split across multiple chunks |
DISCORD_RUNTIME_FOOTER |
false |
When true, appends a compact runtime metadata footer (model Β· context% Β· cwd) to the final assistant message |
DISCORD_PROFILE_ROUTES |
Optional | JSON array of hierarchical profile routing rules mapping (guild, channel, thread) to custom models, prompts, and toolsets |
DEFAULT_MODEL |
gpt-4o |
Default LLM model identifier |
OPENAI_API_BASE |
https://api.openai.com/v1 |
OpenAI-compatible endpoint URL |
OPENAI_API_KEY |
Optional | OpenAI API key |
ANTHROPIC_BASE_URL |
Optional | Anthropic Messages endpoint URL |
ANTHROPIC_API_KEY |
Optional | Anthropic API key |
DATABASE_URL |
sqlite://omon_gateway.db |
SQLite database path (WAL mode) |
OMON_WORKSPACE_ROOT |
$HOME/.omon/workspace |
Dedicated sandboxed working directory used by terminal and file tools |
OMON_TOOL_ROOTS |
$HOME |
Optional colon-separated absolute paths authorized for tool access (defaults to HOME; workspace always allowed; approval and hardline guards apply) |
HERMES_HOME |
$HOME/.hermes |
Hermes root used by migration, cron synchronization, and Hermes skill discovery |
OMON_HERMES_PROFILES |
Auto-discover | Optional comma-separated Hermes cron profiles; when unset, synchronizes default plus discovered profile directories |
OMON_CRON_SCRIPT_TIMEOUT_SECS |
1800 |
Timeout in seconds for cron pre-run / script executions (default 1800 / 30m; overridable per job via timeout_seconds or timeout) |
APPROVAL_MODE |
smart |
Enforced terminal approval policy: smart gates dangerous commands, always gates every command, and never/yolo bypass approval |
APPROVAL_TIMEOUT_SECS |
900 |
Seconds to wait for a Discord command approval before the request expires (default 900) |
APPROVALS_DENY |
Optional | Comma-separated wildcard globs (npm publish *,kubectl delete *) unconditionally blocked before policy, YOLO, or allowlists |
DISCORD_APPROVAL_MENTIONS |
false |
When true, @-mentions allowed users (<@uid>) on approval prompts for push notifications |
Licensed under the Apache License 2.0.