> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orcbot.buzzchat.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Web Gateway

> Set up the web gateway for REST API access, WebSocket events, and remote management

## Overview

The OrcBot Web Gateway provides:

* **REST API** for remote control and management
* **WebSocket** for real-time events and bidirectional communication
* **Dashboard hosting** for web-based interfaces
* **Secure authentication** with API keys

## Quick Start

### Start the Gateway

<CodeGroup>
  ```bash Basic theme={null}
  orcbot gateway

  # Gateway starts on http://localhost:3100
  ```

  ```bash With Agent theme={null}
  orcbot gateway --with-agent

  # Starts both gateway and agent loop
  ```

  ```bash Custom Port theme={null}
  orcbot gateway -p 8080 -k mysecretkey

  # Custom port and API key
  ```

  ```bash Serve Dashboard theme={null}
  orcbot gateway -s ./apps/dashboard

  # Serves static files from directory
  ```
</CodeGroup>

You should see:

```
Gateway: Serving static files from /path/to/dashboard
Gateway Server listening on http://0.0.0.0:3100
```

## Configuration

### Basic Settings

```yaml theme={null}
# ~/.orcbot/orcbot.config.yaml

# Gateway server settings
gatewayPort: 3100
gatewayHost: 0.0.0.0  # Listen on all interfaces

# Security
gatewayApiKey: your-secret-api-key-here

# CORS origins
gatewayCorsOrigins:
  - "*"  # Allow all (development only!)
  # - "https://yourdomain.com"  # Production

# Rate limiting
gatewayRateLimitPerMinute: 180  # 180 requests per minute

# Static files (optional)
gatewayStaticDir: ./apps/dashboard
```

### Generate API Key

<Steps>
  <Step title="Auto-Generate">
    ```bash theme={null}
    curl -X POST http://localhost:3100/api/gateway/token/rotate
    ```

    Returns:

    ```json theme={null}
    {
      "token": "a7f3...c2b1",  // 64-char hex token
      "message": "New API key generated and saved to config"
    }
    ```
  </Step>

  <Step title="Manual">
    ```bash theme={null}
    # Generate random token
    openssl rand -hex 32
    ```

    Add to config:

    ```yaml theme={null}
    gatewayApiKey: "a7f3c4b9...your-token"
    ```
  </Step>

  <Step title="Verify">
    ```bash theme={null}
    curl http://localhost:3100/api/gateway/token/status
    ```

    Shows:

    ```json theme={null}
    {
      "authEnabled": true,
      "tokenPartial": "a7f3****...c2b1",
      "tokenLength": 64
    }
    ```
  </Step>
</Steps>

## REST API

### Authentication

Include API key in requests:

<CodeGroup>
  ```bash Header (Recommended) theme={null}
  curl -H "X-Api-Key: your-secret-key" \
    http://localhost:3100/api/status
  ```

  ```bash Bearer Token theme={null}
  curl -H "Authorization: Bearer your-secret-key" \
    http://localhost:3100/api/status
  ```

  ```bash Query Parameter theme={null}
  curl "http://localhost:3100/api/status?apiKey=your-secret-key"
  ```
</CodeGroup>

### API Endpoints

#### Status & Info

<CodeGroup>
  ```bash GET /api/status theme={null}
  curl http://localhost:3100/api/status

  # Returns agent status, model, memory, queue info
  ```

  ```bash GET /api/health theme={null}
  curl http://localhost:3100/api/health

  # Returns uptime, memory usage, WebSocket clients
  ```

  ```bash GET /api/gateway/capabilities theme={null}
  curl http://localhost:3100/api/gateway/capabilities

  # Returns available API endpoints and features
  ```
</CodeGroup>

#### Tasks & Queue

<CodeGroup>
  ```bash POST /api/tasks theme={null}
  curl -X POST http://localhost:3100/api/tasks \
    -H "Content-Type: application/json" \
    -d '{
      "description": "Summarize latest AI news",
      "priority": 10
    }'

  # Creates new task
  ```

  ```bash GET /api/tasks theme={null}
  curl http://localhost:3100/api/tasks

  # Lists all tasks (active + pending)
  ```

  ```bash GET /api/tasks/:id theme={null}
  curl http://localhost:3100/api/tasks/act_abc123

  # Get specific task details
  ```

  ```bash POST /api/tasks/:id/cancel theme={null}
  curl -X POST http://localhost:3100/api/tasks/act_abc123/cancel

  # Cancel running task
  ```

  ```bash POST /api/tasks/clear theme={null}
  curl -X POST http://localhost:3100/api/tasks/clear

  # Clear completed/failed tasks
  ```
