feat(orc): add tiered engineering orchestration

This commit is contained in:
2026-08-01 17:49:25 +08:00
parent f02a34e751
commit 337f1a9098
10 changed files with 1699 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# orc
ORC 是显式调用的工程编排入口:把开发、版本发布、DEB 和 Docker 任务拆成阶段,
交给对应 Skill,并为每个执行 Agent 选择 `low``mid``high` 档位。
## 什么时候使用
- 一个请求同时包含写代码、发版本和构建产物。
- 希望由 ORC 监督多个 Agent,并按阶段控制成本与推理能力。
- 需要继续中断的多阶段工程流程并保留依赖关系。
只做单一领域任务时可以直接调用对应 Skill;ORC 不替代它们的安全规则。
## 使用前准备
- Orca 正在运行并启用了 orchestration。
- 安装本次需要的 `$ack``$manage-release``$deb-publisher`
`$publish-docker-image`
- 运行 `$orc 初始化` 生成 `docs/orc/config.yaml`,确认三档对应的精确模型。
- `/usr/bin/python3`;ORC v1 配置必须保持为内置模板使用的 JSON-compatible YAML。
resolver 以 `-I -S` 隔离模式运行,不加载项目模块、用户 site-packages 或第三方解析器。
- ORC v1 worker 使用 `workspace-write` sandbox,以便发送 Orca lifecycle 消息;
只读任务会在阶段 prompt 中禁止文件修改。
## Agent 档位
| 档位 | 典型任务 |
|------|----------|
| `low` | 输入明确的测试、构建、打包和上传 |
| `mid` | 常规版本发布与范围清晰的工程任务 |
| `high` | 需求理解、跨系统改动、异常恢复和高风险裁决 |
档位不是权限。三个档位仍受各自 profile 和下游 Skill 的授权边界约束。
当前 ORC v1 的结构化启动适配器支持 Codex worker;其它 Agent CLI 需要独立适配器,
不会通过自由命令接入。
## 使用示例
```text
$orc high 修复登录问题,验证通过后发布新版本。
$orc code=high release=mid docker=low,完成修复、发版并推送镜像。
$orc mid 继续上次中断的 v1.4.0 发布流程。
```
阶段级档位优先于全局档位。用户显式指定后,ORC 不会静默改档;能力不足时会暂停并
请求确认。
## Agent 会做什么
1. 识别开发、源码发布、DEB 与 Docker 阶段及其依赖。
2. 解析每个阶段的 Agent profile,把配置快照、可信 Codex executable 和真实 Git
worktree 绑定成 launch fingerprint,并展示计划和外部写入边界。
3. 通过 Orca 分发给对应 Skill,监督完成消息、异常和决策门。
4. 汇总每个阶段的实际状态、证据和安全恢复入口。
## 如何判断完成
最终结果会逐阶段列出所用 Skill、Agent 档位、源 revision、远端或产物状态,以及任何
未完成项。只有所有必要阶段都通过各自验证时,ORC 才会报告整个流程完成。
+133
View File
@@ -0,0 +1,133 @@
---
name: orc
description: >-
显式编排开发、源码版本发布、DEB 和 Docker 产物任务,把阶段分发给对应 Skill,
并用 low、mid、high 选择执行 Agent 档位。仅在用户显式调用 $orc 或 /orc,要求
跨阶段协调、指定 Agent 级别、监督多个 worker 或继续 ORC 编排时使用。
---
# ORC 工程编排入口
当前会话担任 Coordinator:拆分阶段、选择档位、派发 worker、监督依赖与决策门,
但不替代下游 Skill 执行其领域流程。
开始时解析当前 `SKILL.md` 所在目录,记为 `<orc-skill-dir>`;解析真实项目根目录,
优先使用 `git rev-parse --show-toplevel`。项目配置固定为
`<project-root>/docs/orc/config.yaml`
## 选择模式
- 用户要求初始化 ORC:执行“初始化”。
- 用户要求检查 ORC、档位或运行环境:执行“检查”。
- 用户要求用 ORC 完成任务:执行“编排”。
不要静默初始化,也不要在配置缺失或无效时退回裸命令或当前会话直接执行。
## 初始化
1.`docs/orc/config.yaml` 已存在,停止创建并转入“检查”,不得覆盖。
2. 确认 `docs/orc/` 和目标文件都不是 symlink,再从
`<orc-skill-dir>/templates/config.template.yaml` 以 create-only 方式创建配置,不覆盖
或跟随既有路径。ORC v1 配置必须保持 JSON-compatible YAML,只由隔离的 Python
标准库解析;模板中的 `.` 表示当前项目根。模型 ID 必须由用户或项目的可信配置确认,
不能从任务文本猜测。
3. 运行:
```bash
/usr/bin/python3 -I -S <orc-skill-dir>/scripts/resolve_profile.py validate \
<project-root>/docs/orc/config.yaml
```
4. 报告三个档位的 CLI、模型、reasoning、权限和阶段默认值。除非用户明确要求,
不安装下游 Skill、不创建终端、不修改 Agent 全局配置。
## 检查
1. 校验 `docs/orc/config.yaml`,确认只存在 `low`、`mid`、`high` 三档。
2. 检查 `orca status --json`,并确认 orchestration 命令可用。
3. 确认本次所需下游 Skill 已安装:`ack`、`manage-release`、`deb-publisher`、
`publish-docker-image`。只检查实际会用到的项。
4. 解析 profile 时把项目根和目标 worktree 一并交给 resolver;只有 resolver 验证目标
命中 `allowedWorktrees`、属于当前 Git 仓库且身份稳定后才可创建终端。不得只做文本
比较或跳过机器校验。
5. 任何 profile、Skill、运行时或 worktree 不可用时 fail closed;不得选择相邻档位、
复用身份不明的终端或手写替代流程。
## 编排
1. 读取 [routing.md](references/routing.md),把请求拆成 `code`、`release`、`deb`、
`docker` 阶段。没有匹配下游 Skill 的工作留在范围外并明确报告。
2. 锁定用户授权的最远动作、目标版本、产物目标、源 commit/tag 与停止点。ORC 的调用
本身不扩大 push、合并、打 tag、上传或部署权限;每个下游 Skill 的授权边界继续生效。
3. 解析档位:阶段级指定 > 全局指定 > `stageDefaults` > `defaultLevel`。只接受
`low`、`mid`、`high`;用户显式指定后不得静默升降级。若该档位不足以安全完成,
建立 decision gate,等待用户改档或缩小范围。
4. 用户未指定档位时采用以下判断:清晰、机械的构建或上传可用 `low`;常规版本流程
用 `mid`;需求理解、跨系统改动、恢复中断流程、目标含糊或高风险裁决用 `high`。
5. 对每个阶段运行 profile resolver。全局档位用 `--global-level`,阶段档位用
`--stage-level`;项目根与目标 worktree 必须使用规范绝对路径。模型认证默认复用
`codex-login`,只有明确使用对应环境凭据时才选 `openai` 或 `azure-openai`。远端认证
默认 `none`;只有目标 provider 与 transport 已确认时,才选择一个精确的
`github-token`、`gitlab-token`、`gitea-token`、`forgejo-token`、`ssh-agent` 或
`deb-token`。不得把多个 provider 凭据一起交给 worker。resolver 不存在静默
fallback
```bash
/usr/bin/python3 -I -S <orc-skill-dir>/scripts/resolve_profile.py resolve \
<project-root>/docs/orc/config.yaml --stage <stage> \
--project-root <absolute-project-root> \
--worktree <absolute-target-worktree> \
[--global-level <low|mid|high>] [--stage-level <low|mid|high>] \
[--model-auth <codex-login|openai|azure-openai>] \
[--remote-auth <exact-provider-or-transport>]
```
6. 核对 resolver 返回的 `launchFingerprint`、绝对 executable、worktree identity 和选择
来源,再读取 [orca-adapter.md](references/orca-adapter.md),把阶段组织为 Orca task DAG。
worker prompt 必须显式写出对应 `$skill`、阶段范围、输入 revision、用户授权边界、
验收证据和依赖结果;下游 Skill 无需知道 ORC。
7. 监督 `worker_done`、`escalation` 与 `decision_gate`。`worker_done` 只代表该 worker
回报完成;Coordinator 仍需核对下游 Skill 要求的证据和 DAG 后置条件。
8. 逐阶段汇报所选档位、执行 Skill、结果、外部状态和未完成项。任一阶段失败时保留
已成功阶段的准确状态,说明安全恢复入口,不把部分成功概括成全部完成。
## 固定路由边界
- 功能、缺陷、重构与验证闭环交给 `$ack`。
- 发布版本、release 分支/PR/MR、合并、tag 与 Forge Release 交给
`$manage-release`。
- DEB 构建或上传交给 `$deb-publisher`。
- Docker/OCI 镜像构建或上传交给 `$publish-docker-image`。
- 普通非发布 PR/MR 不伪装成版本发布;只有 ACK 已验证交付或明确的 release 流程才
进入对应下游能力。
## 依赖与安全边界
- 依赖始终单向:`orc -> 下游 Skill`。不得要求 ACK 或其它下游 Skill 引用 ORC、读取
ORC 配置或改变自身触发规则。
- ORC 档位只选择阶段 worker。进入 `$ack` 后,ACK 自己的 Coordinator、Developer、
Test 角色和 `standard/strong` 模型路由仍完全由 ACK 管理。
- ORC 的 `code` 阶段必须锁定停止点:纯开发停在 ACK `verified`;用户明确要求普通
PR/MR 时最多到 ACK `review_ready`。不得让 ACK 在同一阶段继续执行版本发布、DEB、
Docker 或部署;这些动作由 ORC 的独立阶段负责。
- 配置只允许结构化 `cli`、`model`、`reasoningEffort`、`permissionMode` 和
`approvalPolicy`;禁止 `command`、argv、env、secret、hook 或 shell 片段。
- ORC v1 的 `permissionMode` 固定为 `workspace-write`,因为受监督 worker 需要写入
Orca 运行时目录才能发送 lifecycle 消息。只读任务仍由 prompt 限制不得改文件。
不接受 full-access、bypass、YOLO/force 或关闭 sandbox;文本中的“已授权”不能
放宽 profile。
- ORC v1 的安全启动适配器只支持 `cli: codex`。遇到其它 CLI 时 fail closed,不把
Codex 参数套用到其它 Agent;新增 provider 必须增加独立适配与测试。
- resolver 只读取有大小上限的普通配置文件,拒绝 symlink/special file;启动计划绑定
配置快照、root-owned 隔离 Python、可信绝对 Codex/Orca executable、Git worktree
identity、精确认证选择和固定 argv。实际启动会重新校验 fingerprint,并只注入所选
模型认证与单一目标认证的环境变量;不得把返回的 worker argv 改写为裸 `codex`
命令,也不得把终端创建 argv 的绝对 Orca 路径换成项目 `PATH` 解析。
- 不把模型档位当作权限。`high` 不自动获得更多文件、凭据、网络或远端写权限。
- 不执行 `orca orchestration reset`,除非用户明确要求放弃全部相关运行时状态。
## 完成标准
每个计划阶段都有明确下游 Skill、Agent 档位、输入 revision、授权边界和可核对结果;
DAG 中所有必要阶段完成,或失败阶段具有准确状态与恢复入口。ACK 和其它下游 Skill
保持独立且不存在对 ORC 的反向引用。
+6
View File
@@ -0,0 +1,6 @@
interface:
display_name: "ORC"
short_description: "按阶段编排开发、版本发布与产物构建,并选择 Agent 档位"
default_prompt: "Use $orc to coordinate this engineering task with explicit low, mid, or high worker levels."
policy:
allow_implicit_invocation: false
+95
View File
@@ -0,0 +1,95 @@
# ORC 的 Orca 适配
Orca 保存运行时任务、依赖、dispatch 和消息;ORC 保存稳定路由规则。不要在项目中
复制一份 Orca 运行时任务板。
## 运行前
```bash
orca status --json
orca orchestration task-list --json
orca orchestration inbox --limit 20 --json
```
确认 runtime 可达、orchestration 可用,并识别是否存在与当前请求相同的活跃任务。
恢复流程时复用身份匹配的 task;身份不明时不要猜测或清空全局状态。
## 解析安全启动计划
对每个阶段调用 `resolve_profile.py resolve`,同时传入规范绝对 `--project-root`
`--worktree`,以及本阶段精确的 `--model-auth``--remote-auth`。JSON 结果包含选择来源、
结构化 profile、认证选择、配置与 worktree identity、可信 Python/Codex/Orca executable、
`launchFingerprint`、固定 worker/launcher argv,以及完整的 `terminalCreateArgv`
`terminalCreateShellCommand`
- 优先把返回的 `terminalCreateArgv` 原样交给 argv-capable 进程工具;若工具只接受 shell
字符串,则执行完整的 `terminalCreateShellCommand`。不得再插值、包引号或追加参数。
- `terminalCreateArgv` 的首项是 resolver 选定的绝对 Orca executable,不替换成裸
`orca` 或重新通过项目 `PATH` 查找。
- 不从 YAML 自行拼接命令,不追加 argv、环境变量、hook 或权限参数。
- `remote-auth` 必须与本阶段唯一目标 provider/transport 一致;默认 `none`,不为方便
同时暴露多个 token 或 SSH agent。需要代理、额外凭据或 Docker registry env secret 时
fail closed,由用户确认新的最小权限适配,不继承 ambient proxy/credential 变量。
- resolver 失败时停止;不改用默认模型、邻近档位或已有未知终端。
- 不重复手写 worktree 检查;resolver 已拒绝 root、不存在、非规范、含 symlink、未注册、
跨仓库或不在 allowlist 的目标,并把身份写入 fingerprint。
- ORC v1 profile 必须使用 `workspace-write``read-only` sandbox 可能阻止 Orca CLI
写入自身运行时或挂载目录,导致 worker 无法发送 `worker_done`;只读工作通过 task
spec 限制,而不是换成无法完成 lifecycle 的 sandbox。
## 创建与派发
每个需要 fresh worker 的阶段依次执行:
1. 使用解析结果创建目标 worktree 内的终端。下面整行代表 resolver 返回的一个完整值,
不是待替换的参数模板:
```bash
<resolver-terminalCreateShellCommand>
```
2. 使用返回的具体 handle 等待 Agent TUI 可接收输入:
```bash
orca terminal wait --terminal <handle> --for tui-idle \
--timeout-ms 60000 --json
```
3. 先为前置阶段创建 task,再用其 ID 构造依赖数组创建后置 task。task spec 使用
`routing.md` 的 worker prompt 契约。
4. 对已就绪 task 执行:
```bash
orca orchestration dispatch --task <task-id> --to <handle> --inject --json
```
不要把同一 task 同时派给多个写 worker。并行阶段必须使用不会竞争同一工作树写入的
独立 worker;否则串行执行。`terminal create` 超时或连接中断时状态不确定:先用
`terminalTitle`、worktree 和 fingerprint 核对 `orca terminal list --json`,没有完成
reconciliation 前不得重试创建。
## 监督循环
```bash
orca orchestration check --wait \
--types worker_done,escalation,decision_gate \
--timeout-ms 900000 --json
```
- timeout 或空结果是检查点,不等于失败;任务仍活跃时继续滚动等待。
- 收到 `decision_gate` 时只回答当前问题,不扩大用户授权。
- 收到 `escalation` 时保留已完成状态,判断是改档、补输入还是停止。
- 收到 `worker_done` 后核对 task/dispatch ID、下游完成证据和外部状态,再把依赖 task
标记完成并派发新就绪阶段。
- 三次连续同因失败后停止重派,报告恢复入口;不要用新终端掩盖同一阻塞。
## ACK 特例
`code` worker 是运行 `$ack` 的阶段 Coordinator。ORC 的 `low/mid/high` 只决定这个
worker 的启动 profileACK 启动 Developer/Test 时继续读取自己的项目配置与
`standard/strong` 规则。ORC 不读取、改写或覆盖 ACK 的内部 worker profiles。
## 收尾
不要自动关闭仍承担恢复入口的终端,不自动删除 worktree 或清空 runtime-global task。
只有用户明确要求清理时,才按 Orca 和下游 Skill 的安全规则处理。
+74
View File
@@ -0,0 +1,74 @@
# ORC 阶段路由
ORC 只负责拆分、依赖、档位和监督。领域步骤、授权检查和完成标准由下游 Skill 自己
决定。
## 路由表
| 阶段 | 下游 Skill | 包含 | 不包含 |
|------|------------|------|--------|
| `code` | `$ack` | 功能、缺陷、重构、测试、三角色验证闭环,以及用户明确要求的普通非发布 PR/MR | 版本发布、单独上传产物 |
| `release` | `$manage-release` | 版本号、release worktree/分支、release PR/MR、合并、tag、Forge Release、恢复发布 | 普通非发布 PR/MR、构建或上传 DEB/Docker |
| `deb` | `$deb-publisher` | DEB 构建、校验、上传与仓库可见性 | 源码 tag、Docker 镜像 |
| `docker` | `$publish-docker-image` | Docker/OCI 构建、push、digest 与平台验证 | 源码版本生命周期、DEB |
没有匹配项时不要临时扩写某个 Skill 的职责,也不要让 ORC 自己模仿领域流程。报告缺少
的能力,由用户决定直接执行、安装新 Skill 或另行设计。
## 拆分规则
1. 先从用户请求提取最终结果,再拆出真正需要的阶段;不要因为安装了某个 Skill 就
自动增加发布或上传。
2. 为每个阶段锁定输入:项目、worktree、源 commit/tag、版本、目标和用户授权的最远
写操作。
3. 同一领域的连续动作保留在一个下游任务中。例如版本号、release PR、合并和 tag
属于一个 `manage-release` 生命周期,不拆成多个互相争抢状态的 worker。
4. 只有输入 revision 完全相同且互不修改同一工作树时,才并行执行 DEB 与 Docker。
5. 普通代码改动进入 ACK。若项目尚未初始化 ACK,`code` 阶段停在前置条件,不由 ORC
静默初始化。
6. `code` 阶段默认停在 ACK `verified`;用户明确要求普通 PR/MR 时最多到
`review_ready`。worker prompt 必须禁止继续执行版本发布、DEB、Docker 或部署。
## 常见 DAG
完整交付:
```text
code ($ack)
-> release ($manage-release)
-> deb ($deb-publisher)
-> docker ($publish-docker-image)
```
只从当前 commit 构建产物:
```text
deb ($deb-publisher) || docker ($publish-docker-image)
```
仅发布源码版本:
```text
release ($manage-release)
```
依赖不是固定模板,但 ORC v1 不拆分一个 `manage-release` 生命周期。若项目要求在打开
release PR 与合并之间插入 DEB/Docker gate,当前 task 粒度无法安全表达该中间里程碑;
在打开 PR 前建立 decision gate 并报告该流程暂不支持,不得用循环依赖或两个 release
worker 临时拼接。
## Worker prompt 契约
每个 worker prompt 至少包含:
- 第一条指令显式调用唯一的下游 Skill,例如 `Use $manage-release ...`
- 阶段目标与明确的非目标。
- 项目/worktree、输入 commit/tag 和前置阶段的可核对结果。
- 用户已经授予的最远动作;未授权动作明确禁止。
- 要求遵循项目 Agent 指令和下游 Skill 自身的停止条件。
- 完成证据,以及通过 live dispatch preamble 回报 `worker_done` 的要求。
- `code` prompt 还必须写明 ACK 停止点是 `verified` 或普通 PR 的 `review_ready`,并禁止
ACK 路由版本、DEB、Docker 或部署动作。
不要把 ORC 的 profile、路由器内部规则或其它下游 Skill 注入 worker。worker 只需要
当前阶段、对应 Skill 和必要依赖结果。
+889
View File
@@ -0,0 +1,889 @@
#!/usr/bin/env python3
"""Validate ORC config and build a worktree-bound Codex launch plan."""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import pwd
import re
import shlex
import stat
import subprocess
import sys
from pathlib import Path
from typing import Any
LEVELS = ("low", "mid", "high")
STAGES = ("code", "release", "deb", "docker")
EXPECTED_EFFORT = {"low": "low", "mid": "medium", "high": "high"}
TOP_LEVEL_KEYS = {
"version",
"defaultLevel",
"stageDefaults",
"allowedWorktrees",
"profiles",
}
PROFILE_KEYS = {
"cli",
"model",
"reasoningEffort",
"permissionMode",
"approvalPolicy",
}
MODEL_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}\Z")
MAX_CONFIG_SIZE = 64 * 1024
MAX_CONTROL_OUTPUT = 64 * 1024
CONTROL_TIMEOUT_SECONDS = 15
CONFIG_RELATIVE_PATH = Path("docs/orc/config.yaml")
COMMON_ENVIRONMENT_NAMES = {
"COLORTERM",
"LANG",
"LC_ALL",
"NO_COLOR",
"TERM",
"TZ",
}
MODEL_AUTH_ENVIRONMENT = {
"codex-login": frozenset(),
"openai": frozenset({"OPENAI_API_KEY"}),
"azure-openai": frozenset({"AZURE_OPENAI_API_KEY"}),
}
REMOTE_AUTH_ENVIRONMENT = {
"none": frozenset(),
"github-token": frozenset({"GITHUB_TOKEN"}),
"gitlab-token": frozenset({"GITLAB_TOKEN"}),
"gitea-token": frozenset({"GITEA_TOKEN"}),
"forgejo-token": frozenset({"FORGEJO_TOKEN"}),
"ssh-agent": frozenset({"SSH_AUTH_SOCK"}),
"deb-token": frozenset({"DEB_TOKEN"}),
}
STAGE_REMOTE_AUTH = {
"code": frozenset(
{
"none",
"github-token",
"gitlab-token",
"gitea-token",
"forgejo-token",
"ssh-agent",
}
),
"release": frozenset(
{
"none",
"github-token",
"gitlab-token",
"gitea-token",
"forgejo-token",
"ssh-agent",
}
),
"deb": frozenset({"none", "deb-token", "ssh-agent"}),
"docker": frozenset({"none"}),
}
class ConfigError(ValueError):
"""ORC configuration or launch state is invalid or unsafe."""
def _json_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
result: dict[str, Any] = {}
for key, value in pairs:
if key in result:
raise ConfigError("JSON-compatible YAML contains a duplicate key")
result[key] = value
return result
def _read_bounded_regular_file(path: Path) -> tuple[str, dict[str, int]]:
absolute = path.absolute()
flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0)
descriptor: int | None = None
try:
descriptor = os.open(absolute, flags)
with os.fdopen(descriptor, "rb") as stream:
descriptor = None
before = os.fstat(stream.fileno())
if not stat.S_ISREG(before.st_mode):
raise ConfigError(f"config must be a regular file: {absolute}")
if before.st_size > MAX_CONFIG_SIZE:
raise ConfigError(f"config exceeds {MAX_CONFIG_SIZE} bytes")
content = stream.read(MAX_CONFIG_SIZE + 1)
after = os.fstat(stream.fileno())
except OSError as exc:
raise ConfigError(f"cannot safely read config {absolute}: {exc}") from exc
finally:
if descriptor is not None:
os.close(descriptor)
if len(content) > MAX_CONFIG_SIZE:
raise ConfigError(f"config exceeds {MAX_CONFIG_SIZE} bytes")
identity_before = (before.st_dev, before.st_ino, before.st_size, before.st_mtime_ns)
identity_after = (after.st_dev, after.st_ino, after.st_size, after.st_mtime_ns)
if identity_before != identity_after:
raise ConfigError("config changed while it was being read")
try:
text = content.decode("utf-8")
except UnicodeDecodeError as exc:
raise ConfigError("config must be valid UTF-8") from exc
return text, {
"device": before.st_dev,
"inode": before.st_ino,
"size": before.st_size,
"mtimeNs": before.st_mtime_ns,
}
def _mapping(value: Any, path: str) -> dict[str, Any]:
if not isinstance(value, dict):
raise ConfigError(f"{path} must be a mapping")
return value
def _exact_keys(
value: dict[str, Any],
*,
required: set[str],
path: str,
) -> None:
missing = sorted(required - set(value))
unknown = sorted(set(value) - required)
if missing:
raise ConfigError(f"{path} is missing fields: {', '.join(missing)}")
if unknown:
raise ConfigError(f"{path} has unknown fields: {', '.join(unknown)}")
def _enum(value: Any, allowed: tuple[str, ...] | set[str], path: str) -> str:
if not isinstance(value, str) or value not in allowed:
raise ConfigError(f"{path} must be one of: {', '.join(sorted(allowed))}")
return value
def validate_config(document: Any) -> dict[str, Any]:
config = _mapping(document, "config")
_exact_keys(config, required=TOP_LEVEL_KEYS, path="config")
version = config["version"]
if isinstance(version, bool) or version != 1:
raise ConfigError("version must be integer 1")
_enum(config["defaultLevel"], LEVELS, "defaultLevel")
stage_defaults = _mapping(config["stageDefaults"], "stageDefaults")
unknown_stages = sorted(set(stage_defaults) - set(STAGES))
if unknown_stages:
raise ConfigError(
f"stageDefaults has unknown fields: {', '.join(unknown_stages)}"
)
for stage, level in stage_defaults.items():
_enum(level, LEVELS, f"stageDefaults.{stage}")
allowed = config["allowedWorktrees"]
if not isinstance(allowed, list) or not allowed:
raise ConfigError("allowedWorktrees must be a non-empty list")
seen_worktrees: set[str] = set()
for index, entry in enumerate(allowed):
if (
not isinstance(entry, str)
or not entry
or entry != entry.strip()
or any(character in entry for character in ("\x00", "\n", "\r"))
):
raise ConfigError(
f"allowedWorktrees[{index}] must be a safe non-empty path"
)
if entry != "." and not Path(entry).is_absolute():
raise ConfigError(
f"allowedWorktrees[{index}] must be '.' or an absolute path"
)
normalized = entry if entry == "." else str(Path(entry).absolute())
if normalized in seen_worktrees:
raise ConfigError(f"allowedWorktrees contains duplicate path: {entry}")
seen_worktrees.add(normalized)
profiles = _mapping(config["profiles"], "profiles")
_exact_keys(profiles, required=set(LEVELS), path="profiles")
for level in LEVELS:
profile = _mapping(profiles[level], f"profiles.{level}")
_exact_keys(profile, required=PROFILE_KEYS, path=f"profiles.{level}")
if profile["cli"] != "codex":
raise ConfigError(f"profiles.{level}.cli must be codex in ORC v1")
model = profile["model"]
if not isinstance(model, str) or not MODEL_RE.fullmatch(model):
raise ConfigError(f"profiles.{level}.model is not a safe exact model ID")
expected_effort = EXPECTED_EFFORT[level]
if profile["reasoningEffort"] != expected_effort:
raise ConfigError(
f"profiles.{level}.reasoningEffort must be {expected_effort}"
)
if profile["permissionMode"] != "workspace-write":
raise ConfigError(
f"profiles.{level}.permissionMode must be workspace-write in ORC v1"
)
_enum(
profile["approvalPolicy"],
{"untrusted", "on-request", "never"},
f"profiles.{level}.approvalPolicy",
)
return config
def load_config_snapshot(path: Path) -> tuple[dict[str, Any], dict[str, Any]]:
raw, identity = _read_bounded_regular_file(path)
try:
document = json.loads(raw, object_pairs_hook=_json_object)
except ConfigError:
raise
except Exception as exc:
raise ConfigError("invalid JSON-compatible YAML config") from exc
config = validate_config(document)
snapshot = {
"sha256": hashlib.sha256(raw.encode("utf-8")).hexdigest(),
**identity,
}
return config, snapshot
def load_config(path: Path) -> dict[str, Any]:
config, _ = load_config_snapshot(path)
return config
def resolve_profile(
config: dict[str, Any],
*,
stage: str,
global_level: str | None = None,
stage_level: str | None = None,
model_auth: str = "codex-login",
remote_auth: str = "none",
) -> dict[str, Any]:
_enum(stage, STAGES, "stage")
if global_level is not None:
_enum(global_level, LEVELS, "global level")
if stage_level is not None:
_enum(stage_level, LEVELS, "stage level")
_enum(model_auth, set(MODEL_AUTH_ENVIRONMENT), "model auth")
_enum(remote_auth, STAGE_REMOTE_AUTH[stage], f"{stage} remote auth")
if stage_level is not None:
level, source = stage_level, "request.stage"
elif global_level is not None:
level, source = global_level, "request.global"
elif stage in config["stageDefaults"]:
level, source = config["stageDefaults"][stage], f"config.stageDefaults.{stage}"
else:
level, source = config["defaultLevel"], "config.defaultLevel"
profile = config["profiles"].get(level)
if profile is None:
raise ConfigError(f"requested profile does not exist: {level}")
worker_args = [
"--model",
profile["model"],
"-c",
f'model_reasoning_effort="{profile["reasoningEffort"]}"',
"--sandbox",
profile["permissionMode"],
"--ask-for-approval",
profile["approvalPolicy"],
"--strict-config",
]
return {
"stage": stage,
"level": level,
"selectionSource": source,
"modelAuth": model_auth,
"remoteAuth": remote_auth,
"profile": dict(profile),
"workerArgs": worker_args,
}
def _path_has_parent_reference(value: str) -> bool:
return ".." in Path(value).parts
def _assert_no_symlink_components(path: Path, label: str) -> None:
if not path.is_absolute():
raise ConfigError(f"{label} must be absolute: {path}")
current = Path(path.anchor)
for part in path.parts[1:]:
current /= part
try:
metadata = os.lstat(current)
except OSError as exc:
raise ConfigError(f"{label} does not exist: {current}") from exc
if stat.S_ISLNK(metadata.st_mode):
raise ConfigError(f"{label} must not contain symlinks: {current}")
def canonical_directory(value: str | Path, label: str) -> Path:
text = str(value)
if (
not text
or text != text.strip()
or any(character in text for character in ("\x00", "\n", "\r"))
or _path_has_parent_reference(text)
):
raise ConfigError(f"{label} must be a safe canonical absolute path")
raw = Path(text)
_assert_no_symlink_components(raw, label)
try:
resolved = raw.resolve(strict=True)
except OSError as exc:
raise ConfigError(f"{label} does not exist: {raw}") from exc
if resolved != raw or resolved == Path(resolved.anchor) or not resolved.is_dir():
raise ConfigError(f"{label} must be a canonical non-root directory: {resolved}")
return resolved
def account_identity() -> tuple[Path, str]:
account = pwd.getpwuid(os.getuid())
account_home = Path(account.pw_dir).resolve(strict=True)
if not account_home.is_dir():
raise ConfigError("current account home is unavailable")
return account_home, account.pw_name
def trusted_path_entries() -> list[Path]:
account_home, _ = account_identity()
candidates = [
account_home / ".local" / "bin",
account_home / ".local" / "share" / "mise" / "shims",
account_home / ".cargo" / "bin",
Path("/home/linuxbrew/.linuxbrew/bin"),
Path("/usr/local/bin"),
Path("/usr/bin"),
Path("/bin"),
]
result: list[Path] = []
for candidate in candidates:
try:
resolved = candidate.resolve(strict=True)
except OSError:
continue
if resolved.is_dir() and resolved not in result:
result.append(resolved)
return result
def _trusted_executable(path: Path, expected_name: str) -> Path | None:
try:
candidate_metadata = os.lstat(path)
resolved = path.resolve(strict=True)
metadata = resolved.stat()
except OSError:
return None
if not (
stat.S_ISREG(candidate_metadata.st_mode)
or stat.S_ISLNK(candidate_metadata.st_mode)
):
return None
if not stat.S_ISREG(metadata.st_mode) or not os.access(resolved, os.X_OK):
return None
if metadata.st_uid not in {0, os.getuid()}:
return None
if stat.S_IMODE(metadata.st_mode) & 0o022:
return None
if expected_name == "python3":
if not resolved.name.startswith("python3"):
return None
elif resolved.name != expected_name:
return None
return resolved
def resolve_trusted_executable(name: str) -> Path:
if name not in {"codex", "git", "orca"}:
raise ConfigError(f"unsupported executable: {name}")
search_paths = trusted_path_entries()
if name == "git":
search_paths = [
path
for path in search_paths
if str(path) in {"/usr/local/bin", "/usr/bin", "/bin"}
]
for directory in search_paths:
resolved = _trusted_executable(directory / name, name)
if resolved is not None:
return resolved
raise ConfigError(f"trusted {name} executable was not found in fixed directories")
def resolve_trusted_python() -> Path:
for candidate in (Path("/usr/bin/python3"), Path("/usr/local/bin/python3")):
resolved = _trusted_executable(candidate, "python3")
if resolved is not None and resolved.stat().st_uid == 0:
return resolved
raise ConfigError("a root-owned Python executable was not found in fixed paths")
def control_environment() -> dict[str, str]:
account_home, username = account_identity()
result = {
"HOME": str(account_home),
"LOGNAME": username,
"PATH": os.pathsep.join(str(path) for path in trusted_path_entries()),
"USER": username,
}
for name, value in os.environ.items():
if (
name in COMMON_ENVIRONMENT_NAMES or name.startswith("LC_")
) and "\x00" not in value:
result[name] = value
return result
def selected_credential_names(
stage: str,
*,
model_auth: str,
remote_auth: str,
) -> frozenset[str]:
_enum(stage, STAGES, "stage")
_enum(model_auth, set(MODEL_AUTH_ENVIRONMENT), "model auth")
_enum(remote_auth, STAGE_REMOTE_AUTH[stage], f"{stage} remote auth")
names = MODEL_AUTH_ENVIRONMENT[model_auth] | REMOTE_AUTH_ENVIRONMENT[remote_auth]
for name in names:
value = os.environ.get(name)
if not value or "\x00" in value:
raise ConfigError(
f"selected authentication variable is unavailable: {name}"
)
if name == "SSH_AUTH_SOCK":
socket_path = Path(value)
if (
not socket_path.is_absolute()
or value != value.strip()
or any(character in value for character in ("\n", "\r"))
or _path_has_parent_reference(value)
):
raise ConfigError("selected SSH_AUTH_SOCK is not a safe absolute path")
_assert_no_symlink_components(socket_path, "selected SSH_AUTH_SOCK")
try:
metadata = os.lstat(socket_path)
except OSError as exc:
raise ConfigError("selected SSH_AUTH_SOCK is unavailable") from exc
if (
not stat.S_ISSOCK(metadata.st_mode)
or metadata.st_uid != os.getuid()
or stat.S_IMODE(metadata.st_mode) & 0o022
):
raise ConfigError("selected SSH_AUTH_SOCK is not a trusted user socket")
return names
def worker_environment(
stage: str,
*,
model_auth: str,
remote_auth: str,
) -> dict[str, str]:
result = control_environment()
for name in selected_credential_names(
stage,
model_auth=model_auth,
remote_auth=remote_auth,
):
result[name] = os.environ[name]
return result
def _run_control(argv: list[str], label: str) -> str:
try:
completed = subprocess.run(
argv,
shell=False,
check=False,
capture_output=True,
text=True,
timeout=CONTROL_TIMEOUT_SECONDS,
env=control_environment(),
)
except (OSError, subprocess.TimeoutExpired) as exc:
raise ConfigError(f"{label} could not be executed safely") from exc
if completed.returncode != 0:
raise ConfigError(f"{label} failed with exit {completed.returncode}")
output = completed.stdout.strip()
if not output or len(output.encode("utf-8")) > MAX_CONTROL_OUTPUT:
raise ConfigError(f"{label} returned invalid output")
return output
def _git_path(value: str, cwd: Path, label: str) -> Path:
candidate = Path(value)
if not candidate.is_absolute():
candidate = cwd / candidate
_assert_no_symlink_components(candidate, label)
try:
resolved = candidate.resolve(strict=True)
except OSError as exc:
raise ConfigError(f"{label} is invalid") from exc
if not resolved.is_dir():
raise ConfigError(f"{label} is not a directory")
return resolved
def validate_worktree(
config: dict[str, Any],
*,
project_root_value: str | Path,
worktree_value: str | Path,
) -> dict[str, Any]:
project_root = canonical_directory(project_root_value, "project root")
worktree = canonical_directory(worktree_value, "target worktree")
git = resolve_trusted_executable("git")
top_level = canonical_directory(
_run_control(
[str(git), "-C", str(project_root), "rev-parse", "--show-toplevel"],
"Git project-root check",
),
"Git project root",
)
if top_level != project_root:
raise ConfigError("project root is not the repository top level")
common_dir = _git_path(
_run_control(
[str(git), "-C", str(project_root), "rev-parse", "--git-common-dir"],
"Git common-directory check",
),
project_root,
"Git common directory",
)
listed = _run_control(
[str(git), "-C", str(project_root), "worktree", "list", "--porcelain"],
"Git worktree listing",
)
registered: set[Path] = set()
for line in listed.splitlines():
if line.startswith("worktree "):
try:
registered.add(
canonical_directory(line[9:], "registered worktree")
)
except ConfigError:
continue
allowed: set[Path] = set()
for entry in config["allowedWorktrees"]:
allowed.add(
project_root
if entry == "."
else canonical_directory(entry, "allowed worktree")
)
if not allowed <= registered:
raise ConfigError("allowedWorktrees contains an unregistered Git worktree")
if worktree not in allowed:
raise ConfigError("target worktree is not in allowedWorktrees")
target_top = canonical_directory(
_run_control(
[str(git), "-C", str(worktree), "rev-parse", "--show-toplevel"],
"Git target-worktree check",
),
"target Git worktree",
)
target_common = _git_path(
_run_control(
[str(git), "-C", str(worktree), "rev-parse", "--git-common-dir"],
"target Git common-directory check",
),
worktree,
"target Git common directory",
)
if target_top != worktree or target_common != common_dir:
raise ConfigError("target worktree does not belong to the project repository")
worktree_metadata = worktree.stat()
common_metadata = common_dir.stat()
return {
"projectRoot": str(project_root),
"worktree": str(worktree),
"gitCommonDir": str(common_dir),
"worktreeIdentity": {
"device": worktree_metadata.st_dev,
"inode": worktree_metadata.st_ino,
"gitCommonDevice": common_metadata.st_dev,
"gitCommonInode": common_metadata.st_ino,
},
}
def _file_facts(path: Path) -> dict[str, Any]:
metadata = path.stat()
return {
"path": str(path),
"device": metadata.st_dev,
"inode": metadata.st_ino,
"size": metadata.st_size,
"mtimeNs": metadata.st_mtime_ns,
}
def _executable_facts(path: Path) -> dict[str, Any]:
return {
**_file_facts(path),
"version": _run_control([str(path), "--version"], "Codex version check"),
}
def _python_facts(path: Path) -> dict[str, Any]:
version = _run_control(
[
str(path),
"-I",
"-S",
"-c",
"import sys; print(sys.version.split()[0])",
],
"Python version check",
)
return {
**_file_facts(path),
"version": version,
}
def _fingerprint(value: dict[str, Any]) -> str:
canonical = json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
).encode("utf-8")
return "sha256:" + hashlib.sha256(canonical).hexdigest()
def build_launch_plan(
config_path: Path,
*,
project_root: str | Path,
worktree: str | Path,
stage: str,
global_level: str | None = None,
stage_level: str | None = None,
model_auth: str = "codex-login",
remote_auth: str = "none",
) -> dict[str, Any]:
project = canonical_directory(project_root, "project root")
expected_config = project / CONFIG_RELATIVE_PATH
if config_path.absolute() != expected_config:
raise ConfigError(f"config path must be {expected_config}")
_assert_no_symlink_components(expected_config, "config path")
config, config_snapshot = load_config_snapshot(expected_config)
worktree_facts = validate_worktree(
config,
project_root_value=project,
worktree_value=worktree,
)
profile = resolve_profile(
config,
stage=stage,
global_level=global_level,
stage_level=stage_level,
model_auth=model_auth,
remote_auth=remote_auth,
)
selected_credential_names(
stage,
model_auth=model_auth,
remote_auth=remote_auth,
)
codex = resolve_trusted_executable("codex")
executable = _executable_facts(codex)
orca = resolve_trusted_executable("orca")
orca_executable = _file_facts(orca)
python = resolve_trusted_python()
python_executable = _python_facts(python)
script = Path(__file__).resolve(strict=True)
script_metadata = script.stat()
script_sha256 = hashlib.sha256(script.read_bytes()).hexdigest()
launch_facts = {
**profile,
**worktree_facts,
"config": {
"path": str(expected_config),
**config_snapshot,
},
"executable": executable,
"orca": orca_executable,
"python": python_executable,
"launcher": {
"path": str(script),
"device": script_metadata.st_dev,
"inode": script_metadata.st_ino,
"size": script_metadata.st_size,
"mtimeNs": script_metadata.st_mtime_ns,
"sha256": script_sha256,
},
}
fingerprint = _fingerprint(launch_facts)
worker_argv = [str(codex), *profile["workerArgs"]]
launcher_argv = [
str(python),
"-I",
"-S",
str(script),
"_launch",
str(expected_config),
"--project-root",
str(project),
"--worktree",
str(worktree_facts["worktree"]),
"--stage",
stage,
"--expected-fingerprint",
fingerprint,
]
if global_level is not None:
launcher_argv.extend(["--global-level", global_level])
if stage_level is not None:
launcher_argv.extend(["--stage-level", stage_level])
if model_auth != "codex-login":
launcher_argv.extend(["--model-auth", model_auth])
if remote_auth != "none":
launcher_argv.extend(["--remote-auth", remote_auth])
terminal_command = shlex.join(launcher_argv)
worktree_selector = "path:" + str(worktree_facts["worktree"])
terminal_title = f"ORC-{stage}-{profile['level']}-{fingerprint[7:15]}"
terminal_create_argv = [
str(orca),
"terminal",
"create",
"--worktree",
worktree_selector,
"--title",
terminal_title,
"--command",
terminal_command,
"--json",
]
return {
**launch_facts,
"argv": worker_argv,
"launchFingerprint": fingerprint,
"launcherArgv": launcher_argv,
"terminalCommand": terminal_command,
"worktreeSelector": worktree_selector,
"terminalTitle": terminal_title,
"terminalCreateArgv": terminal_create_argv,
"terminalCreateShellCommand": shlex.join(terminal_create_argv),
}
def execute_launch(args: argparse.Namespace) -> int:
plan = build_launch_plan(
args.config,
project_root=args.project_root,
worktree=args.worktree,
stage=args.stage,
global_level=args.global_level,
stage_level=args.stage_level,
model_auth=args.model_auth,
remote_auth=args.remote_auth,
)
if plan["launchFingerprint"] != args.expected_fingerprint:
raise ConfigError("launch fingerprint changed; resolve the profile again")
current = canonical_directory(Path.cwd(), "launcher working directory")
if current != Path(plan["worktree"]):
raise ConfigError("launcher working directory does not match target worktree")
current_python = Path(sys.executable).resolve(strict=True)
if current_python != Path(plan["python"]["path"]):
raise ConfigError("launcher Python does not match the resolved interpreter")
if _python_facts(current_python) != plan["python"]:
raise ConfigError("Python executable changed before launch")
executable = Path(plan["executable"]["path"])
if _executable_facts(executable) != plan["executable"]:
raise ConfigError("Codex executable changed before launch")
try:
os.execve(
executable,
plan["argv"],
worker_environment(
plan["stage"],
model_auth=plan["modelAuth"],
remote_auth=plan["remoteAuth"],
),
)
except OSError as exc:
raise ConfigError("Codex worker could not be launched") from exc
return 1 # pragma: no cover - os.execve does not return on success
def _add_resolution_arguments(parser: argparse.ArgumentParser) -> None:
parser.add_argument("config", type=Path)
parser.add_argument("--project-root", required=True)
parser.add_argument("--worktree", required=True)
parser.add_argument("--stage", required=True, choices=STAGES)
parser.add_argument("--global-level", choices=LEVELS)
parser.add_argument("--stage-level", choices=LEVELS)
parser.add_argument(
"--model-auth",
choices=tuple(MODEL_AUTH_ENVIRONMENT),
default="codex-login",
)
parser.add_argument(
"--remote-auth",
choices=tuple(REMOTE_AUTH_ENVIRONMENT),
default="none",
)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
validate = subparsers.add_parser("validate", help="validate config only")
validate.add_argument("config", type=Path)
resolve = subparsers.add_parser("resolve", help="resolve a bound launch plan")
_add_resolution_arguments(resolve)
launch = subparsers.add_parser("_launch", help=argparse.SUPPRESS)
_add_resolution_arguments(launch)
launch.add_argument("--expected-fingerprint", required=True)
return parser
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
try:
if args.command == "validate":
config = load_config(args.config)
result: dict[str, Any] = {
"ok": True,
"config": str(args.config.absolute()),
"levels": list(LEVELS),
"stages": list(STAGES),
"defaultLevel": config["defaultLevel"],
}
elif args.command == "resolve":
result = build_launch_plan(
args.config,
project_root=args.project_root,
worktree=args.worktree,
stage=args.stage,
global_level=args.global_level,
stage_level=args.stage_level,
model_auth=args.model_auth,
remote_auth=args.remote_auth,
)
else:
return execute_launch(args)
except ConfigError as exc:
print(f"ORC config error: {exc}", file=sys.stderr)
return 1
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())
+36
View File
@@ -0,0 +1,36 @@
{
"version": 1,
"defaultLevel": "mid",
"stageDefaults": {
"code": "high",
"release": "mid",
"deb": "low",
"docker": "low"
},
"allowedWorktrees": [
"."
],
"profiles": {
"low": {
"cli": "codex",
"model": "gpt-5.6-luna",
"reasoningEffort": "low",
"permissionMode": "workspace-write",
"approvalPolicy": "never"
},
"mid": {
"cli": "codex",
"model": "gpt-5.6-terra",
"reasoningEffort": "medium",
"permissionMode": "workspace-write",
"approvalPolicy": "never"
},
"high": {
"cli": "codex",
"model": "gpt-5.6-sol",
"reasoningEffort": "high",
"permissionMode": "workspace-write",
"approvalPolicy": "never"
}
}
}