baa-conductor


baa-conductor / docs / runtime
im_wower  ·  2026-03-29

launchd.md

  1# launchd
  2
  3当前只记录 `mini` 单节点的 launchd 管理方式。
  4
  5## 当前目标状态
  6
  7- `conductor``launchd` 托管,并承载 canonical local API `http://100.71.210.78:4317`
  8- `codexd``launchd` 托管,并作为正式独立 Codex 运行面监听 `http://127.0.0.1:4319`
  9- `status-api` 是显式 opt-in 的本地只读观察面,默认从 `BAA_CONDUCTOR_LOCAL_API` 读取 `/v1/system/state`
 10- 工作目录固定到 `/Users/george/code/baa-conductor`
 11- 通过仓库内脚本统一安装、启动、停止、重启与验证
 12
 13## 一键安装到当前仓库路径
 14
 15```bash
 16./scripts/runtime/install-mini.sh
 17```
 18
 19这个脚本会顺序执行:
 20
 211. 初始化 runtime 目录
 222. 构建仓库
 233. 渲染并安装默认 `conductor` / `codexd` 的 LaunchAgents
 244. 重启 launchd 服务
 255. 跑静态检查和节点检查
 26
 27如果还要把本地状态观察面一起装上,用:
 28
 29```bash
 30./scripts/runtime/install-mini.sh --with-status-api
 31```
 32
 33默认会把共享 token 收口到:
 34
 35- `~/.config/baa-conductor/shared-token.txt`
 36
 37如果你只是想先生成一个新的本地 token,再安装运行面,可以直接执行:
 38
 39```bash
 40./scripts/runtime/generate-shared-token.sh
 41```
 42
 43默认会生成一个 32-byte hex token,并写入上面的固定路径。
 44
 45如果这个文件不存在,脚本会尝试从:
 46
 47- `~/.config/baa-conductor/runtime-secrets.env`
 48
 49里提取 `BAA_SHARED_TOKEN` 并生成它;只有这个默认 env 文件不存在时,才会回退读取 legacy 的 `control-api-worker.secrets.env` 迁移前文件名。
 50
 51说明:
 52
 53- `codexd` 独立安装时不需要共享 token
 54- 如果 `runtime-secrets.env` 里同时提供 `D1_ACCOUNT_ID`、`D1_DATABASE_ID`、`CLOUDFLARE_API_TOKEN`,安装脚本会把它们写进 `conductor` LaunchAgent,从而启用 D1 sync worker
 55- `status-api` 默认真相源是 `BAA_CONDUCTOR_LOCAL_API`
 56- `--public-api-base` 是 canonical 参数名;`--control-api-base` 仍保留为 legacy 兼容别名,但都只影响 `conductor` 安装副本
 57- `--codexd-local-api-base` 会同时写给 `codexd``conductor`
 58- `codexd` 正式运行面只写入 `app-server` 会话链路所需默认值
 59- `codexd` 正式服务面只保留 `/healthz`、`/v1/codexd/status`、`/v1/codexd/sessions`、`/v1/codexd/turn`、`/v1/codexd/events`
 60- install / reload / status / check 脚本都只验这条会话链路
 61
 62## 日常管理
 63
 64查看状态:
 65
 66```bash
 67./scripts/runtime/status-launchd.sh
 68```
 69
 70停止:
 71
 72```bash
 73./scripts/runtime/stop-launchd.sh
 74```
 75
 76启动:
 77
 78```bash
 79./scripts/runtime/start-launchd.sh
 80```
 81
 82重启:
 83
 84```bash
 85./scripts/runtime/restart-launchd.sh
 86```
 87
 88这些命令默认同时操作 `conductor`、`codexd`。需要单独管理可选观察面时,再显式加 `--service status-api` 89
 90例如只重启 `codexd` 91
 92```bash
 93./scripts/runtime/restart-launchd.sh --service codexd
 94```
 95
 96当前运维观察口径:
 97
 98- `status-launchd.sh` 会展示 `conductor /v1/codex`,确认代理是否已经指向独立 `codexd`
 99- `status-launchd.sh``codexd` 只展示 `/healthz``/v1/codexd/status`
100- `reload-launchd.sh` 只等待 `codexd /healthz` 恢复
101- `check-node.sh` 要求 `conductor /v1/codex`、`codexd /healthz` 和 `/v1/codexd/status` 返回正常
102- 额外会话验收统一走 `./scripts/runtime/codexd-e2e-smoke.sh`
103
104## 渲染安装副本
105
106默认 mini 安装副本示例:
107
108```bash
109./scripts/runtime/install-launchd.sh \
110  --repo-dir /Users/george/code/baa-conductor \
111  --node mini \
112  --service conductor \
113  --service codexd \
114  --install-dir /Users/george/Library/LaunchAgents \
115  --shared-token-file /Users/george/.config/baa-conductor/shared-token.txt \
116  --d1-secrets-env /Users/george/.config/baa-conductor/runtime-secrets.env \
117  --local-api-base http://100.71.210.78:4317 \
118  --local-api-allowed-hosts 100.71.210.78 \
119  --codexd-local-api-base http://127.0.0.1:4319
120```
121
122默认 mini 安装不需要显式传 `--public-api-base`;只有 `conductor` 的 upstream/public API base 不是 `https://conductor.makefile.so` 时才需要覆盖。`--control-api-base` 仍可作为 legacy 兼容别名使用;如果新旧参数同时出现,`--public-api-base` 优先。脚本现在会把 `BAA_CONDUCTOR_PUBLIC_API_BASE` 和 legacy `BAA_CONTROL_API_BASE` 一起写给 `conductor` 安装副本;`status-api` 实际默认仍然优先读 `--local-api-base http://100.71.210.78:4317`123
124如果需要本地状态观察面,再显式安装:
125
126```bash
127./scripts/runtime/install-launchd.sh \
128  --repo-dir /Users/george/code/baa-conductor \
129  --node mini \
130  --service status-api \
131  --install-dir /Users/george/Library/LaunchAgents \
132  --status-api-host 100.71.210.78
133```
134
135单独安装 `codexd`136
137```bash
138./scripts/runtime/install-launchd.sh \
139  --repo-dir /Users/george/code/baa-conductor \
140  --node mini \
141  --service codexd \
142  --install-dir /Users/george/Library/LaunchAgents \
143  --codexd-local-api-base http://127.0.0.1:4319
144```
145
146`codexd` 默认写入这些正式运行值:
147
148- `BAA_CODEXD_MODE=app-server`
149- `BAA_CODEXD_LOCAL_API_BASE=http://127.0.0.1:4319`
150- `BAA_CODEXD_EVENT_STREAM_PATH=/v1/codexd/events`
151- `BAA_CODEXD_SERVER_STRATEGY=spawn`
152- `BAA_CODEXD_SERVER_COMMAND=codex`
153- `BAA_CODEXD_SERVER_ARGS=app-server`
154- `BAA_CODEXD_SERVER_CWD=/Users/george/code/baa-conductor`
155- `BAA_CODEXD_SERVER_ENDPOINT=stdio://codex-app-server`
156
157`conductor` 的安装副本也必须拿到:
158
159- `BAA_CODEXD_LOCAL_API_BASE=http://127.0.0.1:4319`
160
161否则 `conductor` 虽然会正常监听 `4317`,但 `/v1/codex*` 会返回 `503 codexd_not_configured`162
163如果要让 `conductor` 带上 D1 远端同步配置,确保当前 shell 或 `--d1-secrets-env` 指向的 env 文件里完整提供:
164
165- `D1_ACCOUNT_ID`
166- `D1_DATABASE_ID`
167- `CLOUDFLARE_API_TOKEN`
168
169这三个值必须一起存在;只给其中一部分时,安装脚本会直接失败,避免生成“看起来装好了、实际上 sync worker 不会启动”的半配置副本。
170
171## reload 行为
172
173`restart-launchd.sh` / `reload-launchd.sh` 不只看 `launchctl` 返回码,还会等待已选服务的 `/healthz` 恢复:
174
175- `conductor`: 读取 `BAA_CONDUCTOR_LOCAL_API`
176- `codexd`: 读取 `BAA_CODEXD_LOCAL_API_BASE`
177- `status-api`: 只有显式选择时才读取 `BAA_STATUS_API_HOST` 并按默认端口 `4318` 探活
178
179mini 正确安装后,建议追加一轮代理验证:
180
181```bash
182curl -fsSL http://127.0.0.1:4319/v1/codexd/status
183curl -fsSL http://100.71.210.78:4317/v1/codex
184curl -fsSL http://100.71.210.78:4317/v1/codex/sessions
185```
186
187如果服务处于 loaded 但未提供 HTTP,脚本会自动再执行一次:
188
189```bash
190launchctl kickstart -k gui/$(id -u)/<label>
191```
192
193如果二次 kickstart 后仍未恢复,脚本会返回非零,并输出:
194
195- 最后一次 health probe 的 curl 结果
196- `launchctl print` 诊断
197- 对应服务 stdout/stderr 日志尾部
198- 手工兜底命令提示
199
200## 职责边界
201
202- `launchd` 负责开机自启动和硬重启
203- `conductor-daemon` 负责发现 `codexd` 不可用并重连
204- `codexd` 负责发现 Codex child 不可用并重建子进程
205- 不做 `conductor-daemon` 直接 spawn `codexd`
206- 不做 `codexd` 直接 spawn `conductor-daemon`