OpenViking 发版实战:多产物 Tag 命名约定、Release 工作流与补发验证体系
OpenViking 一次发版会同时产出 Python 主包、SDK、Docker 镜像、TOS 资产、Rust CLI/npm 包与多类插件,其发布体系围绕“一个主版本 tag + 多个独立 tag 命名空间”组织。本文基于仓库根目录的 RELEASE.md 以及 .github/workflows 下实际追踪的 GitHub Actions 工作流、pyproject.toml 包配置逐环节展开,帮助发版负责人和贡献者理解 OpenViking 的版本解析机制、各发布通道的触发条件,以及发布失败后的补发与验证方法。
发版目标:一次主版本发布,产出多个独立资产
OpenViking 不发布单一产物。一次正式主版本发版(以 vX.Y.Z 主 tag 为准)会围绕不同使用入口发布一组相互关联的资产:
openvikingPython 主包:面向需要本地运行时、服务端、CLI 与完整功能的用户;- Python SDK
openviking-sdk:面向只通过 HTTP 调用已有 OpenViking 服务的轻量客户端; - Docker 镜像:面向容器化部署,发布到 GHCR 和 Docker Hub;
- TOS 发布资产:源码压缩包、安装脚本与稳定下载路径;
- Rust CLI / npm 包:面向通过 npm 安装
ovCLI 的用户; - OpenClaw / ClawHub 插件:OpenClaw 插件分发渠道;
- TypeScript SDK
@openviking/sdk:TypeScript / JavaScript HTTP 客户端; - OpenCode 插件
@openviking/opencode-plugin:OpenCode 集成分发; - Controlplane MCP
mcp-server-openviking-controlplane:控制面 MCP server 与ov-cpCLI; - VikingBot:当前随
openviking[bot]额外依赖与官方 Docker 镜像分发,历史独立发版入口单独说明以避免误用。
一条硬性约束是:正式主发版中,Python 主包、Docker 镜像与 TOS 资产必须使用同一个主版本 tag;SDK、CLI、ClawHub 插件则各自使用独立的 tag 或 version 命名空间。
从源码结构看,这一“多资产、单一主 tag”的设计在根 pyproject.toml 中有直接体现:
- 主包名
openviking,版本dynamic = ["version"],由setuptools_scm从 Git tag 解析,tag_regex只匹配v开头的语义化版本(见 pyproject.toml#L203-L207),解析结果写入openviking/_version.py; - 主包
dependencies中显式声明openviking-sdk>=0.1.9,即主包依赖独立发布的 SDK,二者版本解耦(见 pyproject.toml#L32-L33); [project.optional-dependencies]中的bot额外依赖组承载 VikingBot 全功能(Telegram、Slack、钉钉、沙箱、Gradio 等),对应安装入口pip install "openviking[bot]"(见 pyproject.toml#L140-L177);- 打包时
[tool.setuptools.packages.find]从.与bot两处收集openviking*与vikingbot*包,package-data还会把预编译的 ragfs Python 扩展、向量引擎.so/.pyd与bin/ov二进制打进 wheel(见 pyproject.toml#L209-L232),这就是“一个 wheel 包含运行时 + Rust CLI 二进制 + 服务端”的原因; [project.scripts]定义了ov、openviking、openviking-server、vikingbot四个可执行入口(见 pyproject.toml#L197-L201),其中ov/openviking是指向 Rust CLI 的极简包装器。
版本与 Tag 约定
各产物推荐使用如下 tag / 版本约定:
| 产物 | 推荐 tag / version | 说明 |
|---|---|---|
openviking 主包 |
vX.Y.Z |
主 release tag,例如 v0.3.26 |
openviking-sdk |
python-sdk@X.Y.Z |
SDK 专用 tag,例如 python-sdk@0.1.3 |
@openviking/sdk(TypeScript) |
typescript-sdk@X.Y.Z |
TypeScript SDK tag |
| Rust CLI / npm CLI | cli@X.Y.Z |
CLI 专用 tag,例如 cli@0.2.0 |
| ClawHub 插件 latest | YYYY.M.D 或 YYYY.M.D-N |
由 workflow 自动生成或手动指定 |
| ClawHub 插件 dev | YYYY.M.D-dev.N |
dev channel 使用 |
主包版本通过 setuptools_scm 从 Git tag 解析,git_describe_command 明确限定 --match v[0-9]*(见 pyproject.toml#L203-L207);SDK 同样使用 setuptools_scm,但其工作目录限定在 sdk/python 且 tag 匹配 python-sdk@*,因此与主包 tag 互不干扰。这种“tag 前缀即命名空间”的约定,使得同一仓库里主包、SDK、CLI 可以在任意时刻独立发版而互不覆盖。
正式主包发版流程
主包正式发版走根仓库的 GitHub Release,完整链路如下:
- 确认待发布改动已合入目标分支,且 PR / main 分支检查通过;
- 创建主包 tag,例如
v0.3.26; - 在 GitHub 上基于该 tag 发布 Release;
03. Release工作流在 Release published 事件触发;- 工作流复用
_Build Distribution构建 sdist 与多平台 wheel; - 将构建产物发布到 PyPI;
- 构建并推送多架构 Docker 镜像;
20. Release TOS Upload工作流上传源码压缩包与安装脚本到 TOS。
正式主发版的发布目标为:PyPI 上的 openviking;GHCR 上的 ghcr.io/<owner>/<repo>;Docker Hub 上的 <dockerhub-user>/openviking;TOS 上的版本化 release 路径与可选 latest 稳定路径。
.github/workflows/release.yml 的实现印证了这条链路:
- 触发与门禁:工作流仅在
release.published且 tag 以v开头时执行正式发布逻辑——if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'v')(见 release.yml#L46-L54)。python-sdk@*、cli@*等组件 tag 的 Release 事件不会误触发主包发布,它们由各自专用工作流处理; - 构建:
buildjob 复用可调用工作流_build.yml(即_Build Distribution),默认构建 5 个平台的 wheel:ubuntu-24.04(x86_64)、ubuntu-24.04-arm(aarch64)、macos-14(arm64)、macos-15-intel(x86_64)、windows-latest(x86_64),Python 版本默认3.10; - 权限门禁:手动 dispatch 场景下,
permission-checkjob 会调用 GitHub API 校验触发者具备admin/maintain/write权限,无写权限直接失败(见 release.yml#L56-L88); - 发布:
publish-testpypi/publish-pypi两个 job 分别绑定testpypi/pypiGitHub environment,使用id-token: write走 PyPI trusted publishing(OIDC),并设置skip-existing: true,重复发布同版本时不会报错而是跳过; - 镜像校验:
verify-dockerjob 会轮询等待 tag 对应的 Docker 构建 run 完成,再用docker buildx imagetools inspect断言 GHCR 与 Docker Hub 上的版本 tag 与latest指向同一 manifest digest(见 release.yml#L159-L215)。这是“主包发版与镜像口径一致”的自动化保证。
主包手动构建、测试发布与补发
release.yml 同样支持 workflow_dispatch 手动触发,输入参数包括:
target:none(只构建不发布)、testpypi(发布到 TestPyPI)、pypi(发布到 PyPI)、both(两者都发);build_sdist/build_wheels:分别控制是否构建源码包与 wheel;os_json:JSON 字符串形式的目标平台 runner 列表(ubuntu-24.04=x86_64、ubuntu-24.04-arm=aarch64、macos-14=arm64、macos-15-intel=x86_64、windows-latest=x86_64);python_json:JSON 字符串形式的 Python 版本列表。
当“Python 包构建成功但发布失败”时,仓库提供 .github/workflows/_publish.yml(即 16. _Publish Distribution)作为恢复与补发通道:它支持 workflow_call 与手动 dispatch,手动时必须传入 build_run_id(从构建 run 的 URL 中获取),工作流会跨 run 下载该次构建产出的 python-package-distributions-* artifact 再执行发布(见 _publish.yml#L16-L31 与 _publish.yml#L89-L97)。该路径定位为故障恢复,不应作为正常发版入口。
Docker 镜像发布与补发
正式主发版时,Docker 镜像由发布链路自动构建并推送到 GHCR 与 Docker Hub,正式 release 下写入版本 tag 与 latest tag。
仓库同时提供独立的 Build and Push Docker Image 工作流 .github/workflows/build-docker-image.yml,适用于三种场景:手动指定版本重建镜像、main 分支镜像构建、tag 触发后的镜像补发。从该工作流定义可以看到:
- 触发条件为
main分支 push、v*.*.*tag push 与workflow_dispatch(需填version输入); - 镜像名由仓库名小写化生成;amd64 / arm64 双架构矩阵并行构建(
linux/amd64在ubuntu-24.04,linux/arm64在ubuntu-24.04-arm); - 版本解析优先级为:手动输入的
version> tag 名 >setuptools-scm解析(main分支走build_support.versioning.resolve_openviking_version());解析出空值或0.0.0时直接失败退出。
需要注意的一点:独立 Docker 工作流当前也会在 v*.*.* tag push 时自动触发,而 tag push 与 release published 事件几乎同时发生。因此正式 GitHub Release 的发布口径仍以 03. Release 工作流为准,独立 Docker 工作流应视为“镜像专用构建或补发路径”。为避免重复发布,正式版本优先使用主发布工作流;仅当镜像需要补发或做特殊验证时才使用独立工作流。
TOS 发布资产
TOS 发布流程(20. Release TOS Upload,见 .github/workflows/release-tos.yml)会生成源码压缩包并上传以下资产:
releases/<tag>/openviking-<tag>-source.zip(由git archive生成);- Claude Code memory plugin 安装脚本;
- Codex memory plugin 安装脚本;
- 对应的 TOS install 脚本。
关键行为:
- 触发条件与主发布一致:
release.published且 tag 以v开头,组件 tag(python-sdk@*、cli@*等)不会触发 TOS 上传; - 手动补发时可指定
tag输入,并通过布尔量update_latest决定是否同时覆盖稳定 /latest路径(默认覆盖); - 如果
TOS_ACCESS_KEY、TOS_SECRET_KEY、TOS_REGION、TOS_RELEASE_BUCKET、TOS_ENDPOINT任一 secret 未配置,工作流会跳过上传并在 step summary 中说明,而不会让整个发布流程失败——这使 TOS 通道对未配置该通道的镜像部署环境是可选的。
Python SDK 发版流程
Python SDK 位于 sdk/python,PyPI 包名为 openviking-sdk,使用独立 tag 命名空间 python-sdk@X.Y.Z。典型流程与 .github/workflows/python-sdk-release.yml 的实现一一对应:
- 合入 SDK 相关改动;
- 创建并推送 tag,例如
python-sdk@0.1.3; Python SDK Release工作流被 Release published 事件触发(其if条件限定 tag 以python-sdk@开头);- 工作流在
sdk/python下执行python -m setuptools_scm解析 SDK 版本; - 校验 tag 必须严格等于
python-sdk@<resolved-version>,不匹配即失败(见 python-sdk-release.yml#L70-L80); - 用
python -m build构建sdk/python的 sdist/wheel,通过 trusted publishing 发布到 PyPI。
该工作流也支持手动 dispatch,可选 testpypi、pypi 或 both 目标,适合验证与补发;正式 SDK 发版仍建议使用 python-sdk@X.Y.Z tag。
Rust CLI / npm 发版流程
Rust CLI 的 tag 格式为 cli@X.Y.Z。推送 cli@* tag 后,Rust CLI Build 工作流(.github/workflows/rust-cli.yml)会为多平台构建 ov 二进制并发布 npm 包:
- 平台包:
@openviking/cli-linux-x64、@openviking/cli-linux-arm64、@openviking/cli-darwin-x64、@openviking/cli-darwin-arm64、@openviking/cli-win32-x64; - wrapper 包:
@openviking/cli(源码位于 npm/cli)。
从工作流实现可以看到几个工程细节:
- Linux 侧通过
cargo-zigbuild交叉编译 musl 目标(x86_64-unknown-linux-musl/aarch64-unknown-linux-musl),产物为完全静态的 musl 二进制,可运行在 glibc 较老的发行版上; - 版本注入:工作流用
sed把 tag 中的版本写入crates/ov_cli/Cargo.toml中占位的version = "0.0.0"(见 rust-cli.yml#L114-L122),npm 平台包与 wrapper 包的版本号同样来自 tag;非 tag 触发(如crates/**变更的 CI 构建)则以0.0.0-dev命名且不会进入 npm 发布 job; - 幂等保护:
npm-publishjob 逐个npm view检查,若某平台包或 wrapper 包同版本已存在于 npm,则打印“already published”并跳过,避免重复发布报错。
OpenClaw / ClawHub 插件发布
OpenClaw 插件通过 OpenViking OpenClaw plugin release 工作流手动发布(见 .github/workflows/clawhub-dev-release.yml)。输入参数包括:
version:可选;为空时由工作流按日期自动生成YYYY.M.D/YYYY.M.D-N/YYYY.M.D-dev.N;channel:auto、dev或latest;auto会根据仓库是否为配置的上游仓库决定发布到 latest 还是 dev 通道;package_ref:指定要打包的 Git ref(默认main),便于从其他分支工作流发布 main 上的插件代码;changelog:本次插件发布说明;publish_clawhub/publish_npm:分别控制是否发布 ClawHub 资产与 npm 上的@openviking/openclaw-plugin。
工作流先解析 channel 与 version(guard job),再打包 examples/openclaw-plugin,随后分别发布 ClawHub 兼容的 zip 资产与 npm packed tarball。工作流还设置了 concurrency 组(openclaw-plugin-release,不取消进行中的任务),避免连续两次合并自动触发的版本解析相互竞争。
推荐做法:正式渠道使用 latest 或 auto;开发验证使用 dev;手动指定 version 时确保其符合所选 channel 的格式要求。
其他发布流程
- TypeScript SDK 发布(
.github/workflows/typescript-sdk-release.yml):由推送typescript-sdk@X.Y.Ztag 触发或手动触发,发布@openviking/sdk到 npm; - OpenCode 插件发布(
.github/workflows/opencode-plugin-release.yml):当main分支上触及examples/opencode-plugin/**的 push 时自动运行,也可手动触发;发布@openviking/opencode-plugin到 npm,并跳过已存在的版本; - Controlplane MCP 发布(
.github/workflows/controlplane-mcp-release.yml):仅手动触发,发布mcp-server-openviking-controlplane,包含ov-cpCLI。
VikingBot 发布说明
VikingBot 不再作为推荐的独立 PyPI 包发版路径维护,现行分发方式是随主包发布:
- Python 安装入口:
pip install "openviking[bot]"; - 源码开发入口:
uv pip install -e ".[bot]"; - 官方 Docker 镜像默认已包含 VikingBot,可通过
--without-bot或OPENVIKING_WITH_BOT=0关闭。
两条历史脉络需要注意:
- 根仓库原有的
First Release to PyPI工作流已被删除。当前bot/目录不包含独立的pyproject.toml、setup.py或setup.cfg,因此不能从本仓库作为独立 Python 包发布;它现在是根 pyproject.toml 打包范围的一部分(where = [".", "bot"],include = ["openviking*", "vikingbot*"],见 pyproject.toml#L209-L212)。 - bot/.github/workflows/release.yml 位于
bot子目录下,应视为历史 bot 子项目或拆分仓库的发布参考,而不是根仓库当前可直接触发的 GitHub Actions 工作流。若要恢复独立vikingbot包,需要先补齐bot/下的独立 Python 包元数据、版本策略与发布凭证策略。
发版前检查清单
发版前建议逐项确认:
- 待发布改动已合入目标分支;
- CI / PR 检查已通过;
- 版本号未在 PyPI、npm 或 Docker registry 中发布过;
- tag 命名符合对应产物约定(
vX.Y.Z/python-sdk@X.Y.Z/typescript-sdk@X.Y.Z/cli@X.Y.Z/ ClawHub 日期版本); - Python 依赖、构建配置与 README 已同步更新;
- Docker Hub、PyPI/TestPyPI、TOS、npm、ClawHub 所需 secrets 或 trusted publishing 配置可用(PyPI 通道依赖
id-tokenOIDC,Docker Hub 依赖DOCKERHUB_USERNAME等 secrets,TOS 通道依赖五个TOS_*secrets); - Release notes 已准备好,说明破坏性变更、迁移步骤与重要修复。
发版后验证清单
发版后建议验证:
- PyPI / TestPyPI 上的包版本与 tag 一致;
pip install openviking==<version>或pip install openviking-sdk==<version>可成功安装;- Docker registry 中存在版本 tag 与预期的
latest/maintag; - 多架构 Docker manifest 可正常拉取(
03. Release的verify-dockerjob 已自动断言版本 tag 与latest指向同一 digest); - TOS 版本化路径与稳定路径可访问;
- npm 上存在对应 CLI 平台包与 wrapper 包(
@openviking/cli-linux-x64等 +@openviking/cli); - ClawHub 插件 channel 与 version 符合预期。
故障处理与补发原则
- PyPI 和 npm 版本一般不可覆盖:如果包内容有误,应发布新版本。两个工作流都通过
skip-existing行为体现这一原则——重复发布只会跳过而不是覆盖; - Docker
latest、main与手动指定 tag 可通过镜像补发工作流重建,但应保持已发布版本 tag 的可追溯性; - TOS 版本化路径应视为不可变资产;稳定路径可通过手动工作流(
update_latest)覆盖; - 构建成功但发布失败时,优先使用
_Publish Distribution补发工作流或手动 dispatch(传入build_run_id),而不是用不同内容重建同名 tag; - tag 命名错误时,只有在该 tag 尚未触发不可逆发布的前提下,才删除错误 tag 并重新创建正确 tag。
掌握以上约定后,发版人员可以按“选对 tag 命名空间 → 触发对应工作流 → 用发布后清单逐项验证”的固定路径完成 OpenViking 任意一条发布通道,并在失败时依据补发原则快速恢复,而不会造成版本覆盖或口径混乱。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00