一个容器,跑起 Happy 全家桶:用浏览器(桌面 / 移动端适配)远程控制容器里的 AI 编程 Agent
happy-cnb 基于开源项目 slopus/happy 二次开发,把原本需要分开部署的三件套打包进同一个 Docker 镜像,开箱即用:
| 组件 | 说明 |
|---|---|
happy-server | 后端中继,提供 REST + Socket.io |
happy-app | Web 控制台,仅分发 Web 端并适配移动端浏览器 |
happy CLI | 包裹 AI 编程 Agent 的本地进程 |
codebuddy / codex / gemini / claude 等 AI 编程会话npm run dev、静态服务等运行结果docker run 解决问题三个组件依旧各司其职,只是住在同一个容器、并收敛成一个 Node 进程对外:
┌──────────────────── happy-cnb 容器 ─────────────────────┐
│ │
│ happy-server :8687 │
│ ├─ /v<N>/* REST + socket.io /v1/updates │
│ └─ /, /_expo/*, /assets/* (via @fastify/static) │
│ ▲ │
│ │ 同容器内 REST / Socket.io 通信 │
│ │ (CNB 模式使用预共享 token) │
│ ▼ │
│ happy <agent> │
│ ├─ 在 /workspace 里跑 AI 会话 │
│ └─ Happy MCP:改标题 / CNB 端口转发 │
│ │
└─────────────────────────────────────────────────────────┘
▲ ▲
│ 浏览器(桌面 / 移动端) │ -v $(pwd):/workspace
happy-app 和 happy CLI 之间仍经 happy-server 做同步与 RPC 中继。happy-cnb 是单用户、单容器的 CNB / 本地开发场景:自动登录使用预共享 bearer token,消息与会话数据在 CNB 模式下走 no-op 加密路径,不再宣称 server 无法读取数据。server 与前端静态资源由同一个 Fastify 进程服务,对外只暴露一个端口。
docker build -f Dockerfile -t cnbcool/happy-cnb:latest .
docker run -it --rm \
--name happy-cnb \
-p 8687:8687 \
-v "$(pwd)":/workspace \
-v happy-cnb-data:/root/.happy-cnb \
cnbcool/happy-cnb:latest
默认会在 /workspace 启动 happy codebuddy 会话。想换 Agent,把第一个位置参数换成目标 Agent,后续参数原样透传给 happy CLI:
# 使用 codex
docker run ... cnbcool/happy-cnb:latest codex
# 使用 codebuddy 并附加参数
docker run ... cnbcool/happy-cnb:latest codebuddy --model gpt-4o --permission-mode acceptEdits
# 使用 gemini
docker run ... cnbcool/happy-cnb:latest gemini
happy-cnb container is readyhttp://localhost:8687/ —— 直接进入主界面,无需注册 / 登录 / 扫码容器启动时会生成一个随机 token 由 CLI 和 Web 前端共享(写在 /root/.happy-cnb/happy-home/access.key、/root/.happy-cnb/happy-home/agent.key 和 /app/web/auto-login.js),两侧属于同一个本地账号。凭据持久化在 happy-cnb-data volume,下次启动仍然是同一账号、同一套历史会话。
⚠️ 安全提醒:免登录意味着任何访问到
8687端口的人都能接管这个账号。仅用于本地 / 受信任网络。
入口脚本被软链到 /usr/local/bin/happy-cnb,检测到 server 已在跑时会跳过 bootstrap,只起 Agent:
docker exec -it <container> happy-cnb # 默认 agent
docker exec -it <container> happy-cnb codex
docker exec -it <container> happy-cnb gemini
| 端口 / 卷 | 说明 |
|---|---|
-p 8687:8687 | happy-server 对外端口(同时提供 Web 控制台与 API),浏览器访问 http://localhost:8687/。也支持挂在反向代理子路径下,前端会通过 cnb-env.js 自动识别 base path |
-v $(pwd):/workspace | 交给 Agent 操作的项目目录 |
-v happy-cnb-data:/root/.happy-cnb | 持久化所有运行时状态:happy CLI 凭据(happy-home/)+ happy-server 的 PGlite 数据库 / 上传文件(happy-data/) |
| 变量 | 默认值 | 说明 |
|---|---|---|
HAPPY_CNB_DEFAULT_AGENT | codebuddy | 未传 agent 参数时默认启动的 Agent |
HAPPY_CNB_WORKDIR | /workspace | Agent 启动前 cd 到的目录 |
HAPPY_HOME_DIR | /root/.happy-cnb/happy-home | happy CLI 配置 / 凭据目录 |
APP_PORT | 8687 | happy-server 对外监听端口(唯一需要暴露的端口) |
HAPPY_CNB_WEB_ROOT | /app/web | happy-app 静态资源根目录 |
HAPPY_CNB_HIDDEN_PORTS | 未设置 | 逗号分隔的端口列表;Agent 的 forward_port MCP 工具会拒绝把这些端口暴露到公网 |
HANDY_MASTER_SECRET | 自动生成并保存于 $HAPPY_HOME_DIR/master.secret | server master secret(用于 server 侧签名 / 服务令牌等,不代表 CNB 会话内容由客户端私有加密) |
DATA_DIR / PGLITE_DIR | /root/.happy-cnb/happy-data, /root/.happy-cnb/happy-data/pglite | server 数据目录 |
HAPPY_CODEBUDDY_STALL_TIMEOUT_MS | 0(禁用) | codebuddy agent 无响应多少毫秒后向 UI 回写错误。默认禁用,避免模型思考时间长被误判;设为正整数(如 90000)可开启失联保护 |
HAPPY_CNB_PERMISSION_MODE | yolo | 注入给 codebuddy agent 的默认 --permission-mode,让 AI 在容器沙箱里直接执行 shell / git / 文件工具。设为空字符串可禁用注入,或改成 default / acceptEdits / plan 等 |
CODEBUDDY_BASE_URL | 未设置(用 SDK 默认端点) | codebuddy agent 调用 LLM 的 API 端点,搭配 CODEBUDDY_API_KEY 使用 |
CODEBUDDY_API_KEY | 未设置 | codebuddy agent 调用 LLM 时使用的 API Key。本地 docker compose up 自托管 LLM 时必填 |
CODEBUDDY_MODEL | 未设置(使用 SDK 默认模型) | 覆盖 codebuddy agent 默认使用的模型名(如 gpt-4o、claude-sonnet-4、deepseek-v3)。由底层 @tencent-ai/agent-sdk 读取生效;若启动时通过 --model 显式指定,则以 CLI 参数为准 |
⚠️ 镜像的设计目标是本地或受信任网络使用。
happy-cnb 为了 CNB / 本地单用户容器场景简化了认证与存储路径:Web 与 CLI 共享同一个 bearer token,CNB 模式下消息、会话元数据等不再按客户端私有加密模型处理。因此容器把 8687 端口暴露到宿主机且免登录使用时,不要直接把这个端口映射到公网。如需远程访问,建议:
APP_PORT、SSH、Docker daemon、数据库、调试器等基础设施端口公开;内置 forward_port MCP 工具也会拒绝转发常见基础设施端口,并对数据库 / debugger 等敏感端口给出提醒在真实 CNB cloud-dev 环境里,codebuddy 会拿到一个内置 Happy MCP server,除了自动改会话标题,还提供 forward_port 工具。用户启动开发服务后,可以让 Agent 在确认后把容器内 TCP 端口转换成 CNB 的公开预览 URL,例如:
帮我启动前端开发服务,并把端口 5173 暴露成预览链接
注意事项:
CNB_VSCODE_PROXY_URI,普通本地 docker run / docker compose 环境下会返回不可用说明APP_PORT、SSH、Docker daemon、metrics、code-server 等内部端口会被拒绝;数据库、缓存、Node inspector 等敏感端口会提示风险重要:镜像里打包的是 happy-cli +
codebuddyagent,真正的 LLM 调用由@tencent-ai/agent-sdk里的codebuddy-headless完成。它需要一个可用的 AI 端点 + 凭据才能回复。
在 CNB 云原生构建平台里跑:
CNB 会自动注入凭证和端点 URL,开箱即用。
在个人机器上 docker compose up -d:
- 如果要本地跑出真实 AI 回复,需要自行提供可用的 LLM 凭据。典型做法:在
docker-compose.yml的环境里设置CODEBUDDY_BASE_URL+CODEBUDDY_API_KEY(或对应 agent 的官方凭据,例如ANTHROPIC_API_KEY、OPENAI_API_KEY)- 默认会使用 SDK 内置的默认模型。若要切换具体模型,额外设置环境变量
CODEBUDDY_MODEL=<模型名>(例如gpt-4o、claude-sonnet-4、deepseek-v3)即可;也可以在启动 agent 时通过happy-cnb codebuddy --model <模型名>临时覆盖,CLI 参数优先级高于环境变量。
happy-cnb/
├── Dockerfile # 一体化镜像(本项目主产物)
├── Dockerfile.server # 仅 happy-server 的镜像
├── Dockerfile.webapp # 仅 happy-app web 的镜像
├── happy-cnb/
│ ├── run.sh # 一体化镜像的入口脚本(= /usr/local/bin/happy-cnb)
│ ├── bootstrap-auth.ts # 首次启动生成 token 并写给 CLI / Web
│ └── README.md # 一体化镜像的详细说明
├── packages/ # Happy monorepo(cli / server / app / wire / agent)
├── docs/ # Happy 原项目与 happy-cnb 的架构 / 协议 / 设计文档
└── scripts/ # 辅助脚本
本项目基于开源项目 slopus/happy 二次开发,特别感谢 Happy 团队与其社区贡献者:
happy-cnb 在 Happy 的基础上聚焦于容器化一体分发 + CNB 云原生开发场景适配,只分发 Web 端(并适配移动端浏览器),不再包含原项目的 iOS / Android / macOS 客户端分发。原作者的所有贡献和权利依旧归属于 Happy 项目。
Happy 相关资源:
沿用上游 MIT License,详见 LICENSE。