monstercameron/codeflux
GitHub: monstercameron/codeflux
一款以操作级权限控制和隔离执行为核心设计的本地优先 AI 编码代理,通过精确授权、独立 worktree 和透明证据链来保障代码修改的安全性与可追溯性。
Stars: 0 | Forks: 0
# CodeFlux
**一种编码代理,其权限来源于操作本身 *是* 什么 —
而不是来源于模型所说它需要的。**
[](https://github.com/monstercameron/codeflux/actions/workflows/ci.yml)
[](https://github.com/monstercameron/codeflux/actions/workflows/codeql.yml)
[](LICENSE)
[](go.mod)
[](#supported-platforms)
[](#project-status)
**[快速开始](#quickstart) · [工作原理](#how-it-works) · [不会做的事](#what-it-will-not-do) · [用户指南](docs/using.md) · [贡献](.github/CONTRIBUTING.md)**
## 核心主张
大多数编码代理使用模型编写的句子来请求权限。你批准了
这个句子。然后执行了其他操作。
CodeFlux 使用 **精确的操作标识** 进行请求:工具、其有序
参数及其声明的效果。批准 `curl https://example.com` 并不
代表批准 `curl https://elsewhere`,也不代表批准通过
不同工具访问相同的 URL。拒绝记录是针对 *capability* 的,
而不是针对你恰好看到的那个工具——因此被拒绝的操作不会被
悄悄地通过“侧门”重试。
这一点很重要,因为仓库内容是不可信的输入。一个被投毒的 `README`
绝对能说服模型 *提议* 某些恶意的操作。但它无法
说服 CodeFlux 该提议已获授权,因为权限绝不会被
模型或文件断言的任何内容所推导。这就是整个设计,
以下的所有内容皆源于此。
第二个承诺更窄,但也同样具有核心支撑作用:**CodeFlux 将它知道的、含糊不清的以及它所推荐的内容作为三件独立的事物进行报告。** 预测是一个范围,绝不是承诺。未报告的价格保持
为 `unknown`,绝不会渲染为零。通过的验证意味着运行的
检查通过了——并不意味着更改是正确的。执行图解释了
发生了什么;它并不证明发生的事情是正确的。
一个夸大自身证据的代理比没有代理更糟糕,因为你会因此
停止阅读 diff。
## 快速开始
CodeFlux 是 **一个可执行文件**。它按用户安装,从不需要
管理员权限——一个请求提权的编码代理是在请求远远
超出其所需的信任。
```
# 1. Verify the download against its published SHA256SUMS, then put it on PATH.
# 2. Check the install. Reports every prerequisite as ok / missing / degraded /
# failed / unknown, with a next step for anything that is not ok.
codeflux doctor
# 3. Connect one provider. The credential is read from standard input — never
# from an argument, which every process on the machine can see and which
# your shell history keeps — and is stored in the OS credential store.
codeflux provider set --name anthropic
# 4. Start. Binds loopback, opens your browser, prints the URL.
codeflux start
```
会话密钥 **不会** 被打印出来。回显到终端的密钥会
残留在回滚缓存和 shell 历史记录中;你的浏览器会将其作为
你无需输入的 HttpOnly, same-site cookie 接收。使用 `--no-browser` 打印 URL
并自行打开。
然后,在界面中:
1. **选择一个仓库。** 一个具有干净工作树的本地 Git 仓库。
只有在您看到并确认未提交的更改具体是什么之后,它们才会被接受——
否则无法将您的编辑与代理的编辑区分开来。
2. **用你自己的话描述一个结果。** 不需要规格说明。
3. **阅读计划。** CodeFlux 在执行任何操作之前,会提议范围、步骤、
打算运行的检查以及它需要的权限。
批准它或将其打回。
4. **观看它工作。** 任务工作树之外的任何操作都会停止并询问。
5. **审查 diff** 及其背后的证据。在您接受之前,任何内容都不会到达您的分支。
CodeFlux 存储的所有内容都位于一个目录中:
| 平台 | 数据目录 |
| --- | --- |
| Windows | `%LOCALAPPDATA%\codeflux` |
| macOS | `~/Library/Application Support/codeflux` |
| Linux | `~/.local/share/codeflux` |
删除该目录,CodeFlux 就消失了。您的仓库不属于它的一部分。
## 它在哪些方面真正与众不同
### 它从不编辑你的检出
每个任务都在其自己的 Git worktree 中运行。当任务运行时您可以继续工作,
代理执行的任何操作都不会出现在您打开的文件中。完成的任务
会产生一个 diff 以及其背后的证据——改变了什么,运行了哪些检查,
它们说了什么。接受操作会将其合并。在那之前,什么都没有移动。
拒绝任务会 **保留** 其补丁而不是丢弃它,
因此您仍然可以检查您决定不采纳的工作。Worktree 会在
终止状态下被清理——除了那些任务结果含糊不清的 worktree,它会被保留,
因为删除它会破坏发生事情的唯一记录。
### 修复是有界的,而不是重试循环
当验证失败时,CodeFlux 会提议一个有界的修复,而不是盲目地一遍遍重试。
修复会 **重置附加到其更改计划的审批**,
因为针对旧计划收集的证据不再描述将要运行的内容。
### 金钱是精确的,unknown 就意味着未知
很容易混淆的三件事被严格区分:**forecast**(预测,即
估计值,显示为一个范围,绝不会被当作承诺)、**actual cost**(实际成本,即提供商收取的费用)和 **unknown**(未知,即提供商尚未报告
价格)。Unknown 绝不会被渲染为零——一个悄悄将 unknown 计为
无的总额会在最关键的时候低估您的支出。
所有金额都是精确的整数最小货币单位。成本中任何地方都
没有浮点数。**hard budget**(硬预算)在达到时会停止新的付费工作,
让进行中的工作结算完毕,并使任务保持可恢复状态。您可以提高限额、完成或
停止;CodeFlux 不会替您做决定。
### 可失效的记忆
CodeFlux 会记住仓库事实、审查过的命令、文件到测试的映射
以及任务之间的约定。只有当一项内容 **适用** 时才会被使用——
相同的项目、相同的工具链、相同的依赖项、证据依然成立。相似性
绝不等于适用性:一项 *看起来* 相关的内容并不因此就
符合条件。
条目会记录什么是 **derived from**(派生自)的,什么是仅仅 **influenced**(影响了)它们的,
这种区分是有约束力的。使一个条目失效会自动
隔离从它派生出来的所有内容,因为这些结论依赖于
它;它仅仅影响的内容会被标记以供审查。被隔离的条目
永远无法重新获得权限——必须转而建立一个新的条目。
除非测量到的检索召回率证明开启它是合理的,否则向量搜索是关闭的,
即便如此,它也只提议 *候选者*。它永远不会赋予
资格、有效性或权限。
### 承认它无法知道的崩溃恢复
如果 CodeFlux、worker 或您的机器在任务执行中崩溃,下次启动时会分别
告诉您三件事:**已知内容**(最后一个持久检查点)、**含糊不清的内容**(例如,到达外部
系统的命令是否已完成)以及 **它所建议的内容**。
当无法确定外部效果的结果时,您必须在执行任何其他操作之前
对其进行核对。CodeFlux 不会代表您重试含糊不清的
外部效果——重复的扣费、部署或消息是
它无法收回的操作。
### 您的数据保持为一个您可以检查的文件
```
codeflux backup --output 仓库布局
| 路径 | 存放内容 | | --- | --- | | `cmd/codeflux` | 面向用户的可执行文件 | | `cmd/codeflux-worker` | 任务 worker 进程 | | `cmd/codeflux-dev` | 所有的构建、lint、测试和诊断门控 | | `internal/domain` | 稳定的 domain 类型,无基础设施 | | `internal/coordinator` | 规划、权限、任务生命周期、投影 | | `internal/storage` | SQLite 仓库、事务、只读检查 | | `internal/events` | 日志和流契约 | | `internal/policy`, `internal/executor` | 权限推导和工具执行 | | `internal/gitwork` | Worktree、接受、回滚 | | `internal/providers` | 模型提供商适配器和批准的传输 | | `internal/graph`, `internal/graphlayout` | 任务作用域的执行图 | | `internal/retrieval`, `internal/vectorsearch` | 记忆资格和候选者 | | `internal/validation`, `internal/evidence`, `internal/review` | 检查及其证明的内容 | | `internal/forecast`, `internal/benchmarks` | 估计和测量 | | `internal/redact`, `internal/credentials` | 密钥处理和扫描 | | `internal/devdiag` | 性能分析和计时——除非明确启用,否则关闭 | | `web/frontend`, `web/client` | Go/WASM 界面 | | `api/proto` | 服务定义 | | `migrations/` | SQL migrations,合并后不可变 | | `.artifacts/` | 工具或测试 **唯一** 可以写入的地方 |deciding what to build"] B["Phase B · Atoms — stages 7–17
the smallest independently testable units"] C["Phase C · Molecules — stages 18–21
composition, and the obligations it creates"] D["Phase D · Control flow — stages 22–25
ordering, termination, every failure path"] E["Phase E · Program — stages 26–29
assembly through end-to-end exercise"] F["Phase F · Verification depth — stages 30–34
was any of the checking worth anything"] G["Phase G · Delivery — stages 35–37
evidence, acceptance, handover"] A --> B --> C --> D --> E --> F --> G --> OUT(["Accepted change + evidence"]) GATE1{"11 · atom-verification"} GATE2{"26 · assembly"} GATE3{"29 · end-to-end-tests"} GATE4{"31 · adversarial"} B -.- GATE1 E -.- GATE2 E -.- GATE3 F -.- GATE4 GATE1 -.-> LOOP GATE2 -.-> LOOP GATE3 -.-> LOOP GATE4 -.-> LOOP LOOP{{"Implementation loop
the run's only model entry point"}} LOOP -.->|"retry — possibly on a higher rung"| B classDef gate stroke-width:2px class GATE1,GATE2,GATE3,GATE4 gate ``` 该图中有三件事物具有核心支撑作用。 **测试先于被测事物存在,用例先于测试存在。** 阶段 7 在编写任何测试之前,从 *signature* 推导出一个输入阶梯—— 简单的、退化的、边界的、复杂的、错误的、病态的。通过阅读实现 编写的测试检查的是代码做了什么;而从契约推导出的用例 检查的是 signature 承诺了什么,这两者 恰好在 Bug 存在的地方产生分歧。 **阶段内的排序是一个论证,而不是一种约定。** 反模式 检测位于验证 *之后*,因为被吞掉的错误既不是 编译错误,也不是测试失败——针对当前行为编写的任何测试 都无法捕获它。优化只能在 mutation scoring 之后 运行,因为重写由没人证明能检测到缺陷的测试所保护的代码, 正是带有绿色测试套件的行为变更得以交付的原因。 文档排在 *最后*,在 fuzzing 和 mutation 之后, 因此它描述的是已知 atom 能做什么,而不是其作者的本意。 **恰好只有一个模型入口点。** 其他 36 个阶段是静态 分析、编译和运行事物。四个门控可以将工作打回—— `atom-verification`、`assembly`、`end-to-end-tests`、`adversarial`——而下一次尝试 在哪一运行级上运行,每次都是一个真正的选择。 ### 模型阶梯 只有在运行 **停滞** 时——连续三次尝试以相同方式失败——运行才会向上攀升, 而不是在发生一次失败时。 ``` flowchart LR R1["luna : low
default first rung"] R2["luna : max"] R3["sol : low"] R4["sol : high"] R5["sol : max
not on the default ladder"] R1 -->|stall| R2 -->|stall| R3 -->|stall| R4 R4 -.->|"must be added, and asks before spending"| R5 classDef ask stroke-width:2px class R5 ask ``` 在动用昂贵模型之前,耗尽廉价模型的工作量。 提高工作量会按照已经生效的费率计算更多 token 的费用; 更换模型会提高 *每一个* token 的费率。刻意跳过每个模型的中等档位—— 因为检测每个运行级都需要一次完整的停滞,所以一个仅仅比下一级 稍好一点的运行级需要用尝试次数来买单,且一无所获。 顶层运行级完全不在默认阶梯上。达到这个级别意味着运行 不再是一个实验,而是变成了一个关于金钱的决定, 因此需要由人来添加它,并且在运行花费它之前需要先询问。 ### 结果有五种,而不是两种 | 状态 | 含义 | | --- | --- | | `satisfied` | 门控成立且该阶段产生了证据 | | `failed` | 门控未成立 | | `skipped` | 本次运行不需要它——没有解析功能的程序就没有什么可以 fuzz 的 | | `blocked` | 上游的某些事情没有发生,这并不等同于本阶段失败 | | `not-implemented` | 产品完全无法执行此阶段 | 存在最后一种的原因是,如果将其合并到 `skipped` 中,就会让实现了 三分之一的流程的构建报告与实现了全部流程的构建相同结构的 结果。
全部 37 个阶段
``` flowchart TD subgraph A["A · Specification"] direction TB a1["1 instructions"] --> a2["2 clarification"] --> a3["3 atomic-instructions"] a3 --> a4["4 decomposition-coverage"] --> a5["5 contracts"] --> a6["6 recall"] end subgraph B["B · Atoms"] direction TB b1["7 atom-case-synthesis"] --> b2["8 atom-example-tests"] --> b3["9 atom-property-tests"] b3 --> b4["10 atoms"] --> b5["11 atom-verification"] --> b6["12 atom-fuzz"] b6 --> b7["13 atom-mutation"] --> b8["14 anti-patterns"] --> b9["15 atom-optimization"] b9 --> b10["16 atom-complexity"] --> b11["17 atom-documentation"] end subgraph C["C · Molecules"] direction TB c1["18 composition-obligations"] --> c2["19 molecule-tests"] c2 --> c3["20 molecules"] --> c4["21 molecule-verification"] end subgraph D["D · Control flow"] direction TB d1["22 control-obligations"] --> d2["23 control-tests"] d2 --> d3["24 control-flow"] --> d4["25 path-coverage"] end subgraph E["E · Program"] direction TB e1["26 assembly"] --> e2["27 program"] --> e3["28 integration-tests"] --> e4["29 end-to-end-tests"] end subgraph F["F · Verification depth"] direction TB f1["30 global-invariants"] --> f2["31 adversarial"] --> f3["32 repetition"] f3 --> f4["33 platform-matrix"] --> f5["34 non-functional"] end subgraph G["G · Delivery"] direction TB g1["35 evidence-bundle"] --> g2["36 human-acceptance"] --> g3["37 deliver"] end a6 --> b1 b11 --> c1 c4 --> d1 d4 --> e1 e4 --> f1 f5 --> g1 ``` 阶段编号决定了流程顺序;它们 **不是** 标识。插入一个 阶段会使其后的每个数字移位,这就是为什么账本在阶段编号旁边 记录阶段名称的原因。数字回答了“这进行到哪了”;只有名称 才能回答“这是哪个检查”。标签:AI工具, AI编程助手, EVTX分析, Go语言, Python工具, SOC Prime, 代码安全沙箱, 开发工具, 日志审计, 本地优先, 程序破解, 自动化代理