一句话定位:Trellis 的任务/归档/上下文能力 + Spec-Driven 的闭环控制论,用 Rust 做成确定性控制层,让 AI 编码工具(OMP / Claude Code / Codex …)只能在「可定义、可检查、可审计」的边界内工作。
ctl 不是又一个代码生成器。它解决的是 AI 协作里真正难的那部分:
不是「让 agent 做更多事」,
而是「明确什么能做、谁能做、在什么范围内做、越界谁来决定」。
事件溯源的任务账本 + 机器可执行的写入边界 + 确定性验收闸门,三者组成一个不靠自觉、靠机制的护栏。
| 维度 | 没有 ctl | 有了 ctl |
|---|---|---|
| 写入边界 | agent 可以改任何文件 | 每个任务声明 write_allow;越界写入由 hook fail-closed 拦截 |
| 事实源 | 散落的 Markdown 进度 | events.jsonl 追加式唯一事实源,task.json 由 replay 重建 |
| 验收 | 「我觉得做完了」 | 机器可执行 gate(cargo_check/test/fmt/clippy …)通过才能推进状态 |
| 可审计 | 全靠聊天记录回溯 | 每次状态变化都是一条带内容 hash、来源与 actor 标签的 canonical event |
| 多工具治理 | 每个 CLI 一套规则 | 单一来源治理,OMP + Claude Code 共用同一套边界 |
- 运行二进制:
ctl本身是静态二进制,下载即用,无运行时依赖。 - Claude Code 集成:需要
python可执行(PreToolUse hook 是 Python 脚本;缺失则 gate 不会触发,ctl init --claude会告警)。 - OMP 集成:需要 Node.js(context hook 是 TypeScript)。
- opencode 集成:需要 Bun(
ctl adapter doctor --verify会跑插件测试)。 - 从源码构建(可选):Rust ≥ 1.74(stable)。
支持平台:Linux(x64 / arm64)、macOS(Intel / Apple Silicon)、Windows(x64,原生,无需 WSL;ARM64 Windows 走 x64 模拟,无原生构建)。
Linux / macOS(bash)
curl -fsSL https://raw.githubusercontent.com/neostfox/ctl/master/scripts/install.sh | shWindows(PowerShell)
irm https://raw.githubusercontent.com/neostfox/ctl/master/scripts/install.ps1 | iex安装脚本会自动识别系统/架构,从 GitHub Releases 下载对应二进制、强制校验 SHA256(不匹配即拒绝安装),并装入 PATH。
Windows 用户:安装会修改用户级 PATH(
%LOCALAPPDATA%\ctl\bin)。请新开一个 PowerShell/终端窗口再运行ctl init——当前窗口看不到新 PATH。
Linux/macOS 用户:若你没有
/usr/local/bin写权限,脚本会装到~/.local/bin。若该目录不在 PATH,把export PATH="$HOME/.local/bin:$PATH"写入~/.bashrc/~/.zshrc后source之。
ctl --version # 应输出 ctl 0.0.15
ctl doctor # 诊断本地账本/集成健康(无 .ctl/ 时会提示先 ctl init)若提示 ctl: command not found:Windows 请新开一个终端让 PATH 生效;Linux/macOS 请确认 ~/.local/bin 已在 PATH 中(见上方提示)。
可选项与其他安装方式
安装指定版本或自定义目录:
# bash
curl -fsSL https://raw.githubusercontent.com/neostfox/ctl/master/scripts/install.sh | sh -s -- --version vX.Y.Z --dir ~/.local/bin
# 或用环境变量
CTL_VERSION=vX.Y.Z CTL_INSTALL_DIR=~/.local/bin sh install.sh# PowerShell
$env:CTL_VERSION="vX.Y.Z"; irm https://raw.githubusercontent.com/neostfox/ctl/master/scripts/install.ps1 | iex把 vX.Y.Z 换成 Releases 上的具体版本号(不要照抄,示例里用的版本号会随发布漂移)。
从源码构建:
cargo build --release # 产物:target/release/ctl手动下载: 直接到 Releases 取对应平台的 ctl-<target>.tar.gz / .zip。
公司网络/代理环境: bash 设 HTTPS_PROXY=http://proxy:port 后再跑安装命令;PowerShell 用 $env:HTTPS_PROXY='http://proxy:port',或下载脚本本地执行 iex (Get-Content .\install.ps1 -Raw)。安装与 ctl self-update 只访问 raw.githubusercontent.com、github.com、objects.githubusercontent.com(见 ADR 0002)。
卸载: ctl 无独立卸载器,删除二进制即可——Windows 删 %LOCALAPPDATA%\ctl\bin\ctl.exe(self-update 会留 ctl.exe.old,可一并删)并从用户 PATH 移除该目录;Linux/macOS 删 /usr/local/bin/ctl 或 ~/.local/bin/ctl。项目内的 ctl 状态在 .ctl/,平台注入在 .claude/、.omp/、.opencode/,按需删除。
在你的项目根目录,选择你要接入的 AI 编码平台(可多选):
ctl init --claude --omp # 配置 Claude Code + OMP
ctl init --all --yes # 全部平台,跳过提示(适合脚本)
ctl init # 交互式选择ctl init 会创建 .ctl/ 任务账本、写入默认配置、注入所选平台的治理 hook/skill/settings,
并打印下一步指引。
下面是完整生命周期的「底层命令」展示,便于理解机制;日常协作里这一整套通常由 AI agent 经内置 skill 驱动,你只在「确认边界」「确认归档」等节点介入(见 如何使用)。
ctl task create --id 06-14-fix-login \
--objective "修复登录态过期" \
--read-scope src --write-allow src/auth --gates cargo_test
ctl task ready --id 06-14-fix-login
ctl task start --id 06-14-fix-login # 进入 in_progress,写入边界开始生效
# …agent 在 src/auth 内实现…
ctl gate run --id 06-14-fix-login --gate cargo_test # 跑验收闸门,记录 evidence
ctl task submit --id 06-14-fix-login
ctl task finish --id 06-14-fix-login
ctl task archive --id 06-14-fix-loginctl board # 终端 Kanban(默认)
ctl board --active # 只看未归档任务
ctl board --table # 传统表格格式
ctl board --json # 机器可读 JSON
ctl board --include-archived # 含已归档任务不带
--merge的ctl update是遗留的二进制自更新(等同于ctl self-update的旧行为);同步项目模板一律用ctl update --merge。
ctl update --merge # 同步项目内的 ctl 模板(安全合并,不改你的定制)
ctl self-update # 升级 ctl 二进制
ctl self-update --check # 检查是否有新版本日常协作下你几乎不用手敲命令——AI agent 通过内置 skill 驱动整个循环,你只在关键节点确认:
- 描述需求:直接对 agent 说要做什么。
- 确认边界:agent 推断 objective / scope / gates,给出任务提案,你回答
yes / 调整 / skip。 - 受控实现:agent 只能在
write_allow内写入;越界写入被 hook 当场拦截。 - 验收与完成:agent 自动跑 gate,控制层独立检查完成条件后,你确认归档。
CLI 是底层能力;治理与编排由
.omp/(OMP)与.claude/hooks/(Claude Code)里的 hook 强制执行。
工作流技能基座(workflow skills):在 control-guard 之外,
.agent/protocols/workflow-skills.md定义了一套 ctl-native 的工作流核心(WORKFLOW_PROTOCOL_VERSION = 1),并按平台逐字嵌入 OMP / OpenCode 各技能;CI 漂移检查(workflow_protocol_sync)确保两端不静默分叉。阶段为ctl-grill-with-spec(第一性原理对齐)→ctl-to-prd(PRD 合成,区分 Observed/Confirmed/Open 三类依据) →ctl-to-tasks(垂直切片任务提案)。红→绿由--tdd互锁在账本上证明、上下文交接由ctl handoff export/ctl handoff capture提供(两者是特性,不再单独成技能)。这些只是 agent 的工作流纪律—— 不证明正确性,不替代 gate / audit / evidence,不创造已证明的独立审阅者,也不构成 L3 防篡改证据。 外部灵感(Matt Pocock 的 skills、Trellis PR #335)属 L0 参考材料,只借鉴不 vendor(见.omp/skills/NOTICE.md)。
ctl 把工程控制论落到具体对象上——目标状态、观测、比较、控制动作,全部可机器表达:
┌─────────── 控制闭环 ───────────┐
proposal → approval → scoped lease → implement → audit_hold
│
deterministic audit ▼
human_resume | completed | stopped
四条硬约束撑起整个系统:
- 事件溯源:
events.jsonl是唯一事实源(append-only);task.json/control.json都是 replay 出来的投影。外部只能提交 evidence,由控制层验证后才生成 canonical event。 - 写入边界 fail-closed(按工具/平台分级):每个任务声明允许读写的路径;
ctl不可用时路径作用域的写工具(Write/Edit/MultiEdit)拦截而非放行——不可执行的边界绝不静默放行(Bash / 子智能体派发的精确边界见下方诚实声明)。 - 确定性验收:gate 是固定模板(无任意 shell),通过才允许
in_progress → review → completed。 - 审计是权限状态,不是提示:命中 schema / scope / 受保护路径 / 批量变更触发器后立即进入只读
audit_hold,由控制层独立核对,而非靠实现者自述「我做完了」。
边界的诚实声明(这是机制护栏,不是密码学安全边界):
- 写入边界是 agent 工具 hook 层的拦截,不是 OS 沙箱。 它治理经 OMP / OpenCode / Claude Code hook 路由的写操作;一个不经 hook 的进程不受此边界约束。它是「可执行、可审计的边界」,不是内核级隔离。
- fail-closed 是按工具、按平台分级的,不是一刀切。 路径作用域的 Write/Edit/MultiEdit 在
ctl不可用时 fail-closed(拦截)。但 Claude Code 的 Bash 在ctl出错/超时时 fail-open(绝不锁死 shell,故 bash 不是硬写边界——且不做路径作用域检查,应优先用 Write/Edit 做范围内修改);其 Task / 子智能体派发不被 PreToolUse 门禁匹配(U-1 平台边界,非待办——见.claude/subagent-dispatch.md:只派发只读子智能体、写操作留在主 agent)。OMP / OpenCode 的task派发经会话级插件门禁,OpenCode 的 Bash 亦 fail-closed。hash是内容/制品 hash(tree_hash/policy_hash/evidence_hash),保证的是信封完整性,不是内部声明的可信度。 事件未做密码学签名;actor是来源标签,不是被验证的身份主体。事件日志不是 L3 防篡改证据(无 hash chain / 签名 / 外部锚定);它保证的是单写者顺序与信封完整性,不是抗对手篡改。- 尚无 authenticated principal。 「reviewer ≠ implementer」靠
actor标签区分:审计 / 审批由不同的CTL_ACTOR标签(如ctl-review)记录在账本上,但这只是审阅者角色标签,不是被证明的独立身份主体。不要把它读作「已证明的独立审批」。- 并发多-run orchestration 仍是 experimental。 单写者保证对每个 task / run 账本成立,但跨账本(task ↔ run)写入不是事务化的:崩溃可能留下不一致,由
ctl doctor检出并给出手工恢复指引(控制层不自动改写状态)。
完整的控制论映射、drift 计算、子智能体调度协议、schema 设计等详见 DESIGN.md。
执行控制环(scope → implement → gate → review → complete)照不到一个盲区:当使用者只给方向、由 AI 推演需求与设计时,一个全绿、全绑定的任务仍可能建在 AI 幻觉出的 spec 上。0.0.1 之后引入的认识状态层处理的就是这层不可观测性——但它的边界被刻意画死:
这是 record-and-disclose,不是验证。
ctl不证明思考发生过,也不证明结论正确;它只如实记录哪些运行与产物发生过、来自谁 / 什么、是否经过独立挑战,以及哪些未知被何种证据关闭。产物存在 ≠ 思考质量存在;独立调用存在 ≠ 正确性存在。
- Brainstorm 来源(
ctl brainstorm):把一次思考的发散 / 挑战(critic)/ 收敛产物按 path+hash 绑定到任务。记录-only——从不门禁 create/finish,也从不声称「思考有质量」或「评审是独立的」。source_run等字段是自报的,V1 不做证明。产物本身(L0)放在受 git 跟踪的顶层brainstorms/<id>/,不进.ctl/。 - 不确定性账本(
ctl uncertainty):把任务携带的未知显式记下来,并以resolved / accepted_as_assumption / invalidated了结。resolved必须引用一条 oracle-typed evidence,其来源(确定性 / 测试 / 运行时 / 外部权威 / human / model)被如实披露。modeloracle 是顾问性的,不能 resolve 一个未知——控制层在命令层拒绝以 model 证据 resolve;该约束只对新写入生效,规则之前已 resolve 的历史按 append-only 原样回放,披露时标为 ADVISORY。 - 研究 / Spike 任务(
ctl task create --kind research+ctl research):一类以证据 + 未知了结为产出、而非代码的任务。
完整本体、四级信任(L0–L3)与披露模型见 EPISTEMIC_CONTROL.md。
ctl init [--claude] [--opencode] [--omp] [--platform <name>] [--all] [--yes] 多平台初始化
ctl task create|ready|approve|start|submit|finish|archive|status 任务生命周期(approve = human-only ready, gh6)
ctl task quick --write-allow <p> create+ready+start 一步到位
ctl board [--table] [--active] [--include-archived] [--json] Kanban 看板(默认) / 表格 / JSON
ctl update --merge [--force|--skip] 同步项目模板(安全合并)
ctl self-update [--check] 升级 ctl 二进制
ctl handoff export --id <id> 导出只读任务快照
ctl handoff capture --id <id> --file <json> 持久化交接判断
ctl gate run|record 执行 / 记录验收闸门
ctl boundary check 校验某次写入是否越界
ctl replay | reconcile | validate 重建投影 / 校验事件流
ctl architecture check|review 架构合规
ctl doctor 诊断账本健康
# 认识状态层(V1):只记录与披露,从不门禁 / 评分 / 裁决
ctl brainstorm record|attach-critic|skip-critic|show
ctl uncertainty record|evidence|dispose|status
ctl research record|status
完整子命令见 ctl --help。
| 文档 | 内容 |
|---|---|
| DESIGN.md | 设计与愿景:控制论闭环、drift、子智能体、schema 冻结 |
| EPISTEMIC_CONTROL.md | 认识状态层:record-and-disclose 边界、四级信任、不确定性本体 |
| ROADMAP.md | 里程碑 M0–M6+ 与退出条件 |
| ARCHITECTURE_GUARDRAILS.md | 必须遵守的架构约束 |
| GLOB_WORKFLOW.md | 用 OMP /glob 分阶段推进实现 |
| AGENTS.md | 给 AI agent 的项目说明 |
遇到问题先跑这两条只读命令,90% 的常见问题都能定位:
ctl doctor # 诊断本地账本健康(投影漂移、孤儿 run、schema 校验失败等)
ctl adapter doctor # 诊断平台集成(hook/skill/插件是否就位);加 --verify 跑 opencode Bun 插件测试| 症状 | 第一步 | 修复 |
|---|---|---|
ctl: command not found(安装后) |
where ctl(Win)/which ctl(unix) |
Windows:新开终端让用户级 PATH 生效;Linux/macOS:确认 ~/.local/bin 在 PATH(export PATH="$HOME/.local/bin:$PATH" 写入 ~/.bashrc/~/.zshrc) |
| Claude Code 的 gate 从不触发 | python --version |
缺 python——PreToolUse hook 是 Python 脚本。重跑 ctl init --claude 并读输出里的 python-availability 告警 |
| OMP hook 不生效 | node --version |
缺 Node.js——OMP context hook 是 TypeScript |
| opencode 集成状态未知 | ctl adapter doctor --verify |
看 contract.* / platform.* 各 check 的 PASS/FAIL/WARN/UNKNOWN;有 FAIL 才算失败 |
No --gates given and no project default gate floor |
ctl gate(列模板) |
传 --gates cargo_test(或其他模板),或用 /ctl-spec 在 .ctl/config.toml 记录 [project].default_gates |
gate not found: <name> |
ctl gate |
gate 模板是固定注册表(cargo_check/test/fmt_check/clippy、tsc_check/eslint_check/vitest_run),拼写要对 |
| schema 校验失败 | ctl schema validate --file <path> |
校验事件/投影的 JSON Schema;schemas 自 0.0.14 起已嵌入二进制,不再依赖磁盘上的 schemas/ 目录 |
| 事件账本不一致 | ctl doctor |
报告 drift / 孤儿 / 损坏并给手工恢复指引(控制层不自动改写状态) |
| 写入被 hook 拒绝但路径看起来在 write_allow 内 | ctl boundary explain --path <p> |
多半是 ../绝对路径/UNC,或落在受保护路径(.git/.ctl/tasks/Cargo.toml/schemas 等);越界写入要走 ctl apply 申请受审例外 |
和 Trellis / Spec-Kit 有什么不同?
它们以 Markdown 流程为主;ctl 把任务状态、事件、验收做成 Rust 确定性状态机,边界由机器强制,而不是约定俗成。
支持哪些 AI 工具?
当前激活 OMP(原生 hook)、Claude Code(PreToolUse hook)与 opencode(.opencode/plugins/ctl-gate.ts 插件:tool.execute.before 门禁 + system 上下文注入)。控制层只依赖统一协议;ctl 另带 opencode 执行器 adapter(ctl adapter capabilities --adapter opencode、ctl run ingest --adapter opencode)。Codex 仍为规划中的兼容目标。
怎么查看 / 诊断已注册的 adapter?
ctl adapter 提供三个只读自省命令(均支持 --json):
ctl adapter list—— 列出注册表里全部 adapter 及其output_format/ 能力(registry 顺序)。ctl adapter status --adapter <name> [--verify]—— 诊断单个 adapter。ctl adapter doctor [--verify]—— 诊断全部 adapter。
诊断沿两条轴展开,每条 check 带一个 PASS / FAIL / WARN / UNKNOWN / NOT_TRACKED 状态:
- contract.* —— Rust
ExecutorAdapter契约条款(解析、名字自洽、capabilities 形状、prepare_run、validate_output接受/拒绝)。这是src/adapters/里 conformance 测试套件的线上孪生:CI 用#[test]断言,doctor 用同样条款在已发布二进制上回答“有没有半成品 adapter 被发出去”。 - platform.* —— 宿主集成:control-guard skill 是否存在、managed-protocol 是否漂移(复用 CI 的协议漂移检查器)、opencode 插件 / OMP hook·config 文件是否就位、opencode 的 Bun 插件测试。
刻意不给综合“健康分”:输出只报事实——每条 check 的状态,以及 PASS/FAIL/WARN/UNKNOWN/NOT_TRACKED 计数与 healthy/total。判失败的唯一依据是“存在 FAIL”;WARN/UNKNOWN 不算失败,存在 FAIL 时命令非零退出。未实际执行或无法判定的检查保持 NOT_TRACKED / UNKNOWN,绝不冒充 PASS:opencode 的 Bun 插件测试默认 NOT_TRACKED,仅在 --verify 下真正运行(Bun 不可用则 UNKNOWN)。诊断只读文件与注册表,从不触碰任务 / run 账本。
注意:healthy(= 无 FAIL 的 adapter 数)只表示「没有失败检查」,不等于「安全可用」——WARN / UNKNOWN / NOT_TRACKED 仍可能暗含现实风险,只是不触发非零退出。
会不会限制太死?
默认只读、最小权限是刻意设计。需要越界时走 ctl apply 申请受审批的路径例外,而不是直接放开。
需要联网 / 接模型吗?
不需要。ctl 本身不调用模型,只做状态、边界与验收;模型由你选用的执行器提供。
MIT。本项目用 Rust 重新实现状态机与协议,只吸收 Trellis / Spec-Driven 的思想,不复制其代码。