一个容器,跑起 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 编程会话docker run 解决问题三个组件依旧各司其职,只是住在同一个容器、并收敛成一个 Node 进程对外:
┌──────────────────── happy-cnb 容器 ─────────────────────┐ │ │ │ happy-server :8687 │ │ ├─ /v<N>/* REST + socket.io /v1/updates │ │ └─ /, /_expo/*, /assets/* (via @fastify/static) │ │ ▲ │ │ │ 端到端加密(零知识中继) │ │ ▼ │ │ happy <agent> │ │ └─ 在 /workspace 里跑 AI 会话 │ │ │ └─────────────────────────────────────────────────────────┘ ▲ ▲ │ 浏览器(桌面 / 移动端) │ -v $(pwd):/workspace
happy-app 和 happy CLI 之间必须经 happy-server 中继通信(端到端加密、server 零知识),这是 Happy 的架构决定的。好消息是 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-home:/happy-home \
-v happy-data:/happy-data \
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, secret} 由 CLI 和 Web 前端共享(写在 /happy-home/access.key 和 /app/web/auto-login.js),两侧属于同一个本地账号。凭据持久化在 happy-home 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/ |
-v $(pwd):/workspace | 交给 Agent 操作的项目目录 |
-v happy-home:/happy-home | 持久化 happy CLI 的认证凭据 |
-v happy-data:/happy-data | 持久化 happy-server 的 PGlite 数据库与文件存储 |
| 变量 | 默认值 | 说明 |
|---|---|---|
HAPPY_CNB_DEFAULT_AGENT | codebuddy | 未传 agent 参数时默认启动的 Agent |
HAPPY_CNB_WORKDIR | /workspace | Agent 启动前 cd 到的目录 |
HAPPY_HOME_DIR | /happy-home | happy CLI 配置 / 凭据目录 |
APP_PORT | 8687 | happy-server 对外监听端口(唯一需要暴露的端口) |
HAPPY_CNB_WEB_ROOT | /app/web | happy-app 静态资源根目录 |
HANDY_MASTER_SECRET | 自动生成并保存于 $HAPPY_HOME_DIR/master.secret | server master secret |
DATA_DIR / PGLITE_DIR | /happy-data, /happy-data/pglite | server 数据目录 |
HAPPY_CODEBUDDY_STALL_TIMEOUT_MS | 0(禁用) | codebuddy agent 无响应多少毫秒后向 UI 回写错误。默认禁用,避免模型思考时间长被误判;设为正整数(如 90000)可开启失联保护 |
HAPPY_CNB_PERMISSION_MODE | bypassPermissions | 注入给 codebuddy agent 的默认 --permission-mode,让 AI 在容器沙箱里直接执行 shell / git / 文件工具。设为空字符串可禁用注入,或改成 default / acceptEdits / plan 等 |
⚠️ 镜像的设计目标是本地或受信任网络使用。
happy-server 与 CLI 之间是端到端加密的,但容器把 8687 端口暴露到宿主机,且免登录使用,不要直接把这个端口映射到公网。如需远程访问,建议:
镜像里打包的是 happy-cli + codebuddy agent,真正的 LLM 调用由 @tencent-ai/agent-sdk 里的 codebuddy-headless 完成。它需要一个可用的 AI 端点 + 凭据才能回复:
在 CNB 云原生构建平台里跑:
CNB 会自动注入凭证和端点 URL,开箱即用。
在个人机器上 docker compose up -d:
- 如果 SDK 长时间不吐消息,默认会一直等下去;如需失联保护把错误回写到 UI,可设
HAPPY_CODEBUDDY_STALL_TIMEOUT_MS=90000(毫秒)开启- 如果要本地跑出真实 AI 回复,需要自行提供可用的 LLM 凭据。典型做法:在
docker-compose.yml的环境里设置CODEBUDDY_BASE_URL+CODEBUDDY_API_KEY(或对应 agent 的官方凭据,例如ANTHROPIC_API_KEY、OPENAI_API_KEY)
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, secret} 并写给 CLI / Web │ └── README.md # 一体化镜像的详细说明 ├── packages/ # Happy monorepo(cli / server / app / wire / agent) ├── docs/ # Happy 原项目文档(架构、协议、加密等) └── scripts/ # 辅助脚本
本项目基于开源项目 slopus/happy 二次开发,特别感谢 Happy 团队与其社区贡献者:
happy-cnb 在 Happy 的基础上聚焦于容器化一体分发 + CNB 云原生开发场景适配,只分发 Web 端(并适配移动端浏览器),不再包含原项目的 iOS / Android / macOS 客户端分发。原作者的所有贡献和权利依旧归属于 Happy 项目。
Happy 相关资源:
沿用上游 MIT License,详见 LICENSE。