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

# How It Works

> Architecture of the Lua Device Gateway

## Architecture Overview

The Device Gateway sits between your physical devices and the Lua agent runtime. It handles authentication, connection management, command routing, and trigger delivery.

```mermaid theme={null}
graph LR
    subgraph Devices
        D1["🖥️ Node.js Device<br/>(Socket.IO)"]
        D2["📡 Pico W / IoT<br/>(MQTT)"]
    end

    subgraph Lua Platform
        GW["🔌 Device Gateway<br/>Auth · Routing · Heartbeat"]
        AG["🤖 AI Agent<br/>Skills · Tools · Triggers"]
    end

    subgraph Users
        U1["💬 WhatsApp"]
        U2["🌐 Web Chat"]
    end

    D1 <-->|WebSocket| GW
    D2 <-->|MQTT| GW
    GW <-->|Commands & Responses| AG
    AG <-->|Conversation| U1
    AG <-->|Conversation| U2
```

## Self-Describing Flow

When a device connects, it does not need any server-side configuration. The device tells the gateway what it can do, and the gateway tells the agent.

<Steps>
  <Step title="Device connects with command manifest">
    The device client sends its `commands` array during the Socket.IO auth handshake or MQTT online status message. Each command includes a name, description, and optional JSON Schema for input parameters.
  </Step>

  <Step title="Gateway registers device">
    The gateway validates the API key, registers the device, and stores the command manifest. The device appears as "online" to the agent.
  </Step>

  <Step title="Agent discovers tools">
    When the agent processes a user message, it queries connected devices and merges their commands into the tool list. Each device command appears as a tool named `device__{deviceName}__{commandName}`.
  </Step>

  <Step title="Device disconnects, tools disappear">
    When a device goes offline (intentional disconnect, network loss, or missed heartbeats), its tools are removed from the agent. No stale tools remain.
  </Step>
</Steps>

## Command Delivery Path

When the agent decides to use a device tool, the command flows through the gateway:

```mermaid theme={null}
sequenceDiagram
    participant User as 💬 User
    participant Agent as 🤖 Agent
    participant GW as 🔌 Gateway
    participant Device as 📡 Device

    User->>Agent: "Read the temperature"
    Agent->>Agent: Selects tool: device__pico_sensor__read_temperature
    Agent->>GW: Send command (commandId, payload)
    GW->>Device: Deliver command via WebSocket/MQTT
    Device->>Device: Execute handler
    Device->>GW: Return response
    GW->>Agent: Deliver response
    Agent->>User: "The temperature is 23.5°C"
```

Each command carries a unique `commandId` for idempotency. If the device receives the same command twice (due to retry or redelivery), it returns the cached response.

## Trigger Flow

Triggers go in the opposite direction — from device to agent:

```mermaid theme={null}
sequenceDiagram
    participant Device as 📡 Device
    participant GW as 🔌 Gateway
    participant Agent as 🤖 Agent
    participant User as 💬 User

    Device->>Device: Detects temperature > 40°C
    Device->>GW: trigger('high_temp', { temperature: 42.1 })
    GW->>Device: ACK (triggerId, received: true)
    GW->>Agent: Deliver trigger to handler
    Agent->>Agent: Runs defineDeviceTrigger execute()
    Agent->>User: "⚠️ Temperature alert: 42.1°C!"
```

<Note>
  Triggers are **fire-and-forget** from the device's perspective. The device gets an acknowledgment that the gateway received the trigger, but does not wait for the agent to finish processing it.
</Note>

## Transport Comparison

| Feature          | Socket.IO                  | MQTT                                              |
| ---------------- | -------------------------- | ------------------------------------------------- |
| Protocol         | WebSocket over HTTPS       | MQTT 3.1.1 over TLS                               |
| Default URL      | `https://api.heylua.ai`    | `wss://mqtt.heylua.ai/mqtt`                       |
| Reconnection     | Built-in with jitter       | Built-in with backoff                             |
| Message ordering | Guaranteed (single socket) | Guaranteed per topic (QoS 1)                      |
| Offline queueing | No                         | Yes (persistent session)                          |
| Last Will (LWT)  | Not applicable             | Automatic offline status on disconnect            |
| Best for         | Node.js, desktops, servers | Microcontrollers, battery devices, flaky networks |
| RAM footprint    | \~10 MB (Node.js)          | \~30 KB (MicroPython on Pico W)                   |

## Security Model

<CardGroup cols={2}>
  <Card title="API Key Authentication" icon="key">
    Every device connection requires a valid API key. The key is validated against the Lua auth service during the connection handshake.
  </Card>

  <Card title="Agent Scoping" icon="shield-halved">
    A device can only interact with the agent it authenticates against. Cross-agent communication is not possible.
  </Card>

  <Card title="TLS Encryption" icon="lock">
    All transports use TLS. Socket.IO connects over HTTPS. MQTT connects over port 443 (WebSocket) with TLS.
  </Card>

  <Card title="Heartbeat Monitoring" icon="heart-pulse">
    The gateway expects a heartbeat every 30 seconds. Missed heartbeats trigger disconnect detection. MQTT additionally uses Last Will and Testament (LWT) for instant offline notification.
  </Card>
</CardGroup>

## Connection Lifecycle

<Tabs>
  <Tab title="Socket.IO">
    ```
    1. Client opens WebSocket to https://api.heylua.ai/devices
    2. Auth handshake: { apiKey, agentId, deviceName, commands[] }
    3. Server validates, emits 'connected'
    4. Client starts heartbeat (every 30s)
    5. Bidirectional command/trigger exchange
    6. On disconnect: auto-reconnect with jittered exponential backoff
    7. On reconnect: re-sends auth (commands may have changed)
    8. On SIGTERM/SIGINT: graceful disconnect, no reconnect
    ```
  </Tab>

  <Tab title="MQTT">
    ```
    1. Client connects to wss://mqtt.heylua.ai/mqtt
       - username: {agentId}:{deviceName}
       - password: {apiKey}
       - LWT: offline status (retained)
    2. Client subscribes to: command, connected, trigger_ack, error
    3. Client publishes online status (retained, no secrets)
    4. Client publishes API key + commands (non-retained)
    5. Client starts heartbeat (every 30s)
    6. Bidirectional command/trigger exchange via topics
    7. On disconnect: broker publishes LWT, server detects offline
    8. On reconnect: re-subscribe, re-publish online status
    ```
  </Tab>
</Tabs>

## Next Steps

<CardGroup cols={2}>
  <Card title="Self-Describing Commands" icon="list-check" href="/devices/self-describing-commands">
    Deep dive into how devices declare their capabilities
  </Card>

  <Card title="Triggers" icon="bolt" href="/devices/triggers">
    Understand device-to-agent event flow
  </Card>

  <Card title="MQTT Transport" icon="tower-broadcast" href="/devices/mqtt-client">
    Configure MQTT for constrained devices
  </Card>

  <Card title="Agent Tools" icon="wrench" href="/devices/agent-tools">
    How device commands become agent tools
  </Card>
</CardGroup>
