人机协作控制面¶
控制面通过 AntiShortcutSkill.control 组织 Diff、任务看板、Goal、权限和本地维护任务;
文件写入、命令执行和阶段推进仍经过原来的拦截器、校验器和五道防线。
默认工作区保持现有工具行为;创建权限策略后,未认证会话一律拒绝。
未初始化时不缓存写前 Diff,任务写操作和 Goal 管理也不可用;状态查询仍兼容旧工作区。
Task Board 不会推进阶段,Goal 只能在未开始的初始状态或干净交付后绑定新循环。
启动与身份¶
pip install 'phase-barrier[tui]'
anti-shortcut permissions-init --workspace .
permissions-init 是可信本地初始化命令,输出一次人工 admin 令牌;策略存在后不能重新初始化。
将令牌放入 PHASE_BARRIER_SESSION_TOKEN,不要提交到仓库,也不要交给 Agent。
CLI 从这个环境变量取令牌,HTTP 使用 Authorization: Bearer <token>,gRPC 使用
authorization metadata。服务端只存令牌的 SHA-256;令牌绑定角色、会话 ID、
actor(human / agent)、过期时间,客户端不能自行声明角色。
anti-shortcut control session_issue --data '{"role":"worker","actor":"agent"}'
anti-shortcut control session_issue --data '{"role":"observer","actor":"human"}'
anti-shortcut sidecar --workspace . --host 127.0.0.1 --port 8080
anti-shortcut tui --url http://127.0.0.1:8080
命令示例使用 POSIX shell 的 JSON 引号;PowerShell 可用单引号包围同样的 JSON。
新令牌默认 24 小时有效,ttl 可指定 1–604800 秒。
撤销会话:control session_revoke --data '{"session_id":"..."}'。
admin 仅允许人工身份;发令牌、改策略和紧急授权都要求人工 admin。
| 角色 | 能力 |
|---|---|
| observer | 查询状态、证据、审计、diff、任务与 Goal |
| worker | 上述 + 受阶段约束的写入/执行/推进、捕获/认领/完成任务 |
| maintainer | 上述 + 任务排队/丢弃、Goal 管理;人工身份可复核和配置调度 |
| admin | 上述 + 人工会话管理、权限策略管理、一次性授权 |
进程内使用 AntiShortcutSkill(..., session_token=token) 或
PhaseBarrier(..., session_token=token);HTTP 客户端使用 GateClient(url, token=token)。
在进程内拥有 Python 对象和文件系统权限的代码仍属于可信代码;部署隔离边界与
sidecar 部署一致,Agent 不应拥有门禁目录、服务端令牌或进程访问权。
权限策略与人工 Diff 复核¶
.agent_gate/permissions.yaml 示例(经 control policy_update 的 policy 参数提交):
version: 1
roles:
observer: [read_state, read_evidence, read_diff, read_audit, read_tasks, read_goals]
write_paths:
worker: ['spec.md', 'src/*', 'tests/*']
review_writes: ['spec.md', 'src/*']
rate_limits:
write_file: 60
省略角色采用内置权限;显式角色列表只能缩小权限;空列表拒绝该角色全部操作。
路径使用工作区相对 POSIX 路径和 fnmatch 模式,* 可跨目录。
空白、绝对路径、反斜杠、盘符、./.. 路径段与未闭合字符类均视为配置错误,
更新时拒绝;已落盘的非法策略按损坏策略处理。合法但拼错的范围只会不匹配,不会回退放行。
策略损坏或初始化标记存在而策略缺失时拒绝访问。
速率限制按会话/操作在 SQLite 中计数,窗口为 60 秒。
write_file 在阶段检查通过后、落盘前计算 unified diff,缓存到
.agent_gate/diff/latest.json,复核队列持久化在 tasks.db。
文本差异含新增文件、原内容与目标内容哈希、阶段、会话、Goal 和里程碑上下文。
二进制文件显示摘要;超过 2 MiB 的文件仅缓存哈希和提示,不生成完整可视化。
需要复核的写入返回拒绝,原文件保持原状;人工决定后由调用者重试原写入。
anti-shortcut control diff_decide --data '{"review_id":"...","approved":true,"reason":"已核对接口"}'
批准仅用于对应会话、内容、旧文件、阶段循环,成功写入后消费。 内容修改、其他会话、原文件变化或阶段变化都要求重新复核。 驳回的内容须修改后重新提交。需要复核的目标不能通过已识别的 shell 写操作修改。 所有门禁目录写入在插件规则之前被拒绝。
紧急授权采用受限的权限委托:人工 admin 可调用 break_glass_issue,参数为
path、session_id、reason、ttl(最多 900 秒);目标会话以
GateClient.write_file(..., break_glass=token) 使用。令牌只允许一次、一个文件、一个会话,
仍须通过阶段、目录与人工 Diff 复核;不会跳过证据,也不允许写门禁内部文件。
令牌在尝试写入前消费,后续失败也不会恢复;颁发与消费都有 permission.break_glass* 审计。
TUI / Web¶
TUI 显示阶段 0–6、防线状态、任务看板、Goal 进度、Diff 和统一事件流。
按 s 切换 unified/split,q 退出。它通过 sidecar API 获取快照,增量订阅
GET /api/events?cursor=<byte-offset>,不会直接打开工作区状态文件。
事件包包含 cursor、type、timestamp、data,包括 tool.start、tool.complete、
tool.blocked、stage.changed、write.preview、human_input_required 和控制面审计事件。
唯二可写的 UI 动作是人工复核批准/驳回(diff 或交付复核)和 btw 任务认领。 操作由服务端再次鉴权。输入对应复核 ID 和理由,或队列任务 ID 后点击操作即可; 复核通过不会自动写入或推进阶段。Goal 创建和权限管理使用 CLI/API。 交付复核复用现有审批文件,驳回会撤销同 request ID 的旧批准。 Goal 不同里程碑的交付复核 ID 相互隔离。
安全承诺与已知残余风险¶
完整案例及复现命令见控制面安全验证。
| 类别 | 承诺与边界 |
|---|---|
| 机制保证 | 7 个 break-glass 红队案例验证文件/会话绑定、过期、复用、落盘失败后消费、目录与阶段约束;授权不授予推进阶段能力。 |
| 机制保证 | SQLite 事务强制任务跳转与唯一认领;btw 完成须显式回主流程;stale 只加标记。 |
| 机制保证 | Goal 的最后里程碑也先聚合状态和清单证据再标记完成;abandon 保留原状态及文件。 |
| 机制保证 | 已启用权限的 API 在服务端检查身份、角色、人工身份、到期与撤销;直接请求不降低要求。 |
| 机制保证 | TUI 仅有两类写动作:复核决定与 btw 认领;三个按钮为批准、驳回、认领,无直接阶段修改入口。 |
| 依赖人工 | DoD 只校验为非空文本列表;自然语言是否客观、需求是否实现、复核是否充分,需人评估。 |
| 已知残余风险 | textual serve 使用进程环境中的单一令牌,所有浏览器连接代表同一身份。远程部署必须另设身份认证、TLS 和访问隔离,不可直接公开管理员进程。 |
| 已知残余风险 | 拥有服务端 Python 对象、门禁目录写权限或进程访问权的代码属于可信边界内;本库不提供操作系统沙箱。shell 路径识别仍为启发式,write_audit 仅检测。 |
| 已知残余风险 | 调度租约依赖本机时间;崩溃或租约过期后可能重试,不承诺 exactly-once,不会自动推进阶段。 |
一次性授权在策略、身份及目标绑定检查通过后先消费,再做阶段、Goal、Diff 检查与落盘。 匹配令牌在这些后续检查或写入失败后不可恢复;错误路径/其他会话不会窃取消费令牌。 传参非法或目标不是文件时,代理可在进入授权路径前拒绝。控制面红队当前无逃逸豁免; 上述部署和观测限制不等同于允许测试逃逸。
Web 复用同一应用,无独立前端:
textual serve "python -m anti_shortcut.control.tui"
通过 PHASE_BARRIER_URL 和 PHASE_BARRIER_SESSION_TOKEN 配置服务端地址和会话。
Web 进程令牌代表全部浏览器连接,因此远程部署时应由外层认证保护该 Web 实例,
按身份分开部署。HTTP API 支持沿用 sidecar mTLS。
textual-diff-view 当前要求 Python ≥3.11(并使用 AGPL-3.0 许可),只作为 TUI
可选依赖安装;核心包不导入它。Python 3.10 使用 Rich/Pygments unified diff 回退,
无 split 视图。Textual 和 diff 插件均不成为核心强制依赖。
Task Board¶
anti-shortcut task capture --type btw --title '顺便修正文档 typo'
anti-shortcut task list
anti-shortcut task queue --task-id <id> # maintainer/admin
anti-shortcut task claim --task-id <id> # worker 或人工认领
anti-shortcut task complete --task-id <id> --return-to-main
SQLite 强制 captured → queued → active → done,未完成任务也可由有权限的认领者丢弃。
并发认领只允许一个会话成功;人工认领记录 human_owned,其他会话不能完成或丢弃。
btw 完成必须显式 --return-to-main,记录审计。stale 是独立标记,避免破坏原状态机;
只标记长期无人处理的 captured/queued btw,不自动完成、丢弃或抢占活跃任务。
所有状态转换与阶段状态机独立,认领 btw 不赋予额外文件写入或阶段权限。
Goal 多阶段循环¶
anti-shortcut goal create --title '重构模块' --done '回归测试全部通过' \
--milestone '重构接口' --milestone '迁移调用方'
anti-shortcut goal status
anti-shortcut goal pause --goal-id <id>
anti-shortcut goal resume --goal-id <id>
anti-shortcut goal next --goal-id <id>
DoD 和里程碑必须是非空文本列表;调用者负责提供客观可判定的条件。
每个里程碑从阶段 0 开始;必须经过完整校验、交付测试新鲜且全绿、证据清单完整后,
才允许 next。最后一次 next 聚合最后里程碑证据并完成 Goal。
每次循环在签名状态里保留旧状态,在 Goal 中聚合 manifest 与阶段证据,
新循环清除上次测试结果。完成状态表示阶段证据通过,DoD 的自然语言含义仍需人评估。
暂停阻止写入、命令执行和阶段推进;恢复不重置当前循环,可跨会话继续。
绑定循环时先持久化 Goal 意图,进程中断后用 resume 恢复未完成的绑定。
同一工作区只允许一个未结束 Goal,不能创建 Goal 覆盖阶段 2–5 的现有工作。
abandon 留存原阶段证据并停止该 Goal,不提供丢弃未交付证据的状态重置捷径。
Sidecar 定时维护¶
人工 maintainer/admin 通过 control schedule_update --data '{"config": ...}' 设置
.agent_gate/schedule.yaml,然后重启 sidecar。调度器仅随 sidecar 主进程启动,
Agent API 没有运行、启动、停止调度器的方法。
version: 1
jobs:
evidence_integrity_check: {interval_seconds: 3600}
residual_expiry_check: {interval_seconds: 86400}
btw_stale_cleanup: {interval_seconds: 86400, stale_days: 30}
goal_health_report: {interval_seconds: 86400}
red_team_fast: {interval_seconds: 604800, enabled: false}
采用标准库线程循环、持久化下次运行时间与 SQLite 执行租约;重启不重置已持久化周期, 失败写审计并等待下次周期重试。各任务不会修改阶段状态:
| 任务 | 行为 |
|---|---|
| evidence_integrity_check | 重载并验证状态签名、证据清单与文件哈希 |
| residual_expiry_check | 检查当前工作区 benchmarks/red_team/known_residual.yaml 过期项 |
| btw_stale_cleanup | 标记过期且未认领的 btw |
| goal_health_report | 输出 .agent_gate/reports/goal-health.json |
| red_team_fast | 在可信源码安装树运行固定的 equivalent_op/timing_evade 子集,逃逸返回失败 |
红队任务需要安装来源包含完整源码 checkout;普通 wheel 中不存在 benchmarks 时明确失败,
不会运行工作区里同名脚本。所有任务结果写入 scheduler.completed,TUI 可见。
本地维护只处理当前工作区,GitHub Actions 继续负责跨 PR/仓库 CI。
API¶
GET /api/control 返回快照。POST /api/control 使用
{"operation":"task_capture","data":{"title":"..."}} 调用显式操作白名单。
可用操作包括 task_capture、task_transition、goal_create、goal_action、
diff_decide、review_decide、session_issue、session_revoke、policy_update、
break_glass_issue、schedule_update。初始化与调度器生命周期不在白名单中。
相同 API 可由 GateClient.control(operation, **data) 与 control CLI 调用。
所有控制面成功写操作写入既有审计日志;权限拒绝与阶段拒绝分别保留原因。