Integration
Hass Node
Bridges Home Assistant to an OpenClaw gateway. HA app + HACS integration + gateway plugin + skill: your OpenClaw agent answers HA Assist turns and runs ha.* / fs.* / system.* on the paired node.
README
# openclaw-hass-node
[](https://github.com/clawd-ops/openclaw-hass-node/stargazers)
[](https://www.buymeacoffee.com/roblandry)
> ⚠️ **Beta — not yet 1.0.** The node command surface and the HA
> Assist conversation relay (dual websocket pair, streaming token
> deltas, tool-named progress) both work end-to-end: pair, connect,
> invoke round-trips, and conversation relay all stream cleanly.
> Publishing infrastructure is still settling and breaking changes
> between pre-1.0 builds are still possible. Watch
> [`docs/STATUS.md`](docs/STATUS.md) for the first stable tag.
> 🕷️ **With great power comes great responsibility.** Installing this
> app hands an AI agent a direct line into your Home Assistant: it can
> read entity state, call services, control devices, edit files under
> `/config`, `/share`, and `/media`, fetch app logs and metadata, and
> (gated behind `OPENCLAW_ADMIN_TOKEN`) reload HA core config or run
> shell commands inside the app container. We sandbox what we can —
> path-traversal protection, a read-only app surface that strips
> secrets at the boundary, admin tokens on the destructive commands —
> but we are not a tinfoil hat. A misbehaving, jailbroken, or
> well-meaning-but-overconfident agent CAN delete your automations, brick
> an app, leak configuration to a chat channel, or otherwise turn your
> smart home into a smart pile of rubble. **If your agent vaporizes your
> HA install, sets your living-room lights to disco at 3 AM, or your Pi
> catches fire trying to render a chart, that is on you and your agent —
> not on this project.** Back up `/config` before you pair. Use a
> least-privilege agent. Pair this with a real backup integration. You
> have been warned.
Four-piece bundle that connects Home Assistant to an [OpenClaw][]
gateway as a node so your OpenClaw agent (Clawd or whichever agent
you've routed to) can answer HA Assist turns and run the full `ha.*`
control surface — read entity states, call services, control lights,
read logbook/history, validate config — via the standard OpenClaw
Gateway Protocol.
### The four pieces
Everything is prefixed `openclaw-hass-node-` and named for its role.
See [`docs/design/COMPONENT-NAMING.md`](docs/design/COMPONENT-NAMING.md)
for the full taxonomy and rationale.
| Piece | Role | Lives at |
|-----------------------------------|------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
| `openclaw-hass-node-app` | The HA **app**. Python service that pairs with the OpenClaw gateway and exposes the `ha.*` / `fs.*` / `system.*` node command surface. | [`app/`](app/) |
| `openclaw-hass-node-assist` | The **HACS integration**. Registers the OpenClaw conversation entity inside HA core and proxies Assist turns to the app over local HTTP. | [`custom_components/openclaw_hass_node_assist/`](custom_components/openclaw_hass_node_assist/) |
| `openclaw-hass-node-assist-tools` | The OpenClaw **gateway plugin**. Declares scoped per-tool wrappers (`ha_call_service`, `ha_get_state`, `ha_logbook`, …) so HA Assist sessions can operate the paired node without the operator-only `nodes.invoke` tool. | [`plugins/openclaw-hass-node-assist-tools/`](plugins/openclaw-hass-node-assist-tools/) |
| `openclaw-hass-node-skill` | The companion **skill** used by every non-Assist OC session (chat, cron, sub-agent) to drive `ha.*` / `fs.*` via `nodes.invoke`. | [`skills/openclaw-hass-node-skill/`](skills/openclaw-hass-node-skill/) |
Only the first two install to your HA host. The plugin loads into your
OpenClaw gateway config; the skill installs into your OpenClaw session
skill registry.
### End-to-end request flow
```
HA Assist UI
│ user turn
▼
openclaw-hass-node-assist (HACS integration, ConversationEntity)
│ POST /v1/conversation
▼
openclaw-hass-node-app (this repo's HA app)
│ chat.send + sessions.messages.subscribe ◄── operator-role websocket
▼
OpenClaw gateway → configured agent (Assist session)
│ scoped ha_* tool calls via openclaw-hass-node-assist-tools plugin
│ ha.* → node.invoke ◄── node-role websocket
▼
openclaw-hass-node-app runs the HA action, returns
▼
Speech reply back to Assist
```
Both halves work end-to-end. The app opens two parallel gateway
connections — node-role for invokes, operator-role for the
conversation relay — sharing a single device identity. Pair the
device with a dual-role profile via `openclaw qr`.
Non-Assist OC sessions (chat, cron, sub-agent) have `nodes.invoke`
directly and drive the same node command surface via the
`openclaw-hass-node-skill` skill, bypassing the plugin.
**New here?** Read **[`docs/design/PLAN.md`](docs/design/PLAN.md)** for
what this is, what each of the four pieces does and why, the
end-to-end request flow, and the security model.
## Install
See **[`docs/INSTALL.md`](docs/INSTALL.md)** for the full end-to-end
walkthrough, including the **required** `openclaw.json` patch on the
gateway side. Short version:
1. **OpenClaw gateway config** — patch `gateway.nodes.allowCommands`
(the gateway silently drops unknown commands; without this the node
pairs but no commands work). Load the
**`openclaw-hass-node-assist-tools`** plugin under
`plugins.entries` and add a per-node policy block with the allow
lists you want Assist to have (`allowServices`,
`allowReadEntities`, `allowCalendars`; optional `allowAdminOps` +
`adminToken` for Tier B). Install
**`openclaw-hass-node-skill`** into your OC session skill registry
so non-Assist sessions can drive the node too.
2. **HA app** — add this repo as an HA app repository, install
**OpenClaw HA Node — App**, fill in `gateway_url` +
`pairing_token` + `node_name`, start it.
3. `openclaw devices approve <request-id>` on the gateway.
4. **HACS integration** — install **OpenClaw HA Node — Assist**, point
its config flow at the app socket.
5. Pick **OpenClaw HA Node — Assist** as your HA Assist conversation agent.
> Standalone Docker (without HA Supervisor) is **not a supported install
> path during beta**. The runtime entrypoint depends on
> the HA base-python image's s6-overlay `with-contenv` wrapper to pick up
> Supervisor's injected env. Standalone-mode code in `__main__.py`
> still exists for testing on the dev host directly, but the Docker
> image is HA-only.
## Status
- **Node command surface**: complete (42 commands: `ha.*` × 28, `fs.*`
× 11, `system.*` × 2, `ping`).
- **Pairing + connect**: works end-to-end with device-token persistence.
- **Conversation relay (`/v1/conversation` → OpenClaw chat surface)**:
working today, streams token deltas with tool-named progress lines.
The node's operator-role WebSocket owns the relay; pair with a
dual-role profile to enable it.
- **Local HTTP API**: fail-closed bearer auth (`local_api_token` is
required; non-public paths return `401 NO_TOKEN_CONFIGURED`
otherwise). The HTTP command surface is allowlisted to `ping` and
`system.which`; the full surface is gateway-authorized and delivered
over the node-role gateway WS.
## Security model
- **Outbound-only WSS.** The app opens the connection to the gateway. There is no inbound port for the gateway to attack.
- **Signed handshake.** Pairing uses an Ed25519 key generated inside the app. The private key never leaves `/data`. Connect frames are signed (payload format v3); the gateway verifies the signature against the registered public key.
- **Device-token persistence with self-heal.** After first pairing the app persists the device token. If the gateway later rejects it (`NOT_PAIRED`, `PAIRING_REQUIRED`, `AUTH_TOKEN_MISMATCH`, `token_mismatch`), the app drops the stored token and falls back to the pairing token, so a stale token doesn't lock you out.
- **Gateway-side allowlist.** Even if the app were compromised, the gateway only honors commands listed in `gateway.nodes.allowCommands`. Removing a command from that list and restarting the gateway disables it everywhere.
- **HA Supervisor isolation.** The app runs in its own container with explicit filesystem maps. Removing a map (e.g. `media:rw`) immediately removes the app's access to that area.
- **No agent reasoning happens here.** This node is purely an executor. Prompts, tool-choice, model selection, and policy all live in the gateway. The node does what the gateway tells it; the gateway does what the agent decides; the agent runs under whatever policy you configure upstream.
## What this is not
- **Not an AI by itself.** It does not call any LLM. It only exposes HA to the agent your OpenClaw gateway already runs.
- **Not a replacement for HA Assist.** It plugs into Assist as one more conversation-agent option; the rest of the pipeline (wake word, STT, TTS) is unchanged.
- **Not a public-internet bridge.** Both the WSS to the gateway and the agent that responds are yours.
## Pointers
Live state and roadmap: [`docs/STATUS.md`](docs/STATUS.md).
Architecture and decisions: [`docs/design/PLAN.md`](docs/design/PLAN.md).
Install/troubleshooting: [`docs/INSTALL.md`](docs/INSTALL.md).
Release + versioning policy: [`docs/operations/RELEASE.md`](docs/operations/RELEASE.md).
## License
[MIT](LICENSE).
## For maintainers / contributors
- [`docs/MEMORY.md`](docs/MEMORY.md) — durable build memory written for
the Clawd agent driving the implementation. Read it if you're
resuming work after a context compaction.
- [`docs/operations/LESSONS.md`](docs/operations/LESSONS.md) — gotchas from the install
push. Read
... (truncated)
integration
Comments
Sign in to leave a comment