一个开箱即用的 Multica Runtime 容器:预装 multica、opencode、Codex CLI、Reasonix 等 agent,并内置 New-API / DeepSeek 的接入与协议转换。构建后填入 .env 即可启动一个可用的运行时容器。
基础镜像为 ghcr.io/prefix-dev/pixi:0.76.1-noble-cuda-13.0.0(Ubuntu Noble + CUDA 13.0.0),已预装 pixi。容器内软件如下(Dockerfile 未固定版本的会在构建时取最新,括号内为当前镜像的实测版本):
| 组件 | 版本 | 安装方式 | 说明 |
|---|---|---|---|
| pixi | 0.76.1 | 基础镜像 | 包/环境管理器;multica、opencode 通过 pixi global 安装 |
| Node.js | v22.23.2 | 官方 tarball 解压到 /usr/local |
供 npm 全局工具、ponytail 的 hooks 使用 |
| npm | 10.9.8 | 随 Node | registry 设为 registry.npmmirror.com,@tencent-ai 走腾讯镜像 |
| pnpm | 12.4.1 | npm -g |
|
| multica | 0.4.43 | pixi global(channel https://prefix.dev/sylens) |
Runtime 本体:自动登录并启动 daemon |
| opencode | 1.18.30 | pixi global(同上 channel) |
|
| Codex CLI | 0.154.0 | npm -g @openai/codex |
|
| Reasonix | 最新 | npm -g reasonix |
容器内 bash 沙箱依赖 bubblewrap(见 Reasonix 章节) |
| CLIProxyAPI | 7.2.146 | GitHub Release 固定版本 + SHA256 校验,装到 /usr/local/bin/cliproxyapi |
Codex 协议转换桥接 |
| ponytail | v4.9.0 | git clone --depth 1 --branch v4.9.0 → /opt/ponytail |
仅 Codex 的插件,默认关闭 |
| gh (GitHub CLI) | 2.45.0 | apt |
容器启动时交互式登录 |
| docker CLI | 29.1.3 | apt docker.io |
配合挂载的宿主机 docker socket |
| docker compose | 2.40.3 | apt docker-compose-v2 |
|
| curl / git / sudo / xz-utils | - | apt |
其它环境特性:
- 支持 GPU(NVIDIA GPU + DRI 设备)。
ubuntu用户拥有免密 sudo,且已加入镜像内的docker组。- 容器内可直接调用宿主机 Docker(见 容器内使用 Docker)。
docker-compose build
docker-compose up -d按 .env.example 填写 .env。关键变量:
| 变量 | 必填 | 说明 |
|---|---|---|
MULTICA_TOKEN |
是 | 在 Multica 工作区的 API TOKEN 中生成。容器启动后自动登录(server 固定为 https://api.multica.ai)并启动 daemon |
CONTAINER_NAME |
是 | 运行时容器名 |
DEEPSEEK_TOKEN |
二选一 | DeepSeek 官方 API key |
NEW_API_TOKEN |
二选一 | New-API 网关 key(优先使用) |
NEW_API_BASE_URL |
否 | New-API 地址,默认 http://192.168.8.228:3000 |
DOCKER_HOST_GID |
否 | 宿主机 docker 组 GID,默认 999(见下) |
- multica 使用 token 登录:
MULTICA_TOKEN与运行时编码绑定,手动生成并保存有助于恢复运行时容器。 - GitHub 需在容器启动后手动认证:用
docker logs YOU_CONTAINER_NAME_FOR_RUNTIME查看日志里的验证码,打开https://github.com/login/device完成认证。认证后权限与 GitHub 网页端一致,无需额外配置私有仓库/组织权限。
容器支持两个上游,可同时配置:
| 提供方 | 地址 | 凭证 |
|---|---|---|
| DeepSeek 官方 | https://api.deepseek.com |
DEEPSEEK_TOKEN |
| New-API 网关 | NEW_API_BASE_URL(默认 http://192.168.8.228:3000) |
NEW_API_TOKEN |
优先级:设置了 NEW_API_TOKEN 时 Codex 默认走 New-API,否则回退 DeepSeek 官方。Reasonix 两个都接入。opencode 默认用 DeepSeek 官方,同时也可选 New-API。
pixi global 安装。容器启动时若设置了 MULTICA_TOKEN,自动执行:
multica config set server_url https://api.multica.ai
multica config set app_url https://multica.ai
multica login --token "$MULTICA_TOKEN"
multica daemon start启动时写入两份配置:
~/.local/share/opencode/auth.json:写入所有已提供的 provider key(deepseek、newapi)。~/.config/opencode/opencode.json:注册自定义 providernewapi(@ai-sdk/openai-compatible,baseURL = $NEW_API_BASE_URL/v1),并设默认模型deepseek/deepseek-v4-flash。
默认模型 deepseek/deepseek-v4-flash 走 DeepSeek 官方;想用 New-API 网关时:
opencode --model newapi/deepseek-v4-flash或在交互会话里用 /models 切换。
启动时(setup_codex_official)生成:
-
~/.codex/config.toml:model = "deepseek-v4-flash" model_provider = "newapi" # 无 NEW_API_TOKEN 时为 deepseek preferred_auth_method = "apikey" forced_login_method = "api" model_reasoning_effort = "high" model_catalog_json = "~/.codex/models.json" web_search = "disabled" # 网关只接受 function 工具 [model_providers.newapi] base_url = "http://127.0.0.1:8317/v1" # 桥接就绪时;否则上游直连地址 wire_api = "responses"
-
~/.codex/models.json:模型目录,当前仅deepseek-v4-flash(含base_instructions,兼容 Codex CLI >= 0.144.0)。 -
项目
/home/ubuntu默认标记为trust_level = "trusted"。
用法:
codex # 在任意项目目录直接使用
codex -i screenshot.png # deepseek-v4-flash 支持图片输入New-API 上游会经内置的 CLIProxyAPI 桥接(见下节);DeepSeek 官方则按需探测后决定是否桥接。
启动时(setup_reasonix)写入:
-
~/.reasonix/.env:DEEPSEEK_API_KEY、NEW_API_KEY。 -
~/.reasonix/config.toml:default_model = "deepseek/deepseek-v4-flash" language = "zh" [[providers]] # deepseek 官方 name = "deepseek" base_url = "https://api.deepseek.com" models = ["deepseek-v4-flash"] [[providers]] # newapi 网关 name = "newapi" base_url = "$NEW_API_BASE_URL/v1" models = ["deepseek-v4-flash", "qwen3.8-flash"]
用法:
reasonix # 交互会话
reasonix run "帮我改个 bug" # 无界面执行
reasonix run --model newapi "..." # 切到 New-API
reasonix run --model deepseek "..." # 切到 DeepSeek 官方可选:REASONIX_DEFAULT_MODEL 覆盖默认模型(默认 deepseek/deepseek-v4-flash)。
bash 沙箱(已启用):Reasonix 1.38.8 起权限 preset(read-only / workspace-write) 接管 bash 沙箱,ACP 新会话的 preset 是
workspace-write,reasonix 会用 bubblewrap 把每条 bash 关进沙箱;[sandbox] bash = "off"在该版本起不再生效 ([desktop] default_tool_approval_mode/[bot] tool_approval_mode也不作用于 ACP, 实测无效)。若容器里 bwrap 起不来,preset 会 fail closed,任何 bash 调用都拿不到 shell。因此本容器把沙箱真正跑起来:
Dockerfile安装bubblewrap;docker-compose.yml放开security_opt: [seccomp=unconfined, apparmor=unconfined]并cap_add: [SYS_ADMIN]—— Docker 默认 seccomp 拦unshare/clone(CLONE_NEW*)、 默认 AppArmor 拦mount,缺这三项 bwrap 会报Creating new namespace failed/Failed to make / slave。这样 reasonix 跟随最新版本,同时保留自身的 bash 沙箱(容器边界 + bwrap 双层)。 注意这三项放宽了容器的 seccomp/AppArmor 并多给了
SYS_ADMIN;若不需要沙箱,可去掉 它们并改用其它方式(如把会话切到 Full access)。 若只想快速恢复而暂不改 compose,也可降级到reasonix@1.38.7并设[sandbox] bash = "off"(该版本仍认这个设置)。
ponytail 是一个“lazy senior dev”规则集(MIT):写代码前逐级判断(YAGNI → 复用已有代码 → 标准库 → 平台原生能力 → 已装依赖 → 一行代码 → 最后才写最小实现)。
- 只给 Codex 安装,其他 agent(opencode / Reasonix 等)不安装、不启用,也不写全局规则文件。
- 安装方式:
setup_ponytail通过codex plugin marketplace add /opt/ponytail+codex plugin add ponytail@ponytail(本地路径 marketplace,完全离线、版本固定)。 - 默认级别
off:~/.config/ponytail/config.json的defaultMode为off,不注入任何规则。
在命令行临时开启(只影响本次会话):
PONYTAIL_DEFAULT_MODE=full codex # full 级别
PONYTAIL_DEFAULT_MODE=ultra codex # 更激进
PONYTAIL_DEFAULT_MODE=lite codex # 更宽松
codex # 默认:off取值 lite / full / ultra / off。想改容器默认级别:改 ~/.config/ponytail/config.json 的 defaultMode,或在 .env 里设 PONYTAIL_DEFAULT_MODE=full。
hooks 信任:Codex 默认要求交互式 /hooks 确认插件 hooks,容器里无法交互,因此 setup_ponytail 装好插件后会调用 scripts/codex-trust-plugin-hooks.mjs:查询本地 app-server 的 hooks/list,把每个 ponytail hook 的 trusted_hash 写入 ~/.codex/config.toml 的 [hooks.state."<key>"](等价于在 /hooks 里选 “Trust all and continue”)。因此 PONYTAIL_DEFAULT_MODE=full codex 可直接每轮自动注入规则。
该 hash 是 hook 定义的内容哈希(事件、matcher、命令模板、timeout、statusMessage 等),插件或 Codex 版本变化时会变。脚本每次启动现算现写,所以始终匹配;若该步骤失败(打印 WARNING),仍可手动
/hooks,或临时用codex --dangerously-bypass-hook-trust绕过。
会话内可用 ponytail 的 skills:@ponytail(ruleset)、@ponytail-review、@ponytail-audit、@ponytail-debt、@ponytail-gain、@ponytail-help。
想在项目内以“指令式”方式使用 ponytail(不装插件),把
/opt/ponytail/AGENTS.md复制到项目根即可。Multica workspace 内由平台注入自己的AGENTS.md,容器不会改动它。
Codex CLI 只会说 OpenAI 的 responses 协议,而 new-api 网关的 responses 支持不完整——非流式探测可能返回 200,但 Codex 实际使用的流式请求会中途断开(stream closed before response.completed)。镜像内置 CLIProxyAPI 做协议转换:
codex ──responses──> 127.0.0.1:8317 (CLIProxyAPI) ──chat/completions──> new-api
容器启动时 setup_cliproxyapi 会:
- 决定是否插入桥接:上游为 new-api 时始终启用(不做 200 跳过判断,避免非流式探测误判);其它上游探测
POST /v1/responses,404/405/501/400 明确不支持时启用,其余保持直连; - 生成
~/.cli-proxy-api/config.yaml(只绑127.0.0.1,上游配在openai-compatibility下),拉起cliproxyapi并等/v1/models就绪(30s 超时,失败则回退直连); - 把
~/.codex/config.toml的base_url指到http://127.0.0.1:8317/v1,experimental_bearer_token换成桥接自身的 key。
生成的 config.yaml 里固定写入 disable-cooling: true。桥接只有一条上游凭据,而 CLIProxyAPI 默认会对上游失败做凭据/模型冷却:一次瞬时失败(5xx/超时/断流)就把唯一凭据置入冷却(默认 60s,401/403 为 30m,404 为 12h),冷却期内所有请求直接返回 503 auth_unavailable: no auth available。单凭据场景下没有可切换的备用凭据,冷却只是把上游抖动放大成整段黑屏(表现为“用一段时间就 503”)。关闭冷却后,真实的上游错误会直接透传,由 Codex 与 request-retry 重试。
相关环境变量(均有默认值,通常无需设置):
| 变量 | 默认 | 说明 |
|---|---|---|
CLIPROXY_BRIDGE |
auto |
auto 按上游类型启用(new-api 始终启用,其它上游探测后决定)/ on 强制启用 / off 禁用 |
CLIPROXY_PORT |
8317 |
桥接监听端口(仅 127.0.0.1) |
CLIPROXY_HOME |
/home/ubuntu/.cli-proxy-api |
配置、auth 目录、日志、pid 所在位置 |
CLIPROXY_API_KEY |
自动生成 | 桥接访问 key,自动生成后持久化在 $CLIPROXY_HOME/api_key |
CLIPROXY_MODELS |
跟随上游 | 模型映射 上游模型名:Codex侧名字,逗号分隔,省略 :别名 时两边同名 |
排查:tail -f ~/.cli-proxy-api/logs/cliproxyapi.log,或 curl -s http://127.0.0.1:8317/v1/models -H "Authorization: Bearer $(cat ~/.cli-proxy-api/api_key)"。
compose 配置中设置了三项映射:
- 保留 agent 的 workspace 文件以及 multica 运行时设备信息:
- 工作空间数据:
./data/multica_workspaces→ 容器/home/ubuntu/multica_workspaces - 运行时认证信息:
./data/multica_daemon→ 容器/home/ubuntu/.multica
- 工作空间数据:
- opencode 认证文件,避免每次手动配置:
- 认证信息:
~/.local/share/opencode/auth.json→ 容器内对应位置
- 认证信息:
compose 将宿主机 Docker socket(/var/run/docker.sock)挂载进运行时容器,并在镜像内预装 docker CLI(docker.io)与 docker compose 插件。
为了让容器内的 ubuntu 用户可以直接操作 docker:
- Dockerfile 中已把
ubuntu用户加入镜像内的docker组。 - compose 通过
group_add把宿主机 docker 组的 GID(DOCKER_HOST_GID,默认999)注入容器进程,使容器内所有进程(包括 multica daemon 派生的 agent 进程)都能访问宿主机 docker socket。
首次配置时请确认 .env 中的 DOCKER_HOST_GID 与宿主机一致,在宿主机上执行以下命令获取真实值:
stat -c %g /var/run/docker.sock配置正确后,容器内 agent 可直接执行 docker run、docker build、docker compose up 等命令创建和管理容器,无需 sudo。
注意:容器内创建的容器是宿主机上的同级容器,并非真正的嵌套运行时。如果宿主机没有 Docker 运行环境,需要先安装 Docker。
遇到 agent 将容器内软件损坏,或发生意外情况需要重置容器的情况,保持配置不变,执行:
docker compose down -v && docker compose up -d在不同目录克隆本项目,配置 .env 使用不同的 CONTAINER_NAME,然后进行首次配置启动,即可在单机上开启不同的运行时。