私有部署与观测

Remote Control

由 BRIDGE_MODE feature flag 驱动的远程控制:把本地终端注册为一个「bridge 环境」, 在浏览器 Web UI 里创建会话、实时查看消息与工具调用、审批权限。整套后端 Remote Control Server (RCS) 可用 Docker 自托管,数据只经过你自己的私有网络。

  • Docker 自托管
  • 手机可用
  • Bridge / RC

这是什么

Remote Control 让本地的 qsdashi 会话不再局限于当前终端:CLI 会把自己注册成一个 bridge 环境,持续长轮询等待任务;你可以从浏览器(甚至手机)打开 Web UI,选中该环境后 创建会话、发指令、审批工具权限。本地终端成为「执行者」,控制面在浏览器里。

中间层是 Remote Control Server (RCS)——一个纯内存的中间服务,负责环境注册、工作轮询、 消息双向传输与会话管理。它有两种部署形态:

形态 认证方式 门控 数据流经
自托管 RCS API Key(RCS_API_KEYS) 设置 CLAUDE_BRIDGE_BASE_URL 后自动跳过 GrowthBook / 订阅检查 你自己的服务器
云端(Anthropic CCR) claude.ai OAuth 订阅 需要 tengu_ccr_bridge 通过 Anthropic 基础设施

两种形态都要求构建时启用 BRIDGE_MODE feature flag。自托管模式的核心优势是: 只要设置了 CLAUDE_BRIDGE_BASE_URL,代码里的 isSelfHostedBridge() 即返回 true,无需 claude.ai 账户即可使用。

RCS 的职责:

  • 接收 CLI 的环境注册与工作轮询(长轮询 + 心跳保活)
  • 接收 acp-link 的 ACP agent 注册,支持 WebSocket relay 桥接
  • 提供 Web UI 供操作者远程监控与审批
  • 通过 WebSocket / SSE 双向传输消息,管理会话、环境与权限请求

前置条件

  • 服务器:一台能被 CLI 与浏览器同时访问的机器(物理机 / VM / 容器均可)。
  • Docker:容器化部署 RCS 时需要;若用 bun run rcs 本地启动,则只需 Bun。
  • 启用 BRIDGE_MODE 的构建:dev 模式默认启用;build 模式的默认 feature 列表也包含 BRIDGE_MODE。运行时可用 FEATURE_BRIDGE_MODE=1 显式开启。
  • 自托管模式不需要 claude.ai 账户,只需要一组与服务器端 RCS_API_KEYS 匹配的令牌。
i
存储是纯内存的

RCS 用内存 Map 存储会话与环境,重启后数据全部丢失,且不支持水平扩展(单实例部署)。 /app/data 卷已预留但当前未使用。

安装与启动

任选一种方式部署 RCS,然后按「实战示例」用 CLI 连接。

  • 方式 A:Docker 构建并运行

    在项目根目录构建镜像,再以环境变量启动容器。

    Terminal
    # 构建镜像
    docker build -t rcs:latest -f packages/remote-control-server/Dockerfile .
    
    # 启动容器
    docker run -d \
      --name rcs \
      -p 3000:3000 \
      -e RCS_API_KEYS=sk-rcs-your-secret-key-here \
      -e RCS_BASE_URL=https://rcs.example.com \
      -v rcs-data:/app/data \
      --restart unless-stopped \
      rcs:latest

    也可直接用预构建镜像 ghcr.io/qianshou-dashi/remote-control-server:latest 启动。

  • 方式 B:Docker Compose
    docker-compose.yml
    services:
      rcs:
        build:
          context: .
          dockerfile: packages/remote-control-server/Dockerfile
          args:
            VERSION: "0.1.0"
        ports:
          - "3000:3000"
        environment:
          - RCS_API_KEYS=sk-rcs-your-secret-key-here
          - RCS_BASE_URL=https://rcs.example.com
        volumes:
          - rcs-data:/app/data
        restart: unless-stopped
    
    volumes:
      rcs-data:
    Terminal
    docker compose up -d
  • 方式 C:本地直接启动(无需 Docker)

    仓库根 package.json 提供 rcs 脚本,执行 scripts/rcs.ts,读取 RCS 配置后用 Bun.serve 起服务。

    Terminal
    # 默认监听 3000 端口
    bun run rcs
    
    # 覆盖端口与密钥
    RCS_API_KEYS=key1,key2 RCS_PORT=4000 bun run rcs
  • 验证服务健康
    Terminal
    curl https://rcs.example.com/health
    # 预期: {"status":"ok","version":"0.1.0"}
  • 配置

    服务器端环境变量(由 packages/remote-control-server/src/config.ts 读取):

    变量 必填 默认值 说明
    RCS_API_KEYS 是 (空) API 密钥列表,逗号分隔。用于客户端认证与 JWT 签名,务必设置强密钥
    RCS_PORT 否 3000 服务监听端口
    RCS_HOST 否 0.0.0.0 服务监听地址
    RCS_BASE_URL 否 http://localhost:<port> 外部访问 URL,用于生成 WebSocket 连接地址,须与客户端实际访问地址一致
    RCS_VERSION 否 0.1.0 版本号,显示在 /health 响应中
    RCS_POLL_TIMEOUT 否 8 V1 工作轮询超时(秒)
    RCS_HEARTBEAT_INTERVAL 否 20 心跳间隔(秒)
    RCS_JWT_EXPIRES_IN 否 3600 JWT 令牌有效期(秒)
    RCS_DISCONNECT_TIMEOUT 否 300 断线判定超时(秒)
    RCS_WS_IDLE_TIMEOUT 否 30 WebSocket 空闲超时(秒),Bun 发送协议级 ping
    RCS_WS_KEEPALIVE_INTERVAL 否 20 服务端到客户端 keep_alive 帧间隔(秒),防止反向代理关闭空闲连接
    RCS_WEB_CORS_ORIGINS 否 (空) Web UI 跨域允许来源列表,逗号分隔

    客户端(qsdashi CLI)环境变量:

    变量 必填 说明
    CLAUDE_BRIDGE_BASE_URL 是 RCS 服务器地址,如 https://rcs.example.com。设置此变量即启用自托管模式,跳过 GrowthBook 门控
    CLAUDE_BRIDGE_OAUTH_TOKEN 是 认证令牌,必须与服务器端 RCS_API_KEYS 中的某个值匹配
    CLAUDE_BRIDGE_SESSION_INGRESS_URL 否 WebSocket 入口地址,默认与 CLAUDE_BRIDGE_BASE_URL 相同
    QS_REMOTE 否 设为 1 时标记为远程执行模式
    *
    认证是两层

    客户端与 Worker 连接用 API Key 校验,并由 RCS_API_KEYS 派生 JWT;浏览器 Web UI 则使用 UUID 绑定会话(无用户账户、无登录),适合受信任网络环境。

    常用命令与参数

    CLI 子命令(cli.tsx 快速路径,均需 BRIDGE_MODE 启用):

    命令 说明
    qsdashi remote-control 把本机作为 bridge 环境启动,接受远程会话
    qsdashi rc 同上,简写
    qsdashi remote 旧别名,行为一致
    qsdashi sync 旧别名,行为一致
    qsdashi bridge 旧别名,行为一致

    其他相关入口:

    入口 行为
    qsdashi --remote-control [name] 启动交互式会话并启用 Remote Control,可附带会话名
    qsdashi --rc [name] --remote-control 的别名
    /remote-control(别名 /rc) 会话内命令,连接当前终端以进行远程控制,可带 [name]
    bun run rcs 在仓库内启动 RCS 服务(scripts/rcs.ts)

    已连接后再次执行 /remote-control 会弹出对话框,包含 Disconnect this session(断开远程连接)、Show QR code(显示 / 隐藏二维码)、 Continue(保持连接继续使用)三个选项。

    实战示例

    1. 在 CLI 所在机器设置连接变量:

    Terminal
    export CLAUDE_BRIDGE_BASE_URL="https://rcs.example.com"
    export CLAUDE_BRIDGE_OAUTH_TOKEN="sk-rcs-your-secret-key-here"

    2. 启动并注册环境:在 REPL 中执行 /remote-control, 或直接用子命令启动。环境型 Remote Control 注册成功后会打印连接 URL:

    Terminal
    # 发布版默认包含 BRIDGE_MODE
    CLAUDE_BRIDGE_BASE_URL=https://rcs.example.com \
    CLAUDE_BRIDGE_OAUTH_TOKEN=sk-rcs-your-secret-key-here \
    qsdashi
    
    # REPL 内执行
    /remote-control
    
    # 终端会显示环境 URL:
    # https://rcs.example.com/code?bridge=<environmentId>
    # 某些桥接模式下给出会话 URL:https://rcs.example.com/code/session_<id>

    3. 在浏览器打开 URL 操控。两种 URL 都能直接打开;只有 environment 模式会出现在 Web UI 的环境列表中。Web UI 位于 /code/* 路径,基于 React + Vite + Radix UI, 可查看运行环境、创建会话、实时查看对话与工具调用、审批权限、选择权限模式与模型、 查看 Plan 可视化,并支持 QR 码扫描跳转 ACP 直连视图。

    4.(可选)把 ACP agent 接入 RCS:

    Terminal
    ACP_RCS_URL=http://localhost:3000 \
    ACP_RCS_TOKEN=sk-rcs-your-key \
    acp-link qsdashi -- --acp

    注册后 ACP session 会在 Web UI 中显示品牌色标签,与普通 qsdashi session 区分。 详见 ACP 页面。

    i
    反向代理需放行 WebSocket

    Nginx 需设置 proxy_http_version 1.1、Upgrade 与 Connection "upgrade" 头,并把 proxy_read_timeout 调大 (建议 86400 秒);Caddy 的 reverse_proxy 会自动处理。

    常见问题排错

    !
    CLI 无法连接:Remote Control is not available in this build

    原因是 BRIDGE_MODE feature flag 未启用。使用 dev 模式(默认启用) 或确保构建时包含该 flag,也可用 FEATURE_BRIDGE_MODE=1 显式开启。

    !
    认证失败 (401 Unauthorized)

    检查 CLAUDE_BRIDGE_OAUTH_TOKEN 是否与 RCS_API_KEYS 中某个值 完全一致,确认 key 没有多余空格或换行,并确认两个环境变量都已设置。

    !
    WebSocket 连接中断

    若经反向代理,确认已正确配置 WebSocket 升级(Upgrade / Connection 头),proxy_read_timeout 足够大,且防火墙放行 WebSocket 流量。RCS 会以 RCS_WS_IDLE_TIMEOUT 与 RCS_WS_KEEPALIVE_INTERVAL 保活。

    !
    Web UI 看不到当前 Autopilot 状态

    standby 表示 proactive 已开启、正等待下一个 tick;sleeping 表示模型正在 SleepTool 等待窗口。两者通过 worker 的 external_metadata.automation_state 上报。若只显示普通 working spinner, 优先检查 CLI 与 RCS 之间的 worker metadata PUT 是否成功。

    *
    数据不会持久化

    RCS 是纯内存存储,服务器重启后所有会话与环境数据丢失;也不支持水平扩展, 仅适合单实例的中小规模使用。