</CodeGroup>

#### Chat Interface

<CodeGroup>
  ```bash POST /api/chat/send theme={null}
  curl -X POST http://localhost:3100/api/chat/send \
    -H "Content-Type: application/json" \
    -d '{
      "message": "What\'s the weather like?",
      "sourceId": "web-client-123"
    }'

  # Send chat message, agent responds
  ```

  ```bash GET /api/chat/history theme={null}
  curl http://localhost:3100/api/chat/history

  # Get recent chat messages
  ```

  ```bash GET /api/chat/export theme={null}
  curl http://localhost:3100/api/chat/export

  # Export chat history as JSON
  ```

  ```bash POST /api/chat/clear theme={null}
  curl -X POST http://localhost:3100/api/chat/clear

  # Clear chat history
  ```
</CodeGroup>

#### Memory

<CodeGroup>
  ```bash GET /api/memory theme={null}
  curl http://localhost:3100/api/memory?type=short&limit=20

  # Get recent memories
  ```

  ```bash GET /api/memory/stats theme={null}
  curl http://localhost:3100/api/memory/stats

  # Memory statistics
  ```

  ```bash GET /api/memory/search theme={null}
  curl http://localhost:3100/api/memory/search?q=deployment

  # Search memories by keyword
  ```
</CodeGroup>

#### Configuration

<CodeGroup>
  ```bash GET /api/config theme={null}
  curl http://localhost:3100/api/config

  # Get all configuration
  ```

  ```bash GET /api/config/:key theme={null}
  curl http://localhost:3100/api/config/modelName

  # Get specific config value
  ```

  ```bash PUT /api/config/:key theme={null}
  curl -X PUT http://localhost:3100/api/config/modelName \
    -H "Content-Type: application/json" \
    -d '{"value": "gpt-4o"}'

  # Update config value (hot-reload)
  ```
</CodeGroup>

#### Skills & Tools

<CodeGroup>
  ```bash GET /api/skills theme={null}
  curl http://localhost:3100/api/skills

  # List all available skills
  ```

  ```bash POST /api/skills/:name/execute theme={null}
  curl -X POST http://localhost:3100/api/skills/web_search/execute \
    -H "Content-Type: application/json" \
    -d '{"args": {"query": "latest AI news"}}'

  # Execute specific skill
  ```

  ```bash GET /api/skills/health theme={null}
  curl http://localhost:3100/api/skills/health

  # Check skill system health
  ```
</CodeGroup>

#### Models & Providers

<CodeGroup>
  ```bash GET /api/models theme={null}
  curl http://localhost:3100/api/models

  # Get current model and availability
  ```

  ```bash PUT /api/models theme={null}
  curl -X PUT http://localhost:3100/api/models \
    -H "Content-Type: application/json" \
    -d '{"modelName": "gpt-4o", "llmProvider": "openai"}'

  # Switch model/provider
  ```

  ```bash GET /api/providers theme={null}
  curl http://localhost:3100/api/providers

  # List available LLM providers
  ```

  ```bash GET /api/tokens theme={null}
  curl http://localhost:3100/api/tokens

  # Get token usage statistics
  ```
</CodeGroup>

#### Security

<CodeGroup>
  ```bash GET /api/security theme={null}
  curl http://localhost:3100/api/security

  # Get security settings
  ```

  ```bash PUT /api/security theme={null}
  curl -X PUT http://localhost:3100/api/security \
    -H "Content-Type: application/json" \
    -d '{"safeMode": true}'

  # Update security settings
  ```
</CodeGroup>

#### Logs

```bash theme={null}
curl http://localhost:3100/api/logs?lines=50

# Get recent log entries
```

## WebSocket API

### Connect to WebSocket

```javascript theme={null}
const ws = new WebSocket('ws://localhost:3100');

ws.onopen = () => {
  console.log('Connected to OrcBot gateway');
  
  // Subscribe to events
  ws.send(JSON.stringify({
    action: 'subscribe',
    events: ['status', 'event', 'chat']
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};
```

### WebSocket Events

<Tabs>
  <Tab title="status">
    Agent status updates:

    ```json theme={null}
    {
      "type": "status",
      "data": {
        "agentName": "OrcBot",
        "modelName": "gpt-4o-mini",
        "isProcessing": true,
        "queueSize": 3,
        "activeTaskId": "act_abc123"
      }
    }
    ```
  </Tab>

  <Tab title="event">
    Agent events (thinking, action, observation):

    ```json theme={null}
    {
      "type": "event",
      "data": {
        "eventType": "action",
        "actionId": "act_abc123",
        "step": 3,
        "skill": "web_search",
        "args": {"query": "latest AI news"}
      }
    }
    ```
  </Tab>

  <Tab title="chat">
    Chat message events:

    ```json theme={null}
    {
      "type": "chat:message",
      "data": {
        "id": "msg_123",
        "role": "assistant",
        "content": "Here's the latest AI news...",
        "timestamp": "2024-03-15T10:30:00Z"
      }
    }
    ```
  </Tab>
</Tabs>

### WebSocket Actions

Send commands via WebSocket:

<CodeGroup>
  ```javascript Push Task theme={null}
  ws.send(JSON.stringify({
    action: 'pushTask',
    description: 'Analyze server logs',
    priority: 10
  }));
  ```

  ```javascript Execute Skill theme={null}
  ws.send(JSON.stringify({
    action: 'executeSkill',
    skillName: 'web_search',
    args: { query: 'Rust tutorials' }
  }));
  ```

  ```javascript Send Chat Message theme={null}
  ws.send(JSON.stringify({
    action: 'sendChatMessage',
    message: 'What is my schedule today?',
    sourceId: 'web-client-123'
  }));
  ```

  ```javascript Get Status theme={null}
  ws.send(JSON.stringify({
    action: 'getStatus'
  }));
  ```

  ```javascript Update Config theme={null}
  ws.send(JSON.stringify({
    action: 'setConfig',
    key: 'modelName',
    value: 'gpt-4o'
  }));
  ```
</CodeGroup>

## Security

### API Key Authentication

The gateway uses timing-safe comparison for API keys:

```typescript theme={null}
try {
  authenticated = crypto.timingSafeEqual(
    Buffer.from(providedKey, 'utf8'),
    Buffer.from(apiKey, 'utf8')
  );
} catch {
  authenticated = false;
}
```

### Security Headers

Automatically applied to all responses:

```typescript theme={null}
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
res.setHeader('Referrer-Policy', 'no-referrer');
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
res.setHeader('Cache-Control', 'no-store');
```

### Rate Limiting

Per-IP rate limiting:

```yaml theme={null}
gatewayRateLimitPerMinute: 180  # 180 requests/minute per IP
```

Exceeding limit returns:

```json theme={null}
{
  "error": "Too many requests. Slow down and retry shortly.",
  "requestId": "req_abc123"
}
```

### CORS Configuration

<Tabs>
  <Tab title="Development">
    ```yaml theme={null}
    gatewayCorsOrigins:
      - "*"  # Allow all origins
    ```
  </Tab>

  <Tab title="Production">
    ```yaml theme={null}
    gatewayCorsOrigins:
      - "https://yourdomain.com"
      - "https://app.yourdomain.com"
    ```
  </Tab>
</Tabs>

## Remote Access with Tailscale

<Warning>
  **Do NOT expose the gateway directly to the internet.** Use a private network like Tailscale.
</Warning>

### Why Tailscale?

* Private mesh network (WireGuard-based)
* No port forwarding needed
* Zero-trust access control
* End-to-end encryption
* Works across NAT/firewalls

### Setup

<Steps>
  <Step title="Install Tailscale">
    ```bash theme={null}
    # Linux
    curl -fsSL https://tailscale.com/install.sh | sh

    # macOS
    brew install tailscale
    ```
  </Step>

  <Step title="Connect to Tailnet">
    ```bash theme={null}
    sudo tailscale up
    ```

    Follow link to authenticate
  </Step>

  <Step title="Configure Gateway">
    ```yaml theme={null}
    gatewayHost: 0.0.0.0  # Listen on all interfaces
    gatewayPort: 3100
    gatewayApiKey: your-secret-key
    ```
  </Step>

  <Step title="Access Remotely">
    ```bash theme={null}
    # Get Tailscale IP
    tailscale ip -4
    # Example: 100.64.1.2

    # Access from any device on your Tailnet
    curl http://100.64.1.2:3100/api/status
    ```
  </Step>

  <Step title="Set Up ACLs (Optional)">
    In Tailscale admin console, restrict access:

    ```json theme={null}
    {
      "acls": [
        {
          "action": "accept",
          "src": ["group:admins"],
          "dst": ["tag:orcbot:3100"]
        }
      ]
    }
    ```
  </Step>
</Steps>

## Hosting a Dashboard

### Static File Serving

Serve a web dashboard:

```bash theme={null}
orcbot gateway -s ./apps/dashboard
```

Directory structure:

```
apps/dashboard/
  ├── index.html
  ├── app.js
  ├── style.css
  └── assets/
      ├── logo.png
      └── ...
```

Access at: `http://localhost:3100/`

API available at: `http://localhost:3100/api/*`

### Example Dashboard Code

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <title>OrcBot Dashboard</title>
</head>
<body>
  <h1>OrcBot Dashboard</h1>
  <div id="status"></div>
  <div id="chat">
    <div id="messages"></div>
    <input type="text" id="input" placeholder="Message OrcBot...">
    <button onclick="sendMessage()">Send</button>
  </div>

  <script>
    const API_KEY = 'your-api-key';
    const WS_URL = 'ws://localhost:3100';
    
    // WebSocket connection
    const ws = new WebSocket(WS_URL);
    
    ws.onopen = () => {
      console.log('Connected');
      ws.send(JSON.stringify({ action: 'subscribe', events: ['chat'] }));
    };
    
    ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      if (data.type === 'chat:message') {
        displayMessage(data.data);
      }
    };
    
    function sendMessage() {
      const input = document.getElementById('input');
      const message = input.value;
      
      ws.send(JSON.stringify({
        action: 'sendChatMessage',
        message,
        sourceId: 'dashboard'
      }));
      
      input.value = '';
    }
    
    function displayMessage(msg) {
      const div = document.createElement('div');
      div.className = msg.role;
      div.textContent = msg.content;
      document.getElementById('messages').appendChild(div);
    }
    
    // Fetch status
    async function updateStatus() {
      const res = await fetch('/api/status', {
        headers: { 'X-Api-Key': API_KEY }
      });
      const status = await res.json();
      document.getElementById('status').textContent = 
        `Model: ${status.modelName} | Queue: ${status.queueSize}`;
    }
    
    updateStatus();
    setInterval(updateStatus, 5000);
  </script>
</body>
</html>
```

## Troubleshooting

### Gateway Won't Start

<Steps>
  <Step title="Check Port">
    ```bash theme={null}
    # See if port is in use
    lsof -i :3100

    # Or use different port
    orcbot gateway -p 8080
    ```
  </Step>

  <Step title="Check Logs">
    ```bash theme={null}
    tail -f ~/.orcbot/logs/orcbot.log | grep -i gateway
    ```
  </Step>

  <Step title="Verify Config">
    ```yaml theme={null}
    gatewayPort: 3100
    gatewayHost: 0.0.0.0
    ```
  </Step>
</Steps>

### API Key Not Working

```bash theme={null}
# Check token status
curl http://localhost:3100/api/gateway/token/status

# Rotate token if needed
curl -X POST http://localhost:3100/api/gateway/token/rotate

# Use new token
curl -H "X-Api-Key: new-token" http://localhost:3100/api/status
```

### CORS Errors

In browser console:

```
Access to fetch at 'http://localhost:3100/api/status' from origin
'http://localhost:8080' has been blocked by CORS policy
```

**Fix:**

```yaml theme={null}
gatewayCorsOrigins:
  - "http://localhost:8080"  # Add your origin
```

### WebSocket Disconnects

```javascript theme={null}
ws.onclose = (event) => {
  console.log('Disconnected:', event.code, event.reason);
  
  // Auto-reconnect
  setTimeout(() => {
    connectWebSocket();
  }, 5000);
};
```

## Best Practices

<Card title="Security" icon="shield">
  * Always set a strong `gatewayApiKey`
  * Use Tailscale or VPN for remote access
  * Restrict CORS origins in production
  * Enable rate limiting
  * Monitor logs for suspicious activity
</Card>

<Card title="Performance" icon="bolt">
  * Use WebSocket for real-time updates
  * Cache static assets with CDN
  * Set reasonable rate limits
  * Monitor memory usage with `/api/health`
</Card>

<Card title="Reliability" icon="signal">
  * Implement WebSocket reconnection logic
  * Handle rate limit errors gracefully
  * Use request IDs for debugging
  * Monitor uptime and errors
</Card>
