# Docker Compose configuration for LangBot # For Kubernetes deployment, see kubernetes.yaml and the deployment guide at https://docs.langbot.app version: "3" services: langbot_plugin_runtime: image: rockchin/langbot:latest container_name: langbot_plugin_runtime volumes: - ./data/plugins:/app/data/plugins ports: - 5401:5401 restart: on-failure environment: - TZ=Asia/Shanghai # Shared with the langbot service and sent only as a WebSocket handshake # header. Generate with: openssl rand -hex 32 - LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN=${LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN:-} command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "rt"] networks: - langbot_network # The Box sandbox runtime is optional. It is only started when you run # ``docker compose --profile box up`` (or ``docker compose --profile all # up``). With Box off, LangBot keeps the dashboard / skills list visible # (read-only) but disables sandbox tools, skill add/edit and stdio MCP — # set ``box.enabled: false`` in ``data/config.yaml`` (or # ``BOX__ENABLED=false`` in the langbot service env below) to match. langbot_box: image: rockchin/langbot:latest container_name: langbot_box profiles: ["box", "all"] volumes: # Keep the source and target path identical because langbot_box uses the # host Docker socket to create sandbox containers. Override # LANGBOT_BOX_ROOT with an absolute path if you do not want the default. - ${LANGBOT_BOX_ROOT:-${PWD}/data/box}:${LANGBOT_BOX_ROOT:-${PWD}/data/box} # Mount container runtime socket for Box sandbox backend. # Uncomment the one that matches your container runtime: # - /var/run/podman/podman.sock:/var/run/podman/podman.sock # Podman - /var/run/docker.sock:/var/run/docker.sock # Docker restart: on-failure environment: - TZ=Asia/Shanghai # Shared control-plane secret used to authenticate both the RPC socket # and managed-process relay. Generate once (for example with # ``openssl rand -hex 32``) and export it before enabling this profile. # An empty value is accepted by Compose so Box can remain optional, but # the Box runtime itself fails closed when the profile is started. - LANGBOT_BOX_CONTROL_TOKEN=${LANGBOT_BOX_CONTROL_TOKEN:-} # The Box runtime does NOT read box.local.* from config.yaml or env; it # receives its functional configuration from LangBot via the INIT RPC # action. LANGBOT_BOX_CONTROL_TOKEN is the intentional security-only # exception; do not add BOX__* here because those would be ignored. # Launched through the same CLI entry point as the plugin runtime # (`langbot_plugin.cli.__init__ `). WebSocket is the default # control transport — mirrors `rt`, which also runs with no flag. Pass # `-s` / `--stdio-control` only for the stdio mode LangBot uses outside # containers. command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "box"] networks: - langbot_network langbot: image: rockchin/langbot:latest container_name: langbot volumes: - ./data:/app/data restart: on-failure environment: - TZ=Asia/Shanghai # Must match langbot_plugin_runtime. Empty/missing values make the # external control channel fail closed. - LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN=${LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN:-} # Must match the value supplied to langbot_box. The token is sent only # in WebSocket handshake headers, never in URLs or action payloads. - LANGBOT_BOX_CONTROL_TOKEN=${LANGBOT_BOX_CONTROL_TOKEN:-} # Unified env-override convention: SECTION__SUBSECTION__KEY overrides the # matching config.yaml field (see LoadConfigStage). These map onto # box.* and are forwarded to the Box runtime via INIT RPC. - BOX__LOCAL__HOST_ROOT=${LANGBOT_BOX_ROOT:-${PWD}/data/box} - BOX__LOCAL__DEFAULT_WORKSPACE=default - BOX__LOCAL__SKILLS_ROOT=skills - BOX__LOCAL__ALLOWED_MOUNT_ROOTS=${LANGBOT_BOX_ROOT:-${PWD}/data/box} - BOX__DOCKER__CPU_LIMIT_ENABLED=${LANGBOT_BOX_DOCKER_CPU_LIMIT_ENABLED:-true} ports: - 5300:5300 # For web ui and webhook callback - 2280-2285:2280-2285 # For platform reverse connection networks: - langbot_network networks: langbot_network: driver: bridge