📦 System Overview

┌─────────────────────────────────────────────────────────┐
│                      Channels                            │
│   (Telegram, WhatsApp, Discord, CLI, Web Gateway)       │
└─────────────────────────┬───────────────────────────────┘
                          ▼
┌─────────────────────────────────────────────────────────┐
│                    Agent Core                            │
│  ┌─────────────┐  ┌──────────────┐  ┌───────────────┐  │
│  │  Decision   │  │   Memory     │  │   Scheduler   │  │
│  │   Engine    │  │   Manager    │  │   (Heartbeat) │  │
│  └─────────────┘  └──────────────┘  └───────────────┘  │
└─────────────────────────┬───────────────────────────────┘
                          ▼
┌─────────────────────────────────────────────────────────┐
│                 Skills & Tools                           │
│   (Browser, File System, Search, Messaging, Plugins)    │
└─────────────────────────┬───────────────────────────────┘
                          ▼
┌─────────────────────────────────────────────────────────┐
│                    Providers                             │
│     (OpenAI, Google, Bedrock, NVIDIA, OpenRouter)       │
└─────────────────────────────────────────────────────────┘

📁 Data Paths

OrcBot stores all data in ~/.orcbot/ by default:

PathPurpose
orcbot.config.yamlMain configuration file
memory.jsonShort-term and episodic memories
action-queue.jsonPending tasks queue
profiles/Contact profiles (per-JID)
plugins/Custom skill plugins
browser-profiles/Persistent browser sessions
downloads/Downloaded media files

🧠 Decision Engine

The decision engine builds context from memories, skills, and channel metadata, then calls the LLM to determine the next action. It supports multi-tool responses.

💾 Memory Manager

Manages short-term memories with automatic consolidation into episodic summaries after 30 entries. Retrieval is capped for context window efficiency.

⏰ Scheduler

Emits scheduler:tick events for background jobs. Heartbeat tasks, polling jobs, and autonomy checks all run through the scheduler.

🔌 Event Bus

Central pub/sub system for decoupled communication. Components subscribe to events like config:changed, action:push, etc.

🔄 Request Flow

  1. Inbound: Message arrives via channel (Telegram, WhatsApp, etc.)
  2. Memory: Message stored in short-term memory with context
  3. Decision: Decision engine builds prompt with memories, skills, channel context
  4. LLM Call: MultiLLM routes to appropriate provider based on model name
  5. Parse: Parser layer extracts tools array from JSON response
  6. Execute: Skills manager executes each tool in sequence
  7. Respond: Results sent back through the originating channel

🔐 Trust Boundaries

BoundaryTrust LevelNotes
Inbound channelsUntrusted inputTelegram, WhatsApp, Discord, Slack, Email, and Gateway Chat payloads are treated as user-controlled input and must pass through session scoping, tool policy, and prompt guardrails.
Gateway APIOperator surfaceThe gateway is an admin/control-plane interface. Remote exposure requires gatewayApiKey, explicit CORS, and a stable sourceId for correct session routing.
Primary agentTrusted runtimeThe primary agent owns channel delivery, final user replies, and all cross-channel policy enforcement. Worker results are returned through this agent rather than sent directly.
Worker processesConstrained trusted codeWorkers inherit execution capabilities needed for delegated tasks, but channel tokens are stripped from their environment by default so they cannot silently impersonate the primary channel endpoints.
Plugins and custom skillsFully trusted codePlugins execute with local code privileges. Treat them as code deployment, not prompt configuration. Review and allow-list them before use on shared systems.
LLM providers and external APIsExternal systemsModel providers, search providers, browsers, and third-party APIs are outside OrcBot's trust boundary. Keep secrets in config/env, not in memory or prompts.

🧭 Deterministic Inbound Routing

OrcBot routes inbound user messages by thread before they become executable actions. The order is explicit and stable:

  1. Resolve session scope: Every inbound message is mapped to a sessionScopeId using the configured session policy (main, per-peer, or per-channel-peer).
  2. Resume waiting work first: If the same thread already has an action in waiting state, the new inbound message resumes that action instead of spawning a parallel replacement.
  3. Supersede stale pending work: Older pending user-lane actions for the same thread are failed before the new message is queued, preventing stacked stale requests from replaying out of order.
  4. Serialize behind active work: If the thread already has an in-progress action, the new request is queued behind it and tagged with routing metadata rather than being ambiguously merged.
  5. Return delegated work through primary: Worker and clone results are reported back through the primary agent using the original reply context so final user delivery stays on the correct channel thread.

These routing decisions are recorded as inbound route metadata on memories and actions, making them inspectable from logs, memory, and gateway/API surfaces.