I have been using OpenClaw as my LLM broker and wanted something a lot more robust than what we have just connecting to a cloud or local LLM in Home Assistant. Would love feedback as this project has been pivotal for me to remove Alexa from my environment and have a lot more reach into my home network while tempering the capabilities with security gates in mind.
PrayerfulDrop/HA-OpenClaw-Conversation-Agent-and-Bridge: A conversation agent for HA directly into OpenClaw. This does require a docker image running.
ha-bridge (Home Assistant ↔ OpenClaw bridge)
This service is intended to sit between Home Assistant (HA) and the “brain” (OpenClaw + local LLMs).
High-level design
- Expose a simple HTTP API (
POST /v1/conversation) for HA or other clients. - Translate incoming text + context into a request for the brain.
- Return natural language
reply_textplus optional structuredactionsdescribing Home Assistant service calls. - Optionally call HA’s REST/WebSocket APIs directly when we want the bridge to execute actions itself (behind an explicit safety toggle).
At the moment, the conversation endpoint can work in three modes:
- Stub mode (no brain configured): returns a safe echo-style reply so you can wire up HA without affecting any real entities.
- OpenClaw gateway mode (recommended):
OPENCLAW_BASE_URLis set to the Gateway’s OpenAI-compatible/v1base, and Home Assistant passes a Gateway token in theAuthorization: Bearer <token>header via the custom component. The bridge calls the Gateway’s/v1/chat/completionsendpoint and expects a JSON object withreply_textandactionsin the documented schema. - Direct LLM mode (legacy):
LLM_BASE_URLandLLM_API_KEYare set to an OpenAI-compatible endpoint. The bridge talks directly to that endpoint instead of going through the OpenClaw Gateway.
Quick start (OpenClaw Gateway mode)
Prerequisites:
- An OpenClaw Gateway running (for example at
http://<gateway-host>:18789/). - The Gateway’s OpenAI-compatible HTTP surface enabled:
gateway.http.endpoints.chatCompletions.enabled = truein~/.openclaw/openclaw.json.
- A Home Assistant instance.
Steps (high level):
- Run
ha-bridgeusing Docker or Docker Compose so it listens onhttp://<ha-bridge-host>:8080. - Install the custom component by copying
homeassistant_custom/openclaw_conversation/into your HA config ascustom_components/openclaw_conversation/and restarting HA. - In HA, add the OpenClaw Conversation Agent integration and set:
- Bridge URL:
http://<ha-bridge-host>:8080 - Gateway token: your OpenClaw Gateway bearer token.
- In Settings → Voice Assistants, select the OpenClaw Conversation agent for the desired Assist pipeline.
- Test with a simple utterance like “What is your name?” from Assist to verify the end-to-end path.
Endpoints
GET /healthz
Basic health check.
POST /v1/conversation
Request body (example):
{ “text”: “turn on the kitchen lights”, “conversation_id”: “optional-conversation-id”, “user”: { “id”: “user123”, “name”: “Brian” }, “room”: { “id”: “kitchen”, “name”: “Kitchen” }, “entities”: [ { “entity_id”: “light.kitchen_main”, “name”: “Kitchen Main Light” } ], “source”: “home-assistant”, “metadata”: { “pipeline”: “default” } }
Response (shape):
{ “reply_text”: “Stub reply or model reply…”, “conversation_id”: “optional-conversation-id”, “actions”: [ { “type”: “ha_service”, “service”: “light.turn_on”, “target”: { “entity_id”: [“light.kitchen_main”] }, “data”: { “brightness”: 200 } } ], “executed_actions”: [ { “action”: { “service”: “light.turn_on”, “entity_id”: “light.kitchen_main” }, “result”: [ /* raw HA service response */ ] } ], “action_errors”: [ { “action”: { “service”: “light.turn_on” }, “error”: “HA_SERVICE_ERROR”, “status”: 400, “body”: “…” } ], “debug”: { “source”: “home-assistant”, “received_entities”: [ { “entity_id”: “light.kitchen_main”, “name”: “Kitchen Main Light” } ], “metadata”: { “pipeline”: “default” }, “openclaw_base_url”: “http://openclaw-gateway:8080”, “ha_configured”: true } }
The actions array is what the brain asked to do. The executed_actions and action_errors arrays describe what the bridge actually tried to do against Home Assistant.
Auth between HA and this service, and between the service and OpenClaw/LLMs, is handled via environment variables and headers:
- HA → ha-bridge: the Home Assistant custom component forwards any configured “API key” as
Authorization: Bearer <token>on/v1/conversationcalls. In the OpenClaw-first flow, this value should be your Gateway token. - ha-bridge → OpenClaw Gateway: when
OPENCLAW_BASE_URLis set, the bridge uses that URL (for examplehttp://gateway-host:18789/v1) and sends the same token as a bearer token when calling/v1/chat/completions.
A safety flag (EXECUTE_HA_ACTIONS) controls whether actions are actually sent to Home Assistant.
For bridge-side debugging, you can enable more verbose logging of outbound LLM calls by setting:
DEBUG_BRIDGE=true
This will log each /v1/chat/completions call (URL + model id) without changing behavior.
Home Assistant custom component (HACS-friendly)
This repo ships a minimal Home Assistant integration under custom_components/openclaw_conversation/ that exposes this bridge as a conversation agent.
Install via HACS (recommended)
- Make sure HACS is installed in your Home Assistant.
- In HACS, go to Integrations → Custom repositories and add this repo:
- URL:
https://github.com/PrayerfulDrop/HA-OpenClaw-Conversation-Agent-and-Bridge - Category: Integration
- Install the OpenClaw Conversation Agent integration from HACS.
- Restart Home Assistant.
Then in HA:
- In Settings → Devices & services → Integrations, add OpenClaw Conversation Agent.
- Set the Bridge URL to the URL where this service is reachable, e.g.
http://ha-bridge:8080orhttp://llm-home:8080depending on where you run the container. - In the agent config, paste your Gateway token into the Gateway token field; this value is forwarded as a bearer token to the bridge.
- In Settings → Voice Assistants, select the OpenClaw Conversation agent as the conversation engine for the relevant Assist pipelines.
Manual install (without HACS)
- Copy
custom_components/openclaw_conversation/into your Home Assistant config directory ascustom_components/openclaw_conversation/. - Restart Home Assistant.
- Follow the same configuration steps as above (Bridge URL + Gateway token, then select the agent in Voice Assistants).
From there, any Assist request that uses this agent will be forwarded to /v1/conversation on the bridge, and the reply_text will be spoken back by Home Assistant.
Docker Compose example (OpenClaw Gateway mode)
Minimal example for running ha-bridge alongside an OpenClaw Gateway and Home Assistant on the same Docker network:
version: “3.9” services: ha-bridge: build: . container_name: ha-bridge environment: # OpenClaw Gateway OpenAI-compatible HTTP surface # Make sure gateway.http.endpoints.chatCompletions.enabled is true. - OPENCLAW_BASE_URL=http://openclaw-gateway:18789/v1 # Optional but recommended: dedicated HA investigative agent # When set, ha-bridge will prefer this model when calling the # OpenClaw Gateway (unless HA explicitly overrides it via # metadata.openclaw.agent_model). - OPENCLAW_AGENT_MODEL=openclaw/ha-bridge # Home Assistant base URL and long-lived access token - HOME_ASSISTANT_BASE_URL=http://homeassistant:8123 - HOME_ASSISTANT_TOKEN=YOUR_HA_LONG_LIVED_TOKEN # Optional: explicitly set the model id for the Gateway # When OPENCLAW_BASE_URL is set, the bridge ignores LLM_MODEL and # instead uses, in order of precedence: # 1) metadata.openclaw.agent_model # 2) OPENCLAW_AGENT_MODEL # 3) openclaw/default # Only enable this once you are confident in the safety profile. - EXECUTE_HA_ACTIONS=true ports: - “8080:8080” restart: unless-stopped # networks: # - your_shared_network # networks: # your_shared_network: # external: true
In this setup:
- The Gateway is reachable inside Docker as
http://openclaw-gateway:18789. - Home Assistant is reachable as
http://homeassistant:8123. - The OpenClaw Conversation custom component in HA is configured with:
- Bridge URL:
http://ha-bridge:8080 - API key: your OpenClaw Gateway token (forwarded to the bridge and then to the Gateway as a bearer token).
- Bridge URL:
If you prefer a one-off docker run instead of Compose, the equivalent is roughly:
## Configuring the OpenClaw HA agent (reproducible setup)
The bridge is designed to talk to a dedicated OpenClaw agent for Home Assistant and infrastructure‑adjacent questions. The recommended convention is:
* **Agent id:** `ha-bridge`
* **Model string:** `openclaw/ha-bridge`
### One-time agent setup on the OpenClaw host
Run these commands on the machine where the OpenClaw Gateway is running:
# Create a dedicated HA agent that reuses the main workspace openclaw agents add ha-bridge \ --workspace ~/.openclaw/workspace \ --non-interactive || true
This creates an `ha-bridge` agent that shares the same workspace as your main agent. You can confirm it with:
openclaw agents list
### Pointing ha-bridge at the HA agent
With the agent in place, set `OPENCLAW_AGENT_MODEL` for the ha-bridge container:
environment: - OPENCLAW_BASE_URL=http://openclaw-gateway:18789/v1 - OPENCLAW_AGENT_MODEL=openclaw/ha-bridge - HOME_ASSISTANT_BASE_URL=http://homeassistant:8123 - HOME_ASSISTANT_TOKEN=YOUR_HA_LONG_LIVED_TOKEN - EXECUTE_HA_ACTIONS=true
The effective model used for Gateway calls will then be:
1. `metadata.openclaw.agent_model` (if Home Assistant explicitly sets it)
2. `OPENCLAW_AGENT_MODEL` (`openclaw/ha-bridge` in this example)
3. `openclaw/default` fallback
If `OPENCLAW_AGENT_MODEL` is unset, behavior is unchanged from prior versions (the default `openclaw/default` model is used when `OPENCLAW_BASE_URL` is configured).
### Manual recovery if automatic setup fails
If you ever suspect the HA agent was not created correctly, you can re-run the one‑time setup step and restart ha-bridge:
openclaw agents add ha-bridge \ --workspace ~/.openclaw/workspace \ --non-interactive || true docker restart ha-bridge
Then test from Home Assistant Assist with a simple utterance such as "What is your name?". The request should route through the `openclaw/ha-bridge` model when `OPENCLAW_AGENT_MODEL` is set.
## Generic investigative questions (no per-scenario stubs)
The bridge is intentionally **generic**: once it is pointed at an OpenClaw Gateway, you should not need to add new HTTP endpoints or hard-coded "scenario" handlers here to support questions like "what cron jobs are running on <server>?" or "how many Wi‑Fi devices are on the network?".
Instead, the behavior is:
* The bridge forwards text + lightweight context to the Gateway via the OpenAI-compatible `/v1/chat/completions` surface.
* A configured OpenClaw agent (for example `openclaw/ha-bridge`) decides how to answer, including when to use tools like `exec` to run **read-only diagnostics** against your own infrastructure.
* The bridge enforces the security split:
* Requests that look like **HA control** ("turn on", "set", "lock", "unlock", "open", "close", "arm", "disarm", etc.) are routed through `/v1/conversation` in **control mode** and may result in Home Assistant service calls when `EXECUTE_HA_ACTIONS=true`.
* Requests that look like **read-only / investigative** questions (plain questions that don’t start with imperative verbs) are handled in an **info-only** mode: the agent may run read-only checks (including SSH commands via OpenClaw tools), but the bridge will not execute HA actions for them.
## What the OpenClaw Conversation Agent is allowed to do
The OpenClaw Conversation Agent is intentionally limited. These limits are by design, for safety and reproducibility.
### Allowed
* **Normal Home Assistant control** in safe domains when you use imperative phrasing and `EXECUTE_HA_ACTIONS=true`:
* Examples: "turn on the kitchen lights", "set the bedroom to 72", "lock the front door", "close the garage door", "arm the alarm".
* The brain returns `ha_service` actions, and ha-bridge enforces confirmation rules for unlock/open/disarm.
* **Read-only / investigative questions** about:
* Home state (lights, doors, climate, scenes, etc.).
* Non-HA systems (servers, Docker, UniFi, NAS) using tools like `config/ha_servers.json` + `scripts/ha_server_inspect.sh` and other read-only helpers.
* Examples: "What cron jobs are running on llm-home?", "Are there any issues with Docker on llm-home?", "How many Wi-Fi clients are on the network?".
### Not allowed (by design)
* **State-changing actions outside of Home Assistant**:
* The HA pathway is strictly read-only for non-HA systems. The agent may not restart Plex, reboot servers, restart Docker, apply updates, edit configs, or change UniFi/NAS settings.
* When you ask for one of these (for example "reboot Plex" or "restart Docker on llm-home"), the agent is instructed to refuse with this exact message:
> I am sorry but there are limitations to what I am allowed to do. Any actions like what you asked is not permitted for security reasons.
* **Automatic SSH / config mutation from HA**:
* The agent will not silently change SSH keys, write new hosts, or rewire config files when a request comes through Home Assistant.
* Instead it will explain what config is missing (for example a host entry in `config/ha_servers.json`) and ask if you want to wire it up, usually by running a helper script or editing a file on the OpenClaw host yourself.
These constraints are deliberate: OpenClaw + ha-bridge handle HA control and cross-host observability, but any non-HA state changes must be done in an explicit maintenance channel (CLI, direct OpenClaw session, etc.), not through the Home Assistant Conversation Agent.
### OpenClaw-side requirements (reproducible setup)
To make this generic behavior work on any OpenClaw deployment:
1. **Enable the Gateway HTTP chat-completions surface**In `~/.openclaw/openclaw.json`:
{ gateway: { http: { endpoints: { chatCompletions: { enabled: true }, }, }, }, }
2. **Describe servers in config, not code**In the agent workspace used by the Gateway (for example the default `~/.openclaw/workspace`), add a config file such as `config/ha_servers.json` (you can start from `config/ha_servers.example.json` in this repo):
{ "llm-home": { "ssh": "[email protected]", "role": "llm-server" }, "media-server": { "ssh": "[email protected]", "role": "media-server" } }
The HA agent is expected to read this configuration (or equivalent context such as TOOLS.md) and decide which host to inspect when the user asks about a particular server.
3. **Use generic, read-only helpers for inspection**This workspace also provides a generic helper script:
scripts/ha_server_inspect.sh <label> <ssh_target>
The HA agent should call this script via OpenClaw's exec/SSH tools to gather information about cron, systemd timers, OS, and (optionally) apt upgradable packages on a host. The script is intentionally **read-only** and should not be modified to perform updates or restarts.
4. **Ask before wiring new hosts**If a user asks about a host that is not present in `config/ha_servers.json`, the HA agent should:
* Explain that it does not yet have read-only access to that host.
* Ask the user if they want to wire it up.
* Provide concrete setup instructions (for example, running a small helper script on the OpenClaw host to add the host to `config/ha_servers.json`), rather than attempting to modify SSH or config directly via the HA pathway.
With this setup, new investigative questions routed through HA → ha-bridge → OpenClaw do **not** require any new per-scenario HTTP handlers in this repo; they are handled generically by the OpenClaw agent and its toolset, with per-host details living in workspace config instead of code.