Skip to content

Latest commit

 

History

History
182 lines (135 loc) · 6.64 KB

File metadata and controls

182 lines (135 loc) · 6.64 KB
date 2026-03-13
author Onur Solmaz
title OpenClaw Integration
tags
openclaw
acp
integration

OpenClaw in Spritz

This document is the single source of truth for OpenClaw-related behavior in this repository.

Scope

Spritz supports running OpenClaw as a per-devbox application surface. Each devbox runs its own OpenClaw process and is opened through its own /i/{name} route. When OpenClaw is used as an ACP backend inside Spritz, it should also expose ACP on the reserved internal port 2529.

Where OpenClaw lives in this repo

  • Image and runtime wrapper:
    • images/examples/openclaw/Dockerfile
    • images/examples/openclaw/entrypoint.sh
    • images/examples/openclaw/README.md
  • API preset catalog:
    • helm/spritz/values.yaml (api.presets)
    • helm/spritz/templates/api-deployment.yaml
  • Transitional UI mirror:
    • helm/spritz/values.yaml (ui.presets)
    • helm/spritz/templates/ui-deployment.yaml

Runtime contract (example image)

The OpenClaw example entrypoint does the following:

  1. Resolves config path (OPENCLAW_CONFIG_PATH / OPENCLAW_CONFIG_DIR).
  2. Writes config from one of:
    • OPENCLAW_CONFIG_JSON
    • OPENCLAW_CONFIG_B64
    • OPENCLAW_CONFIG_FILE
  3. Sets gateway fields:
    • gateway.mode from OPENCLAW_GATEWAY_MODE (default local)
    • gateway.port from OPENCLAW_GATEWAY_PORT (default 8080)
    • gateway.bind from OPENCLAW_GATEWAY_BIND (default lan)
  4. Ensures OPENCLAW_GATEWAY_TOKEN exists (uses provided token or generates one).
  5. Writes the gateway token to a local token file for ACP adapter use.
  6. Starts an image-owned ACP adapter on 0.0.0.0:2529 unless OPENCLAW_ACP_ENABLED=false.
  7. Exposes:
    • WebSocket ACP on /
    • GET /healthz
    • GET /.well-known/spritz-acp
  8. When gateway auth mode is trusted-proxy, automatically trusts loopback for the internal adapter, injects the required trusted-proxy headers on the adapter's upstream gateway hop, and rewrites the upstream gateway connect handshake into a Control UI operator session without device identity.
  9. Auto-starts OpenClaw when command is default (sleep infinity), unless OPENCLAW_AUTO_START=false.

Key implication: direct /i/{name} access with bind=lan expects real gateway auth.

The current image does not consume a SPRITZ_RUNTIME_CONTEXT_PATH file and does not write OpenClaw workspace identity files such as IDENTITY.md or SOUL.md. Spritz-side agentRef and profile data are control-plane fields used by the API, bindings, and UI. OpenClaw-specific identity or behavior must be supplied through OpenClaw configuration or deployment-owned workspace preparation.

ACP contract in Spritz

Spritz treats ACP as backend-agnostic.

For OpenClaw to appear in the Spritz ACP chat UI, the instance must answer ACP on:

  • port 2529
  • WebSocket path /

Spritz will then:

  • discover the agent from the operator by sending ACP initialize
  • surface it in status.acp
  • proxy browser ACP traffic through spritz-api

This ACP path is separate from OpenClaw's dashboard and gateway UI.

Today the example image satisfies that contract with a long-lived ACP adapter:

  • one long-lived Node ACP server inside the image listens on 2529
  • the adapter talks to the local OpenClaw gateway over loopback WebSocket
  • ACP WebSocket clients connect to that long-lived adapter instead of spawning a fresh runtime
  • the adapter also exposes cheap HTTP health and metadata endpoints for Spritz operator discovery
  • if gateway auth mode is trusted-proxy, the adapter uses a loopback-only header injector so the internal ACP hop satisfies the same trusted-proxy contract as the browser route
  • in trusted-proxy mode, the adapter impersonates a Control UI-style operator profile without device identity so OpenClaw does not force pairing for the internal ACP client

This keeps the Spritz side backend-agnostic while OpenClaw remains free to add native socket ACP later.

Auth modes and what to use

token (default-safe for current direct routing)

  • Works with bind=lan.
  • No startup crash.
  • Required when route is direct to the devbox without trusted proxy auth headers.

trusted-proxy (tokenless UX, production-ready if wired correctly)

Use this when you want users not to paste gateway tokens manually.

Required OpenClaw config:

  • gateway.auth.mode: "trusted-proxy"
  • gateway.auth.trustedProxy.userHeader: "<header-name>"
  • gateway.trustedProxies: ["<proxy-ip-or-cidr>", ...]

Required platform behavior:

  • All /i/{name} traffic must pass through an auth proxy.
  • Proxy must authenticate users and overwrite identity headers.
  • No bypass path to the instance service.

none (not for LAN exposure)

  • auth.mode=none with bind=lan is rejected by OpenClaw runtime checks.
  • Use none only for trusted local/loopback scenarios.

Tokenless implementation pattern (recommended)

If the target is "no token prompt in Control UI":

  1. Put instance routes behind an identity-aware proxy.
  2. Switch OpenClaw auth to trusted-proxy.
  3. Configure trustedProxies to only the proxy source IPs/CIDRs.
  4. Configure trustedProxy.userHeader to the forwarded authenticated identity.
  5. Enforce network policy so instance pods are not reachable except through ingress/proxy.

Do not disable auth globally to get tokenless behavior.

Example preset snippet

Define OpenClaw presets in api.presets. Until the UI reads GET /api/presets directly, mirror the same entry into ui.presets from the same values source.

Example:

x-openclaw-preset: &openclaw_preset
  id: openclaw
  name: OpenClaw Devbox
  image: spritz-openclaw:latest
  description: OpenClaw preinstalled
  env:
    - name: OPENCLAW_CONFIG_JSON
      value: >-
        {"gateway":{"mode":"local","bind":"lan","auth":{"mode":"token"}}}

api:
  presets:
    - *openclaw_preset

ui:
  presets:
    - *openclaw_preset

For trusted-proxy deployments, replace the auth block accordingly.

Fast troubleshooting

  • Refusing to bind gateway to lan without auth:
    • invalid config (typically auth.mode=none with bind=lan).
  • gateway token missing in Control UI:
    • gateway is in token mode but UI has no token.
    • either provide token or move to trusted-proxy model.
  • origin not allowed:
    • add the dashboard origin to gateway.controlUi.allowedOrigins.

Related docs