Architecture

This page describes the full OmniLink system architecture, from the user interface layer down to the local runtime. Understanding these layers will help you make better design decisions when building agents.


High-Level Overview

OmniLink is a five-layer platform. Each layer has a clear responsibility, and communication between layers follows well-defined protocols.

┌─────────────────────────────────────────────────────────────┐
│                    LAYER 1: USER INTERFACE                   │
│         Dashboard  ·  Web SDK  ·  Custom Clients            │
├─────────────────────────────────────────────────────────────┤
│                    LAYER 2: REST API                         │
│     Node.js server on Cloud Run (server.ts + api/*.ts)      │
│     /api/chat · /api/stt · /api/tts · /api/memory · ...    │
├─────────────────────────────────────────────────────────────┤
│                    LAYER 3: AI ENGINES                       │
│    g1 (Gemini)            ·  g2 (GPT)                    │
│    g3 (Grok)              ·  g4 (Claude)                    │
├─────────────────────────────────────────────────────────────┤
│                    LAYER 4: DATA LAYER                       │
│                  Supabase (PostgreSQL)                       │
│   Auth · Profiles · Memory · Usage · Billing                │
├─────────────────────────────────────────────────────────────┤
│                    LAYER 5: LOCAL RUNTIME                    │
│               OmniLink Python Library                       │
│   OmniLinkEngine · ToolRunner · HTTP Bridge                  │
└─────────────────────────────────────────────────────────────┘

              ┌───────────────────────────┐
              │     TRANSPORT LAYER       │
              │  REST (HTTPS)             │
              │  HTTP Bridge (port 8080)  │
              └───────────────────────────┘

Layer 1: User Interface

The UI layer is where humans and external systems interact with OmniLink. There are three primary entry points:

Dashboard

The web-based Dashboard at https://www.omnilink-agents.com is the primary management interface. It provides pages for agent configuration, voice settings, engine selection, memory browsing, billing, usage monitoring, message visualization, and more.

The Dashboard communicates with Layer 2 exclusively through the REST API, using the same endpoints available to external clients. There is no privileged internal API.

Custom Clients

Any HTTP client can call the REST API directly. The API uses standard Bearer token authentication and returns JSON responses.

curl -X POST https://www.omnilink-agents.com/api/chat \
  -H "Authorization: Bearer olink_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello", "engine": "g1-engine"}'

Layer 2: REST API

The API layer runs as a single Node.js server (server.ts) on Google Cloud Run, dispatching to per-route handlers in api/*.ts. Each handler:

  1. Validates the Omni Key against Supabase
  2. Extracts user context (profile, permissions, plan tier)
  3. Routes the request to the appropriate AI engine or data service
  4. Deducts credits from the user’s balance
  5. Returns the response

Key Endpoints

Endpoint Method Description
/api/chatPOSTSend a message, receive an AI response
/api/chatPOST (stream)Stream response tokens via Server-Sent Events
/api/sttPOSTTranscribe audio to text
/api/ttsPOSTSynthesize text to audio
/api/translationPOSTTranslate text between languages
/api/memoryGET/POST/DELETERead, write, and delete memory entries
/api/profilesGET/POST/PUT/DELETECRUD operations on agent profiles
/api/usageGETRetrieve credit balance and usage statistics

Request Lifecycle

# Request lifecycle for /api/chat
#
# 1. Client sends POST with Bearer token + JSON body
# 2. Serverless function extracts token → validates against Supabase
# 3. User context loaded (profile, plan, remaining credits)
# 4. Credit check: sufficient balance?
#    ├── No  → 402 Payment Required
#    └── Yes → continue
# 5. Memory injection (if enabled): load relevant entries
# 6. Prompt assembly: system instructions + memory + message
# 8. Route to selected engine (g1/g2/g3/g4)
# 9. Receive response from model provider
# 10. Deduct credits, log usage
# 11. Return response to client

Layer 3: AI Engines

OmniLink abstracts multiple model providers behind a unified engine interface. The API layer routes requests based on the engine parameter.

Engine ID Provider Model Strengths
g1-engine Google Gemini Lowest latency, highest throughput, cost-efficient
g2-engine OpenAI GPT Complex multi-step reasoning, code generation
g3-engine xAI Grok Real-time knowledge, current events
g4-engine Anthropic Claude Instruction following, safety, long context

Model Routing

Engine selection happens at three levels, with later levels overriding earlier ones:

  1. Profile default — Set when the profile is created or updated.
  2. Dashboard selection — Changed from the AI Engine page.
  3. Per-request override — The engine field in the API request body.

This means you can set a default engine for your agent (e.g., g1 for speed) and override it for specific requests that need more reasoning power (e.g., g2 or g4).


Layer 4: Data Layer

OmniLink uses Supabase (PostgreSQL) as its primary data store. Supabase provides authentication, row-level security, real-time subscriptions, and vector storage.

Data Domains

Domain Storage Description
Authentication Supabase Auth Omni Key validation, user sessions, API key management
Profiles PostgreSQL Agent names, personas, system instructions, engine preferences
Memory PostgreSQL Key-value pairs with categories and timestamps
Usage PostgreSQL Credit transactions, API call logs, per-endpoint statistics
Billing PostgreSQL Plan tier, subscription status, payment history

Row-Level Security

Every table is protected by row-level security (RLS) policies. A user’s Omni Key resolves to a user ID, and all queries are scoped to that user. There is no way for one user to access another user’s data, even if they guess a record ID.


Layer 5: Local Runtime

The local runtime is the omnilink Python library. It runs on your hardware and handles everything that does not require cloud inference.

Components

OmniLinkEngine

The command parser. It uses template matching with typed variables to convert natural-language-like strings into function calls.

# Template syntax: "verb [variable_name:type] rest of pattern"
# Supported types: str, int, float, bool, and custom types via TypeRegistry

engine = OmniLinkEngine()

# Register a custom type
engine.type_registry.register("direction", ["north", "south", "east", "west"])

@engine.command("face [dir:direction]")
def face(dir: str):
    return f"Facing {dir}"

# "face north" → face("north") ✓
# "face up"    → no match (not in direction type) ✗

ToolRunner

The cloud-orchestrated local execution framework. Subclass ToolRunner and implement three methods: get_state(), execute_action(), and is_game_over(). The framework handles the rest.

OmniLinkClient

A Python REST client that mirrors the Web SDK. Use it to call any platform endpoint from Python code.

OmniLinkHTTPBridge

Starts a local HTTP server on port 8080. External systems can send commands via POST /command and receive results synchronously.

Note: The legacy bridge class has been removed. Use OmniLinkHTTPBridge instead. Use OmniLinkHTTPBridge for all new projects.


Transport Layer

Two transport mechanisms connect the layers:

REST (HTTPS)

The primary transport between UI/SDK and the cloud API. All requests use HTTPS with Bearer token authentication.

HTTP Bridge

A local REST server for bidirectional communication between the cloud platform and local runtime. Three endpoints are standard:

Endpoint Direction Payload
POST /command Cloud → Local JSON-encoded command with action and parameters
GET /feedback Local → Cloud JSON-encoded result with status, data, and errors
GET /context Local → Cloud JSON-encoded current agent state and context

Useful for integration with tools that speak REST (e.g., Home Assistant, Node-RED).

# Send a command via the HTTP bridge
curl -X POST http://localhost:8080/command \
  -H "Content-Type: application/json" \
  -d '{"command": "turn on the kitchen lights"}'

# Response:
# {"result": "kitchen lights turned on", "status": "ok"}

The ToolRunner Lifecycle

ToolRunner is the heart of OmniLink’s cost-efficient agent architecture. Here is the complete lifecycle:

┌──────────────────────────────────────────────────────────┐
│                   TOOLRUNNER LIFECYCLE                    │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  1. KICKOFF (1 credit)                                   │
│     ├── User provides task description                   │
│     ├── get_state() captures initial state               │
│     ├── State + task sent to cloud AI                    │
│     └── AI returns action plan                           │
│                                                          │
│  2. MAIN LOOP (0 credits)                                │
│     ├── execute_action() runs the AI's chosen action     │
│     ├── get_state() captures new state                   │
│     ├── Memory persisted locally                         │
│     ├── UI command polling (check for user overrides)    │
│     ├── is_game_over() checked                            │
│     │   ├── True  → go to step 4                         │
│     │   └── False → continue loop                        │
│     └── Repeat                                           │
│                                                          │
│  3. PERIODIC REVIEW (1 credit, optional)                 │
│     ├── Triggered after N iterations or time threshold   │
│     ├── Current state sent to cloud AI                   │
│     ├── AI adjusts strategy if needed                    │
│     └── Returns to main loop                             │
│                                                          │
│  4. FINAL ANALYSIS (1 credit)                            │
│     ├── Final state captured via get_state()             │
│     ├── Complete execution log sent to cloud AI          │
│     ├── AI generates summary and recommendations         │
│     └── Result returned to caller                        │
│                                                          │
│  Total: 2 credits (no review) or 3+ (with reviews)      │
└──────────────────────────────────────────────────────────┘

Implementing a ToolRunner

You subclass ToolRunner and implement three required methods:

from omnilink import ToolRunner

class MyRunner(ToolRunner):

    def get_state(self) -> dict:
        """Return a JSON-serializable snapshot of current state.
        Called at kickoff, after each action, and at final analysis."""
        return {"status": "running", "progress": 0.5}

    def execute_action(self, state: dict) -> None:
        """Execute an action decided by the cloud AI.
        Receives the current state dict."""
        # Parse and execute the action locally
        pass

    def is_game_over(self, state: dict) -> bool:
        """Return True when the task is done.
        Checked after every action execution."""
        return self.progress >= 1.0

State Polling & Memory

During the main loop, the ToolRunner persists state locally. This means that even if the process restarts, it can resume from the last known state. Memory entries are written to the platform’s memory store so the cloud AI can reference them during periodic reviews and final analysis.


Command Flow

Here is the complete flow from user input to executed action:

# Command flow
#
# 1. User input: "turn on the kitchen lights"
#
# 2. Cloud AI (if using chat endpoint):
#    - Receives message + system instructions
#    - Decides this maps to a tool call
#    - Emits command string: "turn on the kitchen lights"
#
# 3. Transport (HTTP Bridge):
#    - Command sent to POST /command
#    - Local runtime receives it
#
# 4. OmniLinkEngine:
#    - Matches against template: "turn [state:str] the [device:str]"
#    - Extracts: state="on", device="kitchen lights"
#    - Calls handler: toggle_device(state="on", device="kitchen lights")
#
# 5. Handler execution:
#    - Sends HTTP request to device API → "on"
#    - Returns: "kitchen lights turned on"
#
# 6. Feedback:
#    - Result returned via GET /feedback
#    - Cloud receives confirmation
#    - User sees: "Done! The kitchen lights are now on."

AgentFeedback

Command handlers can send bidirectional messages during execution using AgentFeedback. This allows the handler to report progress, ask for clarification, or stream partial results back to the user.

from omnilink import OmniLinkEngine, AgentFeedback

engine = OmniLinkEngine()

@engine.command("deploy service [name:str]")
def deploy(name: str, feedback: AgentFeedback):
    """Deploy a service with progress updates."""
    feedback.send("Starting deployment...")
    # ... build step ...
    feedback.send("Build complete. Running tests...")
    # ... test step ...
    feedback.send("Tests passed. Deploying to production...")
    # ... deploy step ...
    return f"Service {name} deployed successfully"

Authentication Flow

Every API request must include an Omni Key. Here is how authentication works:

# Authentication flow
#
# 1. Client sends request:
#    Authorization: Bearer olink_abc123...
#
# 2. Serverless function extracts the token
#
# 3. Token validated against Supabase:
#    SELECT user_id, plan, credits_remaining
#    FROM api_keys
#    WHERE key_hash = hash('olink_abc123...')
#    AND is_active = true
#
# 4. If valid:
#    - User context attached to request
#    - Request proceeds to handler
#
# 5. If invalid:
#    - 401 Unauthorized returned
#    - Request rejected

Key Format

Omni Keys follow the format olink_ followed by a cryptographically random string. The key is hashed before storage — OmniLink never stores raw keys. If you lose your key, you must generate a new one from the Dashboard.

Security Best Practices

  • Store your Omni Key in environment variables, never in source code
  • Rotate keys periodically from the Dashboard
  • Use separate keys for development and production
  • Monitor the Usage page for unexpected activity

Knowledge Pipeline

The cloud knowledge pipeline (file upload, chunking, pgvector storage, /api/knowledge-index) was removed in the 2026-04-21 cloud-knowledge-removal work. Knowledge is now provided via per-agent local folders (agents/<name>/knowledge/) checked into the agent repo and read from Python via the search_knowledge tool. See the agents directory for the current pattern.


Deployment Topology

A typical OmniLink deployment looks like this:

                         ┌──────────────────┐
                         │   User Browser    │
                         │   (Dashboard)     │
                         └────────┬─────────┘
                                  │ HTTPS
                         ┌────────▼─────────┐
                         │   Cloud Run       │
                         │   (REST API)      │
                         └──┬─────┬──────┬──┘
                            │     │      │
              ┌─────────────▼┐  ┌─▼────┐ ┌▼──────────────┐
              │   AI Engines  │  │Supa- │ │  Supabase     │
              │ (g1/g2/g3/g4)│  │base  │ │  pgvector     │
              │               │  │Auth  │ │  (memory)     │
              └───────────────┘  └──────┘ └───────────────┘

    ═══════════════════════════════════════════════════════════
                          INTERNET
    ═══════════════════════════════════════════════════════════

                         ┌──────────────────┐
                         │  Local Machine    │
                         │  ┌──────────────┐ │
                         │  │ OmniLink Lib │ │
                         │  │  ┌─────────┐ │ │
                         │  │  │ Engine  │ │ │
                         │  │  │ Runner  │ │ │
                         │  │  │ Bridges │ │ │
                         │  │  └─────────┘ │ │
                         │  └──────┬───────┘ │
                         │         │         │
                         │  ┌──────▼───────┐ │
                         │  │  Hardware    │ │
                         │  │  (robot,     │ │
                         │  │   sensors,   │ │
                         │  │   actuators) │ │
                         │  └──────────────┘ │
                         └──────────────────┘

The cloud and local halves are connected by HTTPS (for API calls) and the HTTP bridge (for local agent communication). The local machine can be anything from a Raspberry Pi to a full server.


Next Steps

  • Quickstart — Put this architecture into practice with a hands-on tutorial.
  • Use Cases — See how the architecture applies to specific domains.
  • Introduction — Revisit the platform overview and value proposition.