# AgentTeam Versioning 规范

> Canonical path: `specs/versioning/versioning.md`
> Scope: first-party server / Desktop application / daemon 版本轨道、产品内版本语义、发布对齐规则

## 1. 目标

本规范定义 AgentTeam 当前的一方版本语义，解决三个问题：

- AgentTeam server、AgentTeam Desktop application 与 `agentteam daemon` 用什么版本轨道表达“当前一方发布版本”
- 产品内哪些 UI / API / diagnostics 可以消费这个版本信息

本规范的目标不是引入复杂发版系统，而是先把版本语义收敛成单一 source of truth，避免产品状态继续漂移。

## 2. 术语

### 2.1 first-party version

AgentTeam 自己维护的一方版本。

它描述的是 AgentTeam 产品自己的发布轨道，而不是外部包的最新版本。

当前 first-party version 适用于：

- AgentTeam server
- macOS / Windows AgentTeam Desktop application
- 应用内的 `agentteam daemon` Go sidecar
- Linux headless `agentteam daemon` / CLI

### 2.2 server version

某个 AgentTeam server 构建/发布所属的一方版本。

### 2.3 daemon version

某个 `agentteam daemon` 二进制上报给 server 的一方版本。

### 2.4 Desktop application version

macOS / Windows 上整个 Electron application 的一方版本。它覆盖 Electron
main/preload、renderer、Go sidecar 和随应用发布的 `builtin` OpenCode runtime；
这些组件不是独立的用户可升级产品。

## 3. 当前产品立场

### 3.1 一方版本来源

AgentTeam 不在源码中保留固定的一方版本号基线。

本地当前版本必须来自二进制构建元数据：

- `agentteam daemon` 通过 build-time `-ldflags` 注入当前 binary 版本
- macOS / Windows Electron package 的 `extraMetadata.version`、其中的 Go
  sidecar 与 staging manifest 使用同一个显式 `AGENTTEAM_DESKTOP_VERSION`
- server 通过 build-time `-ldflags` 注入当前 server binary 版本
- daemon/server dev build 默认从 `git describe --tags --always --dirty` 生成版本并注入
- 本地 Electron package 未显式设置 `AGENTTEAM_DESKTOP_VERSION` 时，从当前 checkout
  最近可达的 Git tag 读取版本并去掉前导 `v`，再统一注入 package、sidecar 与
  staging manifest；没有可用 tag 时构建失败

如果构建环境无法提供版本，runtime surface 可以显示 unknown 或空值，但不能编造一个 semver 作为 fallback。

远端最新版本必须来自 release manifest 或显式环境覆盖。它只用于推荐升级目标，不能作为本地当前版本。

### 3.2 产品内保留 first-party upgrade reminder

在当前阶段，AgentTeam 产品可以继续暴露 daemon upgrade reminder，但该提醒必须表达 AgentTeam 自己的一方版本语义。

因此：

- UI 可以继续显示 `(update available)`
- machine attention 可以继续把 “daemon 版本落后于当前 first-party recommended daemon version” 作为 attention 来源
- 产品可以继续把某个 daemon 标记为 “outdated”，但这个判断只能基于 AgentTeam 自己的一方 daemon version contract

## 4. 产品行为规则

### 4.1 一方版本轨道优先

凡是产品内出现 “当前版本 / 当前发布版本 / 当前建议版本” 的地方，都必须首先基于 AgentTeam 自己的一方版本轨道定义。

### 4.2 daemon upgrade reminder 必须满足这些约束

如果产品显示 daemon upgrade reminder，必须同时满足：

1. server 有明确的一方 recommended daemon version 来源
2. 该 version 明确对应 first-party `agentteam daemon` 这条 daemon family
3. 推荐版本来源必须是 release manifest 或显式环境覆盖，不能是源码中的固定 fallback
4. 提醒语义来自 AgentTeam 自己的版本 contract

## 5. 发布对齐规则

### 5.1 一个 first-party release 只对应一个 canonical version

每次一方发布都应先确定一个唯一版本号 `vX.Y.Z`。

该版本号是本次发布的 canonical version。

### 5.2 该版本至少要对齐这些 surface

每次发布时，至少要同时审查并对齐：

- server 发布版本语义
- server 暴露的 first-party recommended daemon version 来源
- macOS / Windows Electron application version 与 updater metadata
- Electron staging manifest 记录的 product version
- `desktop/internal/version/version.go` 的 build-time version
- `desktop/internal/wire/protocol.go` 上报给 server 的 daemon version 形状
- Linux daemon/CLI archive 中的 binary version
- 随 first-party artifact 发布的 `builtin` OpenCode runtime version/catalog
- docs 中显式写死的一方版本
- 相关测试中的版本期望

### 5.3 平台升级边界

- macOS / Windows 由 Electron updater 安装完整签名应用更新。Electron、
  renderer、Go sidecar 和 managed `builtin` runtime 必须作为一个版本单元
  一起替换，不能由 Go self-updater 单独替换 sidecar。
- Electron updater 读取 `agentteam/releases/desktop/latest-mac.yml` 或
  `agentteam/releases/desktop/latest.yml` 这两个可变 channel feed；每个
  每个 `product=agentteam-desktop` 的 `agentteam/releases/desktop/vX.Y.Z.json` manifest 必须引用对应的
  `agentteam/releases/desktop/vX.Y.Z/latest-*.yml` 不可变副本，不能引用会被后续版本覆盖
  的根 feed。
- `agentteam/releases/desktop/index.json` 只索引版本；每个 Desktop 版本 manifest
  必须列齐 Linux amd64/arm64 tar、macOS arm64/x64 DMG、Windows arm64/x64
  EXE 六个用户包。Linux 资产仍指向 daemon checksum，App 资产指向 Desktop
  checksum；下载页不得再跨两个版本 manifest 运行时拼接。
- `index.json` 的新条目必须显式标记 `product=agentteam-desktop`。迁移前已经发布的
  `agentteam-daemon` 历史条目保留原 product，并继续引用原不可变version manifest；
  root `product` 只描述当前canonical Desktop catalog，不能用于篡改历史条目身份。
- Linux 不发布 Electron application；headless 安装继续使用 Go
  `agentteam upgrade`，但推荐版本和Linux资产也来自统一的 Desktop release
  manifest。旧 `agentteam/releases/daemon` feed只作为已安装Linux客户端迁移到
  统一catalog的有界fallback，不是新的release source of truth。完成一次
  daemon→Desktop→Desktop 两跳升级验证，并且最低支持版本已越过bridge版本后，
  必须删除daemon fallback和ci-ops daemon manifest writer。
- external `opencode`、Claude、Codex、Kimi 不属于 first-party application
  version，也不由上述任一 updater 管理。

### 5.4 release 变更必须是显式的

版本升级不能隐式发生在：

- 某个测试 fixture 自己变化
- 某个 UI helper 的比较逻辑里

版本升级必须以显式代码 / 文档变更表达。

### 5.5 Daemon 本地持久化格式必须支持发布回滚

First-party Desktop/daemon 的行为回滚不得删除已发布格式的读取分支、复用其 format ID，或只把 writer 常量改回旧值。本地持久化格式必须分别声明 active write format 和 supported read formats。自动回滚目标必须能读取当前 writer 已经可能落盘的格式；不能读取时，该版本不得作为自动回滚目标。Runtime delivery ownership 的具体规则见 [Runtime Delivery Ownership 格式兼容](../daemon/runtime-state-compatibility.md)。

### 5.6 版本比较与展示必须先归一化

daemon 上报给 server 的版本字符串允许携带一方 family 前缀，例如 `agentteam/v1.1.3`。

因此：

- UI / diagnostics 在比较版本新旧前，必须先归一化 family 前缀与可选 `v` 前缀
- 产品展示可以继续显示 `v1.1.3` 这种人类友好格式，但不能把原始 wire 值直接拼接成 `vagentteam/...`

## 6. 与 `specs/daemon/daemon.md` 的关系

两份规范分工如下：

- `specs/daemon/daemon.md`
  - 定义 daemon-facing contract
- `specs/versioning/versioning.md`
  - 定义 AgentTeam 自己的一方版本轨道
  - 定义产品内版本语义
  - 定义发布对齐规则

如果问题是“AgentTeam 自己当前版本是什么、产品里怎么用版本信息”，看本文。

## 7. 非目标

本文当前不要求：

- 立即实现完整 changelog / release-note 系统
- 立即给 server 增加公开版本 API
- 立即实现复杂的多轨 daemon 升级策略
- 为 Electron application 内的 sidecar 或 managed runtime 提供独立升级轨道

## 8. 变更控制

任何未来涉及以下内容的改动，都必须同时审查：

- 本文
- `SPECS.md`
- `specs/daemon/daemon.md`
- `README.md`
- `desktop/README.md`
- 相关 archive / upgrade 迁移材料（如存在）
- 相关 UI / diagnostics / tests / release 文案
