diff --git a/src/cosh-ng/docs/design/acp-gateway/README.md b/src/cosh-ng/docs/design/acp-gateway/README.md new file mode 100644 index 0000000000..de56c1a29b --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/README.md @@ -0,0 +1,241 @@ +# COSH Gateway and ACP Architecture + +[中文版](README_zh.md) + +COSH Gateway evolves cosh-ng into a local-first operations gateway for agents. +It connects Shell, CLI, Web, and messaging channels to one durable Task Plane, +runs work through replaceable Agent Runtimes, and governs real operating-system +effects through a shared security boundary. + +This document is the long-lived architecture baseline for that evolution. +Delivery may be incremental, but implementations must preserve the identity, +durability, Runtime, and authority boundaries defined here. + +This document describes target architecture and durable invariants. It does not +claim that every module is available. Current behavior is defined by source, +component READMEs, and user documentation. + +Companion decisions and designs: + +- [ACP v1 integration decision](acp-v1-decision.md) +- [Rust 1.88 toolchain decision](rust-1.88-decision.md) +- [Task and Runtime model](task-runtime-model.md) +- [Durable Task Plane](durable-task-plane.md) +- [Capability and execution](capability-execution.md) +- [Runtime security boundary](runtime-security.md) +- [Adapter conformance](adapter-conformance.md) + +## Positioning + +COSH Gateway is the control plane between user entry points, Agent Runtimes, +and GuestOS execution. `cosh-shell` is a privileged entry point and Task +attachment; it does not own durable tasks, agent sessions, or governance state. + +This positioning enables: + +1. CLI, Shell, Web, and chat clients to act on the same durable Task. +2. Codex, Claude Code, cosh-core, and future on-device agents to share one + Runtime boundary. +3. Every requested system operation to pass through COSH identity, approval, + capability, and audit controls. + +## Architecture principles + +- **Task is the durable control unit.** A Session or process is a resource of + one Run, not the source of product state. +- **Ingress does not own execution.** Channel adapters translate messages and + presentation; they do not start agents or execute commands directly. +- **Runtime is replaceable.** Gateway depends on `AgentRuntimePort`; ACP and + cosh-core are separate implementations. +- **Effects share one governance boundary.** Shell, Skill, MCP, ACP tools, and + typed operators must not bypass the Capability Broker. +- **Events precede views.** Terminal cards, Web views, and chat messages derive + from durable events and projections. +- **Local first.** The default deployment uses a local daemon and stdio agents; + remote control reuses the same Task and authority semantics. +- **Disconnect is recoverable.** Commands are idempotent, events replayable, + and executions leased. A client disconnect is not a Task cancellation. + +## Target architecture + +```mermaid +flowchart TB + subgraph Channels["User entry points"] + SHELL["cosh-shell"] + CLI["CLI / API"] + WEB["Web / Web Shell"] + CHAT["DingTalk / Feishu"] + end + + subgraph Gateway["COSH Gateway"] + ADAPTER["Channel Adapters"] + ID["Identity / RBAC / Idempotency"] + TASK["Task Plane\nTask / Run / Event / Outbox"] + APPROVAL["Approval Service"] + RUNTIME["AgentRuntimePort"] + end + + subgraph Agents["Agent Runtime"] + CORE["CoshCoreBridge"] + ACP["ACP v1 Client Bridge"] + LOCAL["Local Model Adapter"] + EXT["Codex / Claude Code / other agents"] + end + + subgraph Governance["OS governance and execution"] + CAP["Capability Broker"] + OPS["Skills / MCP / Typed Operators"] + AUDIT["Audit / Evidence / Checkpoint"] + TARGET["Local GuestOS / ECS"] + end + + SHELL --> ADAPTER + CLI --> ADAPTER + WEB --> ADAPTER + CHAT --> ADAPTER + ADAPTER --> ID --> TASK + TASK --> APPROVAL + TASK --> RUNTIME + RUNTIME --> CORE + RUNTIME --> ACP + RUNTIME --> LOCAL + ACP <-->|"ACP v1 over stdio"| EXT + CORE --> CAP + ACP --> CAP + LOCAL --> CAP + APPROVAL --> CAP + CAP --> OPS --> TARGET + CAP --> AUDIT +``` + +## Layer responsibilities + +| Layer | Owns | Does not own | +| --- | --- | --- | +| Channel Adapter | Message translation, thread correlation, presentation, approval input | Task state, agent lifecycle, OS execution | +| Gateway API | Identity, authorization, idempotency, input bounds, local or remote transport | Provider protocols and command execution | +| Task Plane | Task/Run lifecycle, Event, Outbox, leases, recovery, replay | Provider-private output parsing | +| AgentRuntimePort | Start, prompt, cancel, events, and terminal semantics | Durable Tasks and channel delivery | +| ACP Client Bridge | ACP negotiation, Session, updates, permission requests, error mapping | Task, Channel, or OS authorization protocol | +| Approval Service | Durable approval, expiry, one-time decisions, receipts | Arbitrary OS authorization | +| Capability Broker | Actor, Target, Operation, Scope, and Permit binding | User interface and agent sessions | +| Execution Target | Execute an authorized typed operation and return evidence | Expand authority or rewrite Task decisions | + +## Capability profiles and portability + +A Gateway capability profile is an admission-time manifest of the governed +operations and trusted `ExecutionTarget` providers available to a daemon. It is +separate from an Agent Runtime profile: selecting Codex, Claude, or cosh-core +does not implicitly install checkpoint, shell, or filesystem authority. + +The target architecture defines at least these profiles: + +| Profile | Governed operation inventory | Platform dependency | Status | +| --- | --- | --- | --- | +| `task-only-v1` | None; Task, approval, cancellation, input, retry, and observation remain available | No checkpoint provider | Target design; not implemented yet | +| `ws-ckpt-v1` | Typed workspace checkpoint creation through the Capability Broker | Linux and an admitted `ws-ckpt` service, socket, and workspace identity | Initial Phase 1 implementation slice | + +Profile selection follows these rules: + +- the operator selects one profile before the daemon binds its command socket; +- a Task or Runtime cannot select a provider or widen the admitted inventory; +- the Runtime handshake advertises exactly the tools enabled by the profile; +- a missing optional provider removes its capability, not its security checks; +- requesting an unavailable operation fails before Approval or Permit issuance; +- Gateway never falls back to provider-native execution, a local copy, or an + ungoverned shell operation. + +This makes `ws-ckpt` a pluggable execution provider rather than a permanent +Gateway dependency. The current implementation still admits only the +checkpoint-enabled production slice; making `task-only-v1` selectable is a +separate implementation and acceptance task. + +Issue-sized implementation slices are: + +| Slice | Deliverable | Acceptance | +| --- | --- | --- | +| Capability profile contract | Versioned profile ID, closed operation manifest, and stable digest | Unknown profiles and inventory mismatch fail before Task admission | +| Portable admission | Explicit `task-only-v1` daemon mode with no checkpoint arguments or connection | Task submit/get/events/cancel/input/retry work; checkpoint is absent and rejected | +| Target provider registry | Trusted startup registration keyed by operation version and target kind | Task and Runtime input cannot select or replace a provider | +| `ws-ckpt` provider extraction | Move the existing checkpoint path behind the common target registry | Existing Permit, audit, typed-result, uncertainty, and replay tests stay green | +| Durable profile binding | Persist the admitted profile identity for scheduling, retry, and recovery | Restart never substitutes a provider or changes a Run inventory | +| Platform matrix | Linux `ws-ckpt-v1` evidence plus portable-profile evidence on each supported host family | Unsupported hosts reject only `ws-ckpt-v1`; no silent downgrade or false tool advertisement | + +Each slice can be reviewed independently. `task-only-v1` is complete only when +the no-`ws-ckpt` startup and negative checkpoint tests exercise the production +binary, not only an injected unit-test driver. + +## Core objects + +| Object | Meaning | +| --- | --- | +| `Task` | Durable work unit that users can query, reconnect to, and audit | +| `Run` | One Task attempt with its own Runtime and lease | +| `SessionBinding` | Mapping between a COSH Run and an external agent Session | +| `Event` | Append-only fact used for reduction and client replay | +| `Approval` | Durable user or policy decision for one operation | +| `Permit` | Single-use authority bound to Actor, Target, Operation, and Scope | +| `Execution` | The actual effect and its result, error, and evidence references | +| `Attachment` | A Shell, Web, or chat relationship to a Task | + +These identifiers are not interchangeable. In particular, an ACP Session ID +must not be used as a Task ID, and process exit does not prove a durable Task +completed reliably. + +## Main flow + +```text +Ingress submits intent + -> Gateway authenticates and checks idempotency + -> create Task and scheduling event + -> Worker acquires Run lease + -> AgentRuntimePort starts Runtime + -> Runtime facts commit atomically to Event/Projection/Outbox + -> sensitive operation enters Approval and Capability Broker + -> Execution Target consumes Permit once + -> result and evidence update Task + -> Attachments replay or continue from cursors +``` + +## Security boundaries + +- The daemon uses a private local endpoint by default. Remote listeners require + a separate authentication model and threat model. +- External agents are untrusted Runtime principals. They must not read Gateway + storage, connect as an operator, or inherit host root authority. +- ACP capability negotiation describes protocol support; it does not grant an + OS capability. +- Permission requests without exact Task, Run, Actor, Target, Operation, and + digest correlation fail closed. +- Timeout, crash, or transport loss with an uncertain effect requires + reconciliation or operator action; it is never retried blindly. +- Audit records contain bounded structured summaries and evidence references, + not credentials or unbounded raw output. + +## Delivery streams + +| Stream | Deliverable | Completion condition | +| --- | --- | --- | +| Foundation contracts | Rust 1.88, Task/Run/Event types, `AgentRuntimePort`, errors, identity | Side-effect-free types, explicit versions, independent tests | +| Local Task Plane | Daemon, worker, Outbox, Run lease, recovery, event replay | Tasks survive disconnect and restart or settle deterministically | +| ACP Runtime | ACP v1 bridge, versioned Codex/Claude adapters, cancellation, conformance | Adapters share one Runtime contract and terminal semantics | +| Approval and execution | Approval, Broker, Permit, Execution, audit correlation | Effects are traceable, denied paths do not execute, Permit is single-use | +| Shell Attachment | Submit, observe, replay, approve, cancel, detach/reattach | Interactive Shell and durable Task coexist without a second state machine | +| Channel Adapter | Web or messaging identity, idempotency, delivery | Channels do not own agents or OS execution and recover after disconnect | +| GuestOS expansion | ECS Target, checkpoint, rollback, on-device agents | Reuse the same capability and audit model | + +Shared contracts stabilize before their producers and consumers. Modules +communicate only through versioned commands, events, and ports. + +## Contributing + +Contributors can work independently on Runtime adapters, Task storage, +approval, Shell attachment, channel adapters, or conformance tests. Each change +must: + +- name the architecture boundary it implements; +- keep provider and channel-private types out of core contracts; +- test new commands, events, transitions, and error paths; +- fail closed on authority, cancellation, crash recovery, and effect replay; +- preserve existing Shell and cosh-core paths during incremental migration; +- update an ADR when a boundary changes and user docs when behavior ships. diff --git a/src/cosh-ng/docs/design/acp-gateway/README_zh.md b/src/cosh-ng/docs/design/acp-gateway/README_zh.md new file mode 100644 index 0000000000..c788441939 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/README_zh.md @@ -0,0 +1,214 @@ +# COSH Gateway 与 ACP 架构 + +[English](README.md) + +COSH Gateway 将 cosh-ng 扩展为本地优先的 Agent 运维网关。它把 Shell、CLI、Web 和 +消息渠道接入同一个持久 Task Plane,通过可替换的 Agent Runtime 处理任务,并由统一的 +OS 治理层约束真实环境中的副作用。 + +本文是 Gateway 演进的长期架构基线。实现可以分阶段推进,但不得破坏这里定义的身份、 +持久性、Runtime 和权限边界。 + +本文描述目标架构和长期不变量,不表示所有模块已经可用。实际能力以当前源码、组件 +README 和用户文档为准。 + +配套决策: + +- [ACP v1 接入决策](acp-v1-decision_zh.md) +- [Rust 1.88 工具链决策](rust-1.88-decision_zh.md) +- [Task 与 Runtime 模型](task-runtime-model_zh.md) +- [持久 Task Plane](durable-task-plane_zh.md) +- [Capability 与执行](capability-execution_zh.md) +- [Runtime 安全边界](runtime-security_zh.md) +- [Adapter 验收](adapter-conformance_zh.md) + +## 定位 + +COSH Gateway 是连接用户入口、Agent Runtime 和 GuestOS 执行面的控制平面。 +`cosh-shell` 是高权限入口和 Task Attachment,不独占会话、任务或治理状态。 + +该定位解决三个问题: + +1. CLI、Shell、Web 和聊天工具可以操作同一项持久任务。 +2. Codex、Claude Code、cosh-core 和后续端侧 Agent 可以通过统一 Runtime 边界接入。 +3. Agent 提出的系统操作必须经过 COSH 的身份、审批、Capability 和审计边界。 + +## 架构原则 + +- **Task 是持久控制单元。** Session 和进程只是一次 Run 的运行资源。 +- **入口不拥有执行权。** Channel Adapter 只转换消息和展示,不直接启动 Agent 或执行命令。 +- **Runtime 可替换。** Gateway 依赖 `AgentRuntimePort`,ACP 和 cosh-core 是不同实现。 +- **副作用统一治理。** Shell、Skill、MCP、ACP Tool 和 Typed Operator 不得绕过 Capability Broker。 +- **事件先于界面。** Terminal card、Web 页面和聊天消息都由持久事件与 Projection 生成。 +- **本地优先。** 默认部署使用本机 daemon 与 stdio Agent;远程控制复用相同 Task 和权限语义。 +- **弱网可恢复。** 请求幂等、事件可重放、执行有租约,断线不等于取消任务。 + +## 目标架构 + +```mermaid +flowchart TB + subgraph Channels["用户入口"] + SHELL["cosh-shell"] + CLI["CLI / API"] + WEB["Web / Web Shell"] + CHAT["钉钉 / 飞书"] + end + + subgraph Gateway["COSH Gateway"] + ADAPTER["Channel Adapters"] + ID["Identity / RBAC / Idempotency"] + TASK["Task Plane\nTask / Run / Event / Outbox"] + APPROVAL["Approval Service"] + RUNTIME["AgentRuntimePort"] + end + + subgraph Agents["Agent Runtime"] + CORE["CoshCoreBridge"] + ACP["ACP v1 Client Bridge"] + LOCAL["Local Model Adapter"] + EXT["Codex / Claude Code / 其他 Agent"] + end + + subgraph Governance["OS 治理与执行"] + CAP["Capability Broker"] + OPS["Skills / MCP / Typed Operators"] + AUDIT["Audit / Evidence / Checkpoint"] + TARGET["Local GuestOS / ECS"] + end + + SHELL --> ADAPTER + CLI --> ADAPTER + WEB --> ADAPTER + CHAT --> ADAPTER + ADAPTER --> ID --> TASK + TASK --> APPROVAL + TASK --> RUNTIME + RUNTIME --> CORE + RUNTIME --> ACP + RUNTIME --> LOCAL + ACP <-->|"ACP v1 over stdio"| EXT + CORE --> CAP + ACP --> CAP + LOCAL --> CAP + APPROVAL --> CAP + CAP --> OPS --> TARGET + CAP --> AUDIT +``` + +## 分层职责 + +| 层级 | 负责 | 不负责 | +|------|------|--------| +| Channel Adapter | 消息转换、线程关联、状态展示、审批输入 | Task 状态机、Agent 生命周期、OS 执行 | +| Gateway API | 身份、授权、幂等、输入边界、本地或远程传输 | Provider 协议和命令执行 | +| Task Plane | Task/Run 生命周期、Event、Outbox、租约、恢复和重放 | 解析 Provider 私有输出 | +| AgentRuntimePort | 启动、Prompt、Cancel、事件和终态的统一语义 | 持久任务和渠道投递 | +| ACP Client Bridge | ACP 协商、Session、更新、权限请求和错误映射 | 充当 Task、Channel 或 OS 权限协议 | +| Approval Service | 持久审批、超时、一次性决策和回执 | 直接授权任意系统操作 | +| Capability Broker | 绑定 Actor、Target、Operation、Scope 和 Permit | 用户界面和 Agent 会话 | +| Execution Target | 在本机或 ECS 执行已授权操作并返回证据 | 自行扩大权限或修改 Task 决策 | + +## Capability Profile 与可移植性 + +Gateway capability profile 是 daemon admission 时确定的 manifest,列出可用的 governed +operation 与可信 `ExecutionTarget` provider。它与 Agent Runtime profile 相互独立:选择 +Codex、Claude 或 cosh-core,不会隐式安装 checkpoint、shell 或 filesystem authority。 + +目标架构至少定义以下 profile: + +| Profile | Governed operation inventory | 平台依赖 | 状态 | +| --- | --- | --- | --- | +| `task-only-v1` | 无副作用 operation;Task、approval、cancel、input、retry 与 observation 仍可用 | 不依赖 checkpoint provider | 目标设计,尚未实现 | +| `ws-ckpt-v1` | 通过 Capability Broker 执行 typed workspace checkpoint create | Linux,以及通过 admission 的 `ws-ckpt` service、socket 与 workspace identity | Phase 1 首个实现切片 | + +Profile selection 遵循以下规则: + +- operator 在 daemon 绑定 command socket 前选择 profile; +- Task 或 Runtime 不能选择 provider,也不能扩大 admitted inventory; +- Runtime handshake 只发布该 profile 启用的 tool; +- optional provider 缺失时移除相应 capability,不移除安全检查; +- unavailable operation 在 Approval 或 Permit 签发前失败; +- Gateway 不得 fallback 到 provider-native execution、local copy 或 ungoverned shell。 + +因此,`ws-ckpt` 是可插拔 execution provider,不是 Gateway 永久依赖。当前实现仍只接纳 +checkpoint-enabled production slice;让 `task-only-v1` 可选择属于独立的实现与验收任务。 + +可以按以下粒度拆分 Issue: + +| 切片 | 交付内容 | 验收标准 | +| --- | --- | --- | +| Capability profile contract | 有版本的 profile ID、封闭 operation manifest 与稳定 digest | Unknown profile 与 inventory mismatch 在 Task admission 前失败 | +| Portable admission | 显式 `task-only-v1` daemon mode,不需要 checkpoint 参数或连接 | Task submit/get/events/cancel/input/retry 可用;checkpoint 不暴露且明确拒绝 | +| Target provider registry | 按 operation version 与 target kind 注册可信 startup provider | Task 与 Runtime input 不能选择或替换 provider | +| `ws-ckpt` provider extraction | 把现有 checkpoint path 迁入公共 target registry | 既有 Permit、audit、typed-result、uncertainty 与 replay test 保持通过 | +| Durable profile binding | 为 scheduling、retry 与 recovery 持久化 admitted profile identity | Restart 不替换 provider,也不改变 Run inventory | +| Platform matrix | Linux `ws-ckpt-v1` evidence,以及各 supported host family 的 portable-profile evidence | Unsupported host 只拒绝 `ws-ckpt-v1`,不 silent downgrade 或错误发布 tool | + +每个切片可以独立 review。只有 production binary 完成无 `ws-ckpt` 启动与 checkpoint negative +test,`task-only-v1` 才算完成,不能只依赖 injected unit-test driver。 + +## 核心对象 + +| 对象 | 语义 | +|------|------| +| `Task` | 用户可查询、重连和审计的持久工作单元 | +| `Run` | Task 的一次执行尝试,拥有独立 Runtime 和租约 | +| `SessionBinding` | COSH Run 与外部 Agent Session 的映射 | +| `Event` | 只追加的事实记录,用于状态归约和客户端重放 | +| `Approval` | 用户或策略对特定操作的持久决策 | +| `Permit` | 绑定 Actor、Target、Operation 和 Scope 的一次性执行凭证 | +| `Execution` | 实际副作用及其结果、错误和证据引用 | +| `Attachment` | Shell、Web 或聊天线程对 Task 的观察或控制关系 | + +这些 ID 不得互相替代。尤其不能把 ACP Session ID 当作 Task ID,也不能把进程退出 +当作持久任务已经可靠完成。 + +## 主流程 + +```text +入口提交意图 + -> Gateway 鉴权与幂等校验 + -> 创建 Task 和待调度事件 + -> Worker 获取 Run Lease + -> AgentRuntimePort 启动 Runtime + -> Runtime 事件原子写入 Event/Projection/Outbox + -> 高风险操作进入 Approval 和 Capability Broker + -> Permit 被 Execution Target 单次消费 + -> 结果和证据回写 Task + -> 所有 Attachment 按 Cursor 重放或继续订阅 +``` + +## 安全边界 + +- daemon 默认使用本地私有端点;远程监听必须定义独立的认证机制和威胁模型。 +- 外部 Agent 是不可信 Runtime,不能直接获得 Gateway 数据库或宿主 root 权限。 +- ACP capability 只表示协议能力,不表示 COSH 已授予 OS 权限。 +- 未关联 Task、Run、Actor 或操作摘要的权限请求必须 fail closed。 +- 发生超时、崩溃或网络断流时,不确定副作用进入人工确认状态,不自动重试。 +- 审计记录保存结构化摘要和有界证据引用,不持久化凭证或无限原始输出。 + +## 实现路线 + +| 工作流 | 交付内容 | 完成条件 | +|--------|----------|----------| +| 基础 Contract | Rust 1.88、Task/Run/Event 类型、`AgentRuntimePort`、错误和身份模型 | 类型无副作用、版本边界明确、可以独立测试 | +| 本地 Task Plane | daemon、Task Worker、Outbox、Run Lease、恢复和事件重放 | Task 可在进程和客户端断线后继续、恢复或确定性终止 | +| ACP Runtime | ACP v1 Client Bridge、Codex/Claude Code Adapter、Cancel 和 conformance | 两个 Adapter 通过相同 Runtime Contract,错误和终态一致 | +| Approval 与执行 | Approval、Capability Broker、Permit、Execution 和审计关联 | 所有副作用可追溯,拒绝路径不执行,Permit 只能消费一次 | +| Shell Attachment | 提交、查看、回放、审批、取消和 detach/reattach | 手动 Shell 与持久 Task 共存,不引入第二套状态机 | +| Channel Adapter | Web 或消息渠道接入、身份映射、幂等和结果投递 | 渠道不直接持有 Agent 或 OS 执行权,弱网后可以续传 | +| GuestOS 扩展 | 单机到 ECS Target、Checkpoint、Rollback 和端侧 Agent | 复用同一 Capability 与审计模型,不按渠道或 Agent 分叉 | + +这些工作流可以由不同贡献者并行推进。共享 Contract 应先于其生产者和消费者稳定,模块 +之间只通过已定义的 command、event 和 port 连接。 + +## 参与开发 + +社区贡献可以从 Runtime Adapter、Task storage、Approval、Shell Attachment、Channel +Adapter 或 conformance test 中选择独立切入点。每项变更应满足以下约束: + +- 说明所实现的架构边界,不把 Provider 或渠道私有类型扩散到核心 Contract。 +- 为新增 command、event、状态迁移和错误路径提供可重复测试。 +- 对权限、取消、崩溃恢复和副作用重试采用 fail-closed 语义。 +- 保持现有 cosh-shell 和 cosh-core 路径可用,迁移通过 Port 逐步完成。 +- 架构边界变化时同步更新本文或新增 ADR,功能可用性写入用户文档。 diff --git a/src/cosh-ng/docs/design/acp-gateway/acp-v1-decision.md b/src/cosh-ng/docs/design/acp-gateway/acp-v1-decision.md new file mode 100644 index 0000000000..1b41472f0c --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/acp-v1-decision.md @@ -0,0 +1,146 @@ +# ACP v1 Integration Decision + +[中文版](acp-v1-decision_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Decision + +cosh-ng acts as an **ACP Client** for external agents, using stable wire +protocol v1 over local stdio. Version-controlled adapters connect Codex and +Claude Code to the same `AgentRuntimePort`; other agents can implement that +contract without adding provider branches to Gateway or Shell. + +Protocol and package versions are managed independently: + +- wire compatibility is negotiated through `initialize.protocolVersion`, with + stable baseline `1`; +- the initial official Rust SDK baseline is `agent-client-protocol = 2.0.0`; +- a crate major version never implies a wire version; +- ACP v2 and unstable features require separate compatibility and security + review. + +The official SDK 2.0.0 requires Rust 1.88.0 and keeps stable v1 behavior +separate from experimental v2 features. + +## Why ACP + +- Decouple COSH from private output formats of individual agent CLIs. +- Reuse standard Session, Prompt, streaming update, Cancel, and Permission + Request semantics. +- Let Codex, Claude Code, and future agents share one Task, Approval, and audit + model. +- Preserve an on-device path that does not depend on a remote control protocol. +- Concentrate provider compatibility in adapters and a conformance suite. + +## Boundary + +```text +COSH Task Plane + -> AgentRuntimePort + -> ACP v1 Client Bridge + <-> ACP Agent Adapter + -> Codex / Claude Code / other agents +``` + +ACP provides runtime interoperability. It does not own: + +- channel messages, chat threads, or cross-device connectivity; +- Task persistence, scheduling, idempotency, leases, or crash recovery; +- user identity, tenancy, RBAC, or OS capabilities; +- checkpoint, rollback, ECS management, or delivery receipts; +- a general IPC protocol between COSH components. + +ACP is therefore a Runtime replaceability boundary, not the COSH control +protocol. + +ACP Runtime selection is also independent from Gateway capability profile +selection. An admitted ACP adapter does not imply that any `ExecutionTarget` +is present. A `task-only-v1` deployment exposes no governed side-effect tool; +`ws-ckpt-v1` exposes checkpoint only through a typed hosted-operation contract +that the Runtime explicitly acknowledges. + +Provider-native ACP permission is not a fallback execution target. An adapter +without a typed hosted-result contract cannot turn `allow_once` into a COSH +Permit or satisfy a checkpoint request on behalf of `ws-ckpt`. + +## Stable capability scope + +| Capability | COSH handling | +| --- | --- | +| `initialize` | Negotiate v1 and record both implementations and capabilities | +| `session/new` | Create one explicit SessionBinding for a Run | +| `session/prompt` | Submit a bounded text task and receive one terminal result | +| Session Update | Map text, plan, tool, and status updates to Runtime events | +| Permission Request | Forward to Approval; reject when trusted correlation is absent | +| Cancel | Propagate Task cancellation and guarantee eventual process reaping | +| Error/Close | Produce deterministic Runtime terminal state with bounded diagnostics | + +Filesystem and terminal client capabilities, Session load/resume/fork, remote +HTTP transport, MCP-over-ACP, and experimental v2 features are outside this +stable baseline. Each requires an explicit data boundary, threat model, +compatibility decision, and conformance evidence. + +## Mapping invariants + +- A Task can have multiple Runs; a Run has at most one active ACP Session. +- ACP updates are normalized to provider-neutral Runtime events before they + reach a presentation layer. +- An ACP Tool Call is not execution authority. A real effect still requires + Approval and a target-bound Permit. +- A Permission Request is correlated to exact Task, Run, Actor, Target, + Operation, and canonical digest. +- Prompt completion, process exit, and transport close are separate facts; + the Runtime reducer chooses one terminal outcome. +- Unknown messages, oversized payloads, stale callbacks, and unsupported + capabilities are rejected or explicitly ignored, never downgraded to allow. + +## Adapter strategy + +- Adapter and upstream agent versions are recorded in an explicit matrix. +- Production profiles use absolute normalized paths, fixed basenames, and a + controlled environment. +- Launch clears the environment and explicitly inherits only required locale, + proxy, and authentication entry points. Dynamic loader and Node injection + variables are rejected. +- Installation, upgrade, and provenance checks are separate from Gateway + runtime; Gateway never downloads packages while starting a Task. +- Every adapter upgrade reruns fake and real conformance. + +## Conformance + +A supported adapter must: + +1. Pin adapter and agent versions and complete v1 initialize, Session creation, + and a text prompt. +2. Map text, plan, tool, permission, cancellation, and error events to stable + Runtime events. +3. Pass real `allow_once` and `reject_once`; denial produces no effect. +4. Settle timeout, cancel, crash, malformed frame, and transport close exactly + once and reap the process tree. +5. Correlate Task, Run, Session, Agent, Adapter, Approval, Execution, and error + evidence without reusing identifiers. +6. Produce redacted, repeatable evidence. + +## Compatibility and rollback + +ACP Runtime is enabled by profile. A protocol or adapter regression disables +that profile while preserving Task and audit history. Rollback does not rewrite +historic events and does not silently move a failed Run to another agent. + +Runtime and capability profiles roll back independently. Their admitted pair +must have an explicit conformance entry; Gateway never invents a new pair for +an existing Run. + +## Adding an agent + +Prefer an ACP adapter over a provider-specific branch in Gateway or Shell. A +contribution includes a version profile, installation provenance, capability +matrix, fake conformance, and at least one real-agent conformance run. +Provider-private events are normalized inside the adapter boundary. + +## References + +- [ACP versioning](https://github.com/agentclientprotocol/agent-client-protocol#versioning) +- [Official ACP Rust SDK](https://github.com/agentclientprotocol/rust-sdk) +- [Rust SDK 2.0.0 manifest](https://docs.rs/crate/agent-client-protocol/2.0.0/source/Cargo.toml) diff --git a/src/cosh-ng/docs/design/acp-gateway/acp-v1-decision_zh.md b/src/cosh-ng/docs/design/acp-gateway/acp-v1-decision_zh.md new file mode 100644 index 0000000000..ade71ee76b --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/acp-v1-decision_zh.md @@ -0,0 +1,127 @@ +# ACP v1 接入决策 + +[English](acp-v1-decision.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## 决策 + +cosh-ng 作为 **ACP Client** 接入外部 Agent,采用稳定 wire protocol v1 和本机 stdio +transport。Codex 与 Claude Code 通过版本受控的 Adapter 接入同一 +`AgentRuntimePort`,其他 Agent 可以遵循相同 Contract 扩展。 + +协议版本与 SDK 包版本分别管理: + +- wire compatibility 由 `initialize.protocolVersion` 决定,稳定基线为 `1`; +- 初始 Rust SDK 基线为 `agent-client-protocol = 2.0.0`; +- 不通过 crate 主版本推断 wire 版本; +- ACP v2 和 unstable feature 需要独立的兼容性与安全评估。 + +官方 ACP 仓库说明当前稳定协议版本为 v1,并要求以初始化协商的 +`protocolVersion` 判断 wire compatibility。官方 Rust SDK 2.0.0 的 MSRV 为 Rust +1.88.0,默认稳定能力与实验性 v2 feature 分离。 + +## 为什么使用 ACP + +- 把 COSH 与单一 Agent CLI 的私有输出格式解耦。 +- 复用标准 Session、Prompt、流式更新、Cancel 和 Permission Request 语义。 +- 让 Codex、Claude Code 和后续 Agent 共用同一 Task、Approval 和审计模型。 +- 保留端侧 Agent 接入路径,使弱网或断网场景不依赖远端控制协议。 +- 将 Provider 兼容性收敛到 Adapter 和 conformance suite,而不是分散到 Shell UI。 + +## ACP 在架构中的边界 + +```text +COSH Task Plane + -> AgentRuntimePort + -> ACP v1 Client Bridge + <-> ACP Agent Adapter + -> Codex / Claude Code / 其他 Agent +``` + +ACP 负责 Agent Client 与 Agent 之间的运行时互操作,不负责: + +- Channel 消息、聊天线程或跨设备连接; +- Task 持久化、调度、幂等、租约和崩溃恢复; +- 用户身份、租户、RBAC 或 OS Capability; +- Checkpoint、Rollback、ECS 管理和投递回执; +- COSH 内部组件之间的通用 IPC。 + +因此 ACP 是 **Runtime 可替换性边界**,不是 COSH 整体控制协议。 + +ACP Runtime selection 与 Gateway capability profile selection 也相互独立。接纳 ACP +adapter 不表示任何 `ExecutionTarget` 已存在。`task-only-v1` deployment 不暴露 governed +side-effect tool;`ws-ckpt-v1` 只通过 Runtime 明确确认的 typed hosted-operation contract +暴露 checkpoint。 + +Provider-native ACP permission 不是 fallback execution target。没有 typed hosted-result +contract 的 adapter 不能把 `allow_once` 变成 COSH Permit,也不能替代 `ws-ckpt` 完成 +checkpoint request。 + +## 稳定能力范围 + +| 能力 | COSH 处理方式 | +|------|---------------| +| `initialize` | 必须协商 v1,记录双方 capability 和实现版本 | +| `session/new` | 每个 Run 建立明确 SessionBinding | +| `session/prompt` | 提交有界文本任务并接收终态 | +| Session Update | 映射文本、计划、工具调用和状态更新为 COSH Runtime Event | +| Permission Request | 转入 Approval Service;缺少可信关联时拒绝 | +| Cancel | 从 Task 取消传播到 ACP,并保证子进程最终回收 | +| Error/Close | 映射为确定性 Runtime 终态,保留有界诊断 | + +filesystem、terminal client capability、Session load/resume/fork、远程 HTTP transport、 +MCP-over-ACP 和 v2 实验能力不属于稳定基线。引入这些能力时,需要补充数据边界、威胁 +模型、兼容性和 conformance 证据。 + +## 映射约束 + +- 一个 Task 可以有多个 Run;一个 Run 在任一时刻至多绑定一个活动 ACP Session。 +- ACP Session Update 必须先转换成 provider-neutral Runtime Event,不能直接写入渠道 UI。 +- ACP Tool Call 不是执行授权。真正副作用仍需 Approval 和 target-bound Permit。 +- Permission Request 必须关联 Task、Run、Actor、Target、Operation 和 canonical digest。 +- Prompt 完成、进程退出和传输关闭是不同事实,由 Runtime reducer 决定唯一终态。 +- 未知消息、越界 payload、无关联回调和不支持的 capability 必须明确拒绝或忽略,不能 + 自动降级为允许。 + +## Adapter 策略 + +- Adapter 版本与上游 Agent CLI 版本进入显式兼容矩阵。 +- 生产 Profile 使用规范化绝对路径、固定 basename 和受控环境变量。 +- 启动时清理环境,再显式继承运行所需的 locale、代理和认证入口;禁止继承动态加载和 + Node 注入变量。 +- Adapter 安装、升级和来源校验由独立流程负责,Gateway 运行时不临时下载包。 +- 每次升级必须重新执行 fake conformance 和真实 Adapter conformance。 + +## Conformance 要求 + +一个 Adapter 只有满足以下条件,才能作为受支持的 COSH Runtime 发布: + +1. 固定 Adapter 与 Agent CLI 版本,完成 v1 初始化、建会话和文本任务。 +2. 文本、计划、工具、权限、取消和错误事件能稳定映射到 Runtime Event。 +3. `allow_once` 与 `reject_once` 真实端到端通过,拒绝路径不会产生副作用。 +4. timeout、cancel、crash、malformed frame 和 transport close 都产生确定性终态并回收进程。 +5. Task、Run、Session、Agent、Adapter、Approval、Execution 和错误证据可以关联审计。 +6. conformance 证据脱敏,并且可以在 CI 或受控环境重复执行。 + +## 兼容与回滚 + +ACP Runtime 通过 Profile 启用。发生协议或 Adapter 回归时,禁用对应 Profile 并保留 +Task 和审计数据,其他 Runtime 实现继续工作。回滚不修改已持久化的历史事件,也不把 +失败 Run 自动迁移到另一个 Agent。 + +Runtime profile 与 capability profile 独立 rollback。两者的 admitted pair 必须有显式 +conformance entry;Gateway 不为已有 Run 临时构造新的组合。 + +## 扩展新的 Agent + +新增 Agent 集成应优先提供 ACP Adapter,而不是在 Gateway 或 Shell 中增加 Provider 私有 +分支。贡献需要包含版本 Profile、安装来源校验、capability matrix、fake conformance 和 +至少一次真实 Agent conformance。Provider 特有事件在 Adapter 内归一化,核心 Runtime +只接收公共 command、event 和 error。 + +## 参考 + +- [ACP 版本规则](https://github.com/agentclientprotocol/agent-client-protocol#versioning) +- [ACP 官方 Rust SDK](https://github.com/agentclientprotocol/rust-sdk) +- [Rust SDK 2.0.0 manifest](https://docs.rs/crate/agent-client-protocol/2.0.0/source/Cargo.toml) diff --git a/src/cosh-ng/docs/design/acp-gateway/adapter-conformance.md b/src/cosh-ng/docs/design/acp-gateway/adapter-conformance.md new file mode 100644 index 0000000000..23b8b4ac7e --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/adapter-conformance.md @@ -0,0 +1,150 @@ +# Adapter Lifecycle and Conformance + +[中文版](adapter-conformance_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Purpose + +An Agent adapter is supported only when its source, profile, protocol behavior, +failure behavior, and release evidence are reproducible. A successful prompt is +not sufficient conformance. + +## Lifecycle + +```text +source selection + -> version lock + -> staged installation + -> provenance verification + -> profile admission + -> fake conformance + -> real-agent conformance + -> signed/offline release artifact + -> upgrade or rollback +``` + +Gateway runtime does not invoke a package runner or network installer. Package +installation is a separate operator action. + +## Installed profile + +A profile records: + +- stable profile name and Runtime kind; +- exact adapter package and version; +- canonical entry point and executable identity; +- trusted interpreter/package closure requirements; +- fixed arguments and working-directory policy; +- environment allowlist; +- ACP wire version and required capabilities; +- compatibility status for the upstream agent version. + +Profile resolution occurs before production admission. A Task cannot override +the executable, arguments, environment, or workspace. + +An installed Agent Runtime profile is distinct from a Gateway capability +profile. The first admits an agent process and wire contract; the second admits +a closed set of governed `ExecutionTarget` operations. Passing ACP adapter +conformance does not make `ws-ckpt`, shell, filesystem, or terminal execution +available. Release evidence records the tested combination of both profiles. + +## Atomic installation + +Installation uses a private managed prefix and stages a complete candidate +before publication. Verification covers package metadata, canonical binary, +file ownership/mode, and expected version. The installed marker is written last +and published atomically. + +A failed or interrupted installation leaves either the previous verified +installation or no accepted installation. It must not leave a marker that +causes a partial tree to pass admission. + +Release distribution should provide a signed or otherwise verifiable offline +artifact. Runtime network bootstrap is not an accepted fallback. + +## Fake conformance + +The deterministic fake adapter suite covers: + +- initialize and required capability negotiation; +- Session creation and a bounded multi-chunk prompt; +- exactly one terminal result after buffered observations; +- batch requests and per-item errors; +- tool-use identity and monotonic revisions; +- correlated permission requests and one-time decisions; +- cancellation independent from a silent or blocked reader; +- malformed JSON, invalid UTF-8, oversized frame, stderr flood, early exit, + timeout, and transport close; +- late update, late permission decision, and duplicate terminal rejection; +- process-group cleanup and exactly one reap. + +Fake conformance is required for every change but does not prove compatibility +with a real provider. + +## Real-agent conformance + +At least one supported adapter runs on the exact candidate artifact with: + +- version and profile identity recorded; +- initialize, Session creation, bounded text prompt, streamed updates, and one + terminal outcome; +- independent cancel of active work; +- real `allow_once` and `reject_once` flows where supported; +- no filesystem or terminal capability outside the declared profile; +- sanitized evidence that excludes prompt, provider output, credentials, + private paths, and proxy URLs. + +Codex and Claude adapter claims are independent; success of one does not accept +the other. + +## Failure and race matrix + +Conformance records expected behavior for: + +| Case | Expected result | +| --- | --- | +| Unsupported wire/capability | Fail before Session work | +| Silent initialization or prompt | Timeout, shutdown, and reap | +| Cancel vs completion | One terminal winner; late loser ignored or rejected | +| Permission during cancellation | No allow response after cancellation wins | +| Malformed stdout | Protocol failure and process-tree shutdown | +| Runtime exit before terminal | Deterministic failure with bounded diagnostics | +| Response loss after accepted callback | Durable replay without second write | +| Adapter path replacement | Launch pinned artifact or fail closed | + +## Upgrade and rollback + +An adapter upgrade is an explicit compatibility change. It reruns installer, +fake, and real conformance before publication. Rollback restores a previously +verified profile and does not rewrite Task or audit history. + +Unsupported or regressed profiles are disabled. Gateway does not silently fall +back to another provider or ungoverned Runtime for an existing Task. + +The same rule applies to capability providers. A missing `ws-ckpt` service can +make `ws-ckpt-v1` unavailable while leaving an explicitly selected +`task-only-v1` daemon valid. It cannot leave the checkpoint tool advertised or +redirect the operation to provider-native execution. + +## Evidence package + +Every accepted release records: + +- candidate commit and artifact digest; +- adapter package, adapter version, and upstream agent version; +- operating environment and required Runtime capabilities; +- Gateway capability profile and exact ExecutionTarget provider versions; +- exact automated commands and result summary; +- manual steps and expected observations, when applicable; +- untested cases and rollback result. + +Evidence is bounded and redacted. Secrets, raw prompts, and private provider +output are never committed to the public repository. + +## Community contribution + +Adapter contributions include the profile, provenance rule, fake fixture, +failure/race matrix, documentation, and real-agent evidence plan. Reviewers can +evaluate each layer independently without needing provider credentials for the +deterministic suite. diff --git a/src/cosh-ng/docs/design/acp-gateway/adapter-conformance_zh.md b/src/cosh-ng/docs/design/acp-gateway/adapter-conformance_zh.md new file mode 100644 index 0000000000..f49e80a519 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/adapter-conformance_zh.md @@ -0,0 +1,137 @@ +# Adapter 生命周期与验收 + +[English](adapter-conformance.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## 目的 + +只有 Adapter source、profile、protocol behavior、failure behavior 与 release evidence +都可复现时,它才是受支持的 Agent adapter。一次 prompt 成功不构成 conformance。 + +## 生命周期 + +```text +source selection + -> version lock + -> staged installation + -> provenance verification + -> profile admission + -> fake conformance + -> real-agent conformance + -> signed/offline release artifact + -> upgrade or rollback +``` + +Gateway runtime 不调用 package runner 或 network installer。Package installation 是独立的 +operator action。 + +## Installed profile + +Profile 记录: + +- stable profile name 与 Runtime kind; +- 准确 adapter package 与 version; +- canonical entry point 与 executable identity; +- 可信 interpreter/package closure 要求; +- fixed arguments 与 working-directory policy; +- environment allowlist; +- ACP wire version 与 required capability; +- upstream agent version 的 compatibility status。 + +Profile resolution 在 production admission 前完成。Task 不能覆盖 executable、argument、 +environment 或 workspace。 + +Installed Agent Runtime profile 与 Gateway capability profile 是两个不同概念。前者接纳 +agent process 与 wire contract,后者接纳封闭的 governed `ExecutionTarget` operation 集合。 +通过 ACP adapter conformance 不会自动启用 `ws-ckpt`、shell、filesystem 或 terminal +execution。Release evidence 必须记录两类 profile 的实际测试组合。 + +## 原子安装 + +Installer 使用 private managed prefix,并在发布前 stage 完整 candidate。Verification 覆盖 +package metadata、canonical binary、file ownership/mode 与 expected version。Installed marker +最后写入并原子发布。 + +安装失败或中断后,只能保留上一份 verified installation,或者没有 accepted installation。 +不能留下使 partial tree 通过 admission 的 marker。 + +Release distribution 应提供 signed 或其他可验证的 offline artifact。Runtime network bootstrap +不是可接受 fallback。 + +## Fake conformance + +Deterministic fake adapter suite 覆盖: + +- initialize 与 required capability negotiation; +- Session creation 与有界 multi-chunk prompt; +- buffered observation 后恰好一个 terminal result; +- batch request 与 per-item error; +- tool-use identity 与单调 revision; +- correlated permission request 与 single-use decision; +- silent/blocked reader 下独立 cancellation; +- malformed JSON、invalid UTF-8、oversized frame、stderr flood、early exit、timeout、 + transport close; +- late update、late permission decision 与 duplicate terminal rejection; +- process-group cleanup 与 exactly one reap。 + +每次变更都必须运行 fake conformance,但它不能证明真实 Provider compatibility。 + +## Real-agent conformance + +至少一个 supported adapter 在 exact candidate artifact 上完成: + +- 记录 version 与 profile identity; +- initialize、Session creation、有界 text prompt、stream update 与一个 terminal outcome; +- active work 的 independent cancel; +- Provider 支持时验证真实 `allow_once` 与 `reject_once`; +- 不使用 profile 未声明的 filesystem/terminal capability; +- 脱敏 evidence,不包含 prompt、provider output、credential、private path 或 proxy URL。 + +Codex 与 Claude adapter 分别验收;一个通过不能代表另一个通过。 + +## Failure 与 race matrix + +Conformance 为以下场景记录 expected behavior: + +| 场景 | 预期结果 | +| --- | --- | +| Unsupported wire/capability | Session work 前失败 | +| Silent initialization/prompt | Timeout、shutdown 并 reap | +| Cancel 与 completion 竞争 | 一个 terminal winner;late loser ignore 或 reject | +| Cancellation 期间 permission | Cancellation 获胜后不发送 allow | +| Malformed stdout | Protocol failure 与 process-tree shutdown | +| Terminal 前 Runtime exit | Deterministic failure 与有界诊断 | +| Accepted callback 后响应丢失 | Durable replay,不二次 write | +| Adapter path replacement | 启动 pinned artifact 或 fail closed | + +## Upgrade 与 rollback + +Adapter upgrade 是显式 compatibility change。发布前重新运行 installer、fake 与 real +conformance。Rollback 恢复此前 verified profile,不改写 Task 或 audit history。 + +Unsupported/regressed profile 必须禁用。Gateway 不为已有 Task 静默 fallback 到其他 Provider +或 ungoverned Runtime。 + +Capability provider 遵守同一规则。`ws-ckpt` service 缺失可以让 `ws-ckpt-v1` 不可用, +同时保留 operator 显式选择的 `task-only-v1` daemon;但不能继续发布 checkpoint tool,也 +不能把 operation 转发到 provider-native execution。 + +## Evidence package + +每个 accepted release 记录: + +- candidate commit 与 artifact digest; +- adapter package、adapter version 与 upstream agent version; +- operating environment 与 required Runtime capability; +- Gateway capability profile 与准确 ExecutionTarget provider version; +- 精确自动化 command 与结果摘要; +- 适用时的 manual step 与 expected observation; +- untested case 与 rollback result。 + +Evidence 必须 bounded、redacted。Secret、raw prompt 与 private provider output 不进入公开仓库。 + +## 社区贡献 + +Adapter contribution 包含 profile、provenance rule、fake fixture、failure/race matrix、文档与 +real-agent evidence plan。Reviewer 无需 Provider credential 也能独立评审 deterministic suite。 diff --git a/src/cosh-ng/docs/design/acp-gateway/capability-execution.md b/src/cosh-ng/docs/design/acp-gateway/capability-execution.md new file mode 100644 index 0000000000..58908d7345 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/capability-execution.md @@ -0,0 +1,162 @@ +# Capability and Execution + +[中文版](capability-execution_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Purpose + +This design separates a Runtime's request, a user's approval, COSH execution +authority, and the external effect. No protocol callback or UI action is itself +a Permit. + +## Authority model + +```text +Runtime request + -> CapabilityRequest + -> Policy decision + -> Approval, when required + -> ExecutionPermit + -> Execution claim + -> durable pre-effect audit + -> typed ExecutionTarget + -> typed result or uncertainty + -> Runtime acknowledgement/result delivery +``` + +The authoritative objects are: + +| Object | Meaning | +| --- | --- | +| `CapabilityRequest` | Canonical requested operation, actor, target, scope, and digest | +| `PolicyDecision` | Versioned allow, deny, or require-approval result | +| `Approval` | Durable human decision bound to the request and expiry | +| `ExecutionPermit` | Single-use authority bound to exact request, target, policy, and fences | +| `Execution` | One claim/start/complete lifecycle for an external effect | +| `ExecutionTarget` | Trusted adapter that validates and performs one typed operation | + +Provider-native permission remains observational evidence unless COSH takes +over the operation through this flow. An ACP `allow_once` response does not +prove a COSH Permit was consumed at the effect boundary. + +## ExecutionTarget registry and profile boundary + +Gateway owns the common approval, Permit, lease, dispatch, and recovery state +machines. An `ExecutionTarget` provider owns only its typed operation mapping, +readiness proof, target identity, effect, result, and reconciliation logic. + +Providers are registered by trusted daemon construction before admission. A +capability profile selects a closed set of operation-version and target-kind +pairs from that registry. Task input, Runtime labels, and approval presentation +cannot load a provider or change that set. + +`task-only-v1` selects an empty governed-operation set and therefore requires +no checkpoint provider. `ws-ckpt-v1` selects the typed workspace checkpoint +operation and requires the `ws-ckpt` provider to pass readiness and identity +admission before Gateway serves Tasks. Future Git, OverlayFS, cloud, or remote +snapshot providers require distinct typed targets and conformance evidence; +they are not aliases or silent fallbacks for `ws-ckpt`. + +Provider absence is handled at profile admission. If an admitted Runtime later +requests an operation outside the profile, Gateway returns a stable unsupported +error before creating Approval or Permit state. + +## Canonical operation + +Every governed operation has a versioned typed representation. Its canonical +digest covers: + +- operation name and version; +- bounded input; +- Actor, Task, Run, and Request identities; +- target identity and scope; +- policy revision and expiry; +- Runtime binding and lease generation. + +Presentation text is not authority. Runtime labels can assist a user but cannot +change operation digest, target, or policy meaning. + +## Approval + +- Approval is asynchronous and durable. +- Only an authenticated actor authorized for the Task can resolve it. +- Approve and deny race through one revisioned state machine. +- Expiry is a terminal denial source and never creates an allow dispatch. +- Idempotent replay returns the original durable receipt. +- Policy and target are re-evaluated before the first Permit is issued. +- A previously issued durable Permit can be recovered without inventing a new + policy decision. + +## Permit and fence + +A Permit is: + +- single-use; +- bound to one `ExecutionId` and typed operation; +- bound to target identity digest; +- bound to RuntimeBinding and Run lease generation; +- time-bounded and policy-revision-bound; +- consumed atomically when execution is claimed. + +Lease renewal inside one generation does not invalidate authority. A takeover +generation fences every old Permit that has not been consumed safely. + +## Audit before effect + +Execution cannot begin until a security audit record for its exact start is +durable. The audit boundary records bounded references for request, policy, +approval, Permit, execution, target, and fences. Raw secrets and unbounded tool +input do not enter audit. + +If audit persistence fails before the target is called, execution settles as +known no effect. If audit durability itself is indeterminate, target execution +does not begin. + +## Execution lifecycle + +```text +Planned -> Claimed -> Started -> Succeeded | Failed | Uncertain +``` + +- `Claimed` proves the Permit was consumed but the target has not started. +- `Started` proves the audit barrier passed and an effect may have occurred. +- `Succeeded` stores a typed durable result. +- `Failed` is conclusive only when the target proves its result. +- `Uncertain` means an effect may have occurred; it cannot be retried + automatically. + +Typed result and terminal Execution state commit atomically. Runtime delivery +uses a separate durable dispatch ledger so response loss cannot duplicate the +effect. + +## Reconciliation + +An `ExecutionTarget` may provide a query-only reconcile operation. It receives +the exact persisted operation, target identity, and execution reference. + +- Exact match can settle `Succeeded` or conclusive `Failed`. +- Absence is conclusive only when the target can prove the effect did not + occur. +- Changed identity, incomplete evidence, timeout, or query failure remains + `Uncertain`. +- Reconciliation never repeats the mutation. + +## Cancellation + +Cancellation prevents unstarted authority from progressing and settles pending +approval or input. It cannot erase an Execution that reached `Started`. +Cancellation of an uncertain execution leaves a visible suspended Task until +reconciliation or explicit operator settlement. + +## Acceptance invariants + +- No execution without a consumed exact Permit and durable start audit. +- Denial, expiry, stale fence, and policy change produce zero target calls. +- A Permit can be claimed once across process restart. +- Started execution is never automatically retried. +- A fabricated Runtime result cannot disagree with durable Execution state. +- Delivery replay writes to Runtime at most once. +- A profile exposes no operation without an admitted exact target provider. +- Removing `ws-ckpt` from a profile removes the checkpoint tool and authority; + it does not redirect checkpoint requests to another execution path. diff --git a/src/cosh-ng/docs/design/acp-gateway/capability-execution_zh.md b/src/cosh-ng/docs/design/acp-gateway/capability-execution_zh.md new file mode 100644 index 0000000000..6313024943 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/capability-execution_zh.md @@ -0,0 +1,148 @@ +# Capability 与执行 + +[English](capability-execution.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## 目的 + +本文把 Runtime request、用户 approval、COSH execution authority 与外部 effect 分开。 +任何 protocol callback 或 UI action 本身都不是 Permit。 + +## Authority 模型 + +```text +Runtime request + -> CapabilityRequest + -> Policy decision + -> Approval, when required + -> ExecutionPermit + -> Execution claim + -> durable pre-effect audit + -> typed ExecutionTarget + -> typed result or uncertainty + -> Runtime acknowledgement/result delivery +``` + +权威对象包括: + +| 对象 | 语义 | +| --- | --- | +| `CapabilityRequest` | Canonical operation、actor、target、scope 与 digest | +| `PolicyDecision` | 有版本的 allow、deny 或 require-approval 结果 | +| `Approval` | 绑定 request 与 expiry 的持久人工决策 | +| `ExecutionPermit` | 绑定准确 request、target、policy 与 fence 的单次权限 | +| `Execution` | 一次外部 effect 的 claim/start/complete 生命周期 | +| `ExecutionTarget` | 校验并执行一个 typed operation 的可信 adapter | + +Provider-native permission 只有在 COSH 通过上述流程接管 operation 后才是治理权限,否则 +只是 observation evidence。ACP `allow_once` 不能证明 COSH Permit 在 effect boundary 被消费。 + +## ExecutionTarget registry 与 profile boundary + +Gateway 负责公共 approval、Permit、lease、dispatch 与 recovery 状态机。`ExecutionTarget` +provider 只负责自身 typed operation mapping、readiness proof、target identity、effect、result +与 reconciliation logic。 + +Provider 由可信 daemon construction 在 admission 前注册。Capability profile 从 registry 中 +选择封闭的 operation-version 与 target-kind 集合。Task input、Runtime label 与 approval +presentation 都不能加载 provider 或改变该集合。 + +`task-only-v1` 选择空 governed-operation 集合,因此不依赖 checkpoint provider。 +`ws-ckpt-v1` 选择 typed workspace checkpoint operation,并要求 `ws-ckpt` provider 在 +Gateway 接收 Task 前通过 readiness 与 identity admission。后续 Git、OverlayFS、cloud 或 +remote snapshot provider 必须拥有独立 typed target 与 conformance evidence,不能作为 +`ws-ckpt` 的 alias 或 silent fallback。 + +Provider 缺失在 profile admission 阶段处理。已经 admitted 的 Runtime 若请求 profile 外的 +operation,Gateway 必须在创建 Approval 或 Permit state 前返回稳定 unsupported error。 + +## Canonical operation + +每个 governed operation 都有有版本的 typed representation。Canonical digest 覆盖: + +- operation name 与 version; +- 有界 input; +- Actor、Task、Run 与 Request identity; +- target identity 与 scope; +- policy revision 与 expiry; +- Runtime binding 与 lease generation。 + +Presentation text 不是 authority。Runtime label 可以帮助用户理解,但不能改变 operation +digest、target 或 policy 语义。 + +## Approval + +- Approval 是 asynchronous 且 durable 的。 +- 只有经过认证并对 Task 有权限的 actor 可以 resolve。 +- Approve 与 deny 通过同一个带 revision 的状态机竞争。 +- Expiry 是 terminal denial source,不得创建 allow dispatch。 +- Idempotent replay 返回原 durable receipt。 +- 第一次签发 Permit 前重新 evaluate policy 与 target。 +- 已经持久签发的 Permit 可以恢复,不重新发明 policy decision。 + +## Permit 与 fence + +Permit 具有以下性质: + +- single-use; +- 绑定一个 `ExecutionId` 与 typed operation; +- 绑定 target identity digest; +- 绑定 RuntimeBinding 与 Run lease generation; +- 受 expiry 和 policy revision 约束; +- execution claim 时原子消费。 + +同一 generation 内的 lease renewal 不使 authority 失效。Takeover generation 会 fence 所有 +尚未安全消费的旧 Permit。 + +## Effect 前 audit + +准确 Execution start 的 security audit record durable 之前不得开始执行。Audit boundary 保存 +request、policy、approval、Permit、execution、target 与 fence 的有界 reference,不保存 +raw secret 或无限 tool input。 + +Target 调用前 audit persistence 失败时,execution 收敛为 known no effect。Audit durability +本身不确定时也不得开始 target execution。 + +## Execution 生命周期 + +```text +Planned -> Claimed -> Started -> Succeeded | Failed | Uncertain +``` + +- `Claimed` 证明 Permit 已消费,但 target 尚未启动。 +- `Started` 证明 audit barrier 已通过,effect 可能已经发生。 +- `Succeeded` 持久化 typed result。 +- `Failed` 只有在 target 能证明时才是 conclusive。 +- `Uncertain` 表示 effect 可能发生,不得自动 retry。 + +Typed result 与 terminal Execution state 原子提交。Runtime delivery 使用独立 durable dispatch +ledger,使响应丢失不会重复 effect。 + +## Reconciliation + +`ExecutionTarget` 可以提供 query-only reconcile。输入为持久化的准确 operation、target +identity 与 execution reference。 + +- Exact match 可以收敛为 `Succeeded` 或 conclusive `Failed`。 +- 只有 target 能证明 effect 未发生时,absence 才是 conclusive。 +- Identity changed、evidence incomplete、timeout 或 query failure 继续保持 `Uncertain`。 +- Reconciliation 不得重复 mutation。 + +## Cancellation + +Cancellation 阻止尚未开始的 authority 继续推进,并收敛 pending approval/input。它不能擦除 +已经到达 `Started` 的 Execution。取消 uncertain execution 后,Task 继续以 suspended 形式可见, +直到 reconcile 或 operator settlement。 + +## 验收不变量 + +- 未消费准确 Permit 且无 durable start audit 时不得执行。 +- Denial、expiry、stale fence 与 policy change 的 target call 数为零。 +- Permit 跨进程重启也只能 claim 一次。 +- Started execution 不得自动 retry。 +- 伪造 Runtime result 不能与 durable Execution state 不一致。 +- Delivery replay 最多写 Runtime 一次。 +- Profile 不得暴露没有 exact admitted target provider 的 operation。 +- Profile 移除 `ws-ckpt` 时必须同时移除 checkpoint tool 与 authority,不能把 checkpoint + request 转发到其他 execution path。 diff --git a/src/cosh-ng/docs/design/acp-gateway/durable-task-plane.md b/src/cosh-ng/docs/design/acp-gateway/durable-task-plane.md new file mode 100644 index 0000000000..58ed3bd361 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/durable-task-plane.md @@ -0,0 +1,136 @@ +# Durable Task Plane + +[中文版](durable-task-plane_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Purpose + +The Task Plane is the durable coordinator for Task state, scheduling intent, +Runtime ownership, and delivery. It is the only source of truth for lifecycle +decisions; an in-memory worker or provider process is not authoritative. + +## Durable records + +The persistence model separates: + +- append-only Task events; +- current Task projection and revision; +- idempotency receipts; +- Outbox delivery intents; +- Run lease and Runtime binding; +- Approval, input, execution, and Runtime-dispatch ledgers; +- bounded audit and reconciliation evidence. + +Each record carries exact internal identities. Raw provider output and secrets +are not Task history. + +The admitted Runtime profile and Gateway capability profile are immutable Run +inputs. Scheduling and retry reconstruct their exact identities from durable +state; they do not re-resolve a profile from current host availability. A +profile change creates a new explicitly admitted Run or fails closed. + +## Atomic command boundary + +A Task command commits, in one transaction: + +1. expected-revision and idempotency validation; +2. accepted Task events; +3. the reduced projection; +4. the durable command receipt; +5. Outbox intents required by the transition. + +Either every item commits or none does. The writer validates event count, +Outbox count, individual payload size, and aggregate command size before the +transaction mutates storage. + +## Outbox + +Outbox is the durable boundary between state transition and external delivery. + +- A stable Delivery ID identifies one logical send. +- Claim and acknowledgement are separate durable transitions. +- A lost response reuses the same delivery identity. +- Malformed or permanently rejected entries move to bounded dead-letter state; + they do not crash or busy-loop the daemon. +- Delivery does not grant execution authority. Authority remains in Approval, + Permit, and Execution records. + +## Run lease and Runtime binding + +A worker must hold a current lease before starting or polling a Runtime. The +lease has an owner, generation, revision, and expiry. Renewal changes revision; +takeover changes generation and fences the old worker. + +Before the first prompt, the worker persists a RuntimeBinding tied to the +current lease generation. Every callback and authority transition validates +the current Run, binding, and fence. + +## Restart and takeover + +On restart, Gateway classifies durable state instead of guessing what an old +process did: + +- queued work with a valid Outbox intent can be claimed; +- work without reconstructable admission settles fail closed; +- an unacknowledged Runtime start becomes a known failure or uncertain state + according to the durable boundary crossed; +- pending input and approval ledgers settle before Task terminalization; +- Started execution or delivery becomes `Uncertain`/`Unknown`, never automatic + replay; +- typed target reconciliation may turn an uncertain result into a conclusive + result when the target proves the exact operation outcome. + +Recovery does not substitute one capability provider for another. If a Run +references a target that is no longer admitted, its unstarted work settles +fail closed and a Started effect remains uncertain until the same typed target +or an explicit operator procedure can reconcile it. + +Explicit release is distinguished from lease expiry so a partially completed +takeover can resume without repeatedly reclaiming a settled suspended Run. + +## Cancellation, retry, and input + +- Cancellation is a durable request before process signaling. +- A safely quiescent suspended Run can be abandoned atomically; an uncertain + effect cannot be silently cancelled as if it never happened. +- Retry creates a new Run only after the old lease, binding, input, approval, + and delivery state are quiescent. +- Input append binds exact Task, Run, Runtime request, revision, and digest. +- Shutdown settles pending input and approvals before closing the binding. + +## Storage and recovery contract + +- SQLite uses WAL and FULL durability for the local single-writer profile. +- Schema migrations are checksummed and reject newer or divergent history + without mutation. +- Startup validates integrity and foreign keys before accepting work. +- Backup is online, source-bound, no-clobber, and verified before publication. +- Restore targets a new path and verifies installation identity and schema. +- Operator inspect is read-only and returns bounded redacted health. + +Filesystem authority must be held across validation and open; pathname checks +alone do not protect against rename or symlink races. + +## Failure semantics + +| Boundary | Recovery classification | +| --- | --- | +| Before Task transaction commit | No accepted command | +| After commit, before Outbox send | Reclaim stable delivery | +| Receiver may have accepted, no durable ack | Delivery `Unknown`; do not resend blindly | +| Permit claimed, no start audit | Known no effect only when audit gate proves it | +| Execution Started, no conclusive result | Execution `Uncertain`; reconcile or suspend | +| Result committed, API response lost | Replay durable result and receipt | + +## Acceptance invariants + +- Event, projection, receipt, and Outbox never diverge after a crash. +- A stale lease owner cannot write Task, Runtime, approval, input, or execution + state. +- Response-loss replay does not duplicate an effect or Runtime delivery. +- Poison data cannot starve unrelated work. +- Every uncertain effect remains visible until exact reconciliation or operator + settlement. +- Restart and retry preserve the admitted capability profile; provider + unavailability cannot silently change a Run's operation inventory. diff --git a/src/cosh-ng/docs/design/acp-gateway/durable-task-plane_zh.md b/src/cosh-ng/docs/design/acp-gateway/durable-task-plane_zh.md new file mode 100644 index 0000000000..dfe60c85fd --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/durable-task-plane_zh.md @@ -0,0 +1,119 @@ +# 持久 Task Plane + +[English](durable-task-plane.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## 目的 + +Task Plane 是 Task 状态、调度意图、Runtime ownership 与 delivery 的持久协调者。 +生命周期决策只以它为事实来源,内存 worker 和 Provider process 都不具有权威性。 + +## 持久记录 + +持久化模型区分: + +- append-only Task event; +- 当前 Task projection 与 revision; +- idempotency receipt; +- Outbox delivery intent; +- Run lease 与 Runtime binding; +- Approval、input、execution 与 Runtime-dispatch ledger; +- 有界 audit 与 reconciliation evidence。 + +每条记录携带准确内部 identity。Raw provider output 和 secret 不进入 Task history。 + +Admitted Runtime profile 与 Gateway capability profile 都是 immutable Run input。调度与 +retry 从 durable state 重建其准确 identity,不根据当前 host availability 重新解析 profile。 +Profile change 必须创建新的显式 admitted Run,否则 fail closed。 + +## 原子 command 边界 + +一个 Task command 在同一 transaction 内提交: + +1. expected-revision 与 idempotency 校验; +2. 被接受的 Task event; +3. reducer 生成的 projection; +4. 持久 command receipt; +5. 状态转换要求的 Outbox intent。 + +以上内容必须全部提交或全部不提交。Writer 在 transaction 修改存储前检查 event 数、 +Outbox 数、单 payload 大小和完整 command aggregate 大小。 + +## Outbox + +Outbox 是状态转换与外部 delivery 之间的持久边界。 + +- Stable Delivery ID 标识一次逻辑发送。 +- Claim 与 acknowledgement 是两个持久转换。 +- 响应丢失时复用相同 delivery identity。 +- Malformed 或永久拒绝的 entry 进入有界 dead-letter,不得崩溃或 busy-loop daemon。 +- Delivery 不授予执行权限。Authority 只来自 Approval、Permit 与 Execution record。 + +## Run lease 与 Runtime binding + +Worker 启动或 poll Runtime 前必须持有 current lease。Lease 包含 owner、generation、 +revision 与 expiry。Renewal 改变 revision,takeover 改变 generation 并 fence 旧 worker。 + +第一次 prompt 前,worker 持久化绑定当前 lease generation 的 RuntimeBinding。所有 +callback 与 authority transition 都验证 current Run、binding 与 fence。 + +## 重启与 takeover + +Gateway 重启后依据持久状态分类,不猜测旧 process 已经做了什么: + +- 带有效 Outbox intent 的 queued work 可以重新 claim; +- 无法重建可信 admission 的 work fail closed; +- 未确认 Runtime start 按实际越过的持久边界收敛为 known failure 或 uncertain; +- pending input 和 approval ledger 在 Task terminalization 前收敛; +- Started execution 或 delivery 进入 `Uncertain`/`Unknown`,不得自动 replay; +- typed target 能证明准确 operation outcome 时,reconciliation 可以把 uncertain 结果 + 转为 conclusive result。 + +Recovery 不替换 capability provider。Run 引用的 target 不再 admitted 时,尚未开始的 work +fail closed;已经 Started 的 effect 保持 uncertain,直到相同 typed target 或显式 operator +procedure 可以 reconcile。 + +显式 release 与 lease expiry 必须区分,使中断的 takeover 可以继续,同时避免反复领取已 +收敛的 suspended Run。 + +## Cancellation、retry 与 input + +- Cancellation 必须先持久化,再发 process signal。 +- 安全静止的 suspended Run 可以原子放弃;uncertain effect 不能伪装成从未发生的 cancel。 +- Retry 仅在旧 lease、binding、input、approval 和 delivery 全部静止后创建新 Run。 +- Input append 绑定准确 Task、Run、Runtime request、revision 与 digest。 +- Shutdown 在关闭 binding 前先收敛 pending input 和 approval。 + +## Storage 与 recovery contract + +- 本地 single-writer profile 使用 SQLite WAL 与 FULL durability。 +- Schema migration 带 checksum;newer/divergent history 必须无 mutation 拒绝。 +- Startup 在接收工作前检查 integrity 与 foreign key。 +- Backup 是 online、source-bound、no-clobber,并在发布前验证。 +- Restore 只写新路径,并检查 installation identity 与 schema。 +- Operator inspect 为 read-only,只返回有界脱敏 health。 + +Filesystem authority 必须跨 validation 与 open 保持;只检查 pathname 不能防止 rename 或 +symlink race。 + +## Failure 语义 + +| 边界 | Recovery 分类 | +| --- | --- | +| Task transaction commit 前 | Command 未被接受 | +| Commit 后、Outbox send 前 | 重新 claim stable delivery | +| Receiver 可能已接受、无 durable ack | Delivery `Unknown`;不得盲目 resend | +| Permit claimed、无 start audit | 只有 audit gate 能证明时才是 known no effect | +| Execution Started、无 conclusive result | Execution `Uncertain`;reconcile 或 suspend | +| Result committed、API response 丢失 | Replay durable result 与 receipt | + +## 验收不变量 + +- Crash 后 event、projection、receipt 与 Outbox 不得分叉。 +- Stale lease owner 不能写 Task、Runtime、approval、input 或 execution 状态。 +- Response-loss replay 不重复 effect 或 Runtime delivery。 +- Poison data 不得饿死无关 work。 +- 每个 uncertain effect 在准确 reconcile 或 operator settlement 前保持可见。 +- Restart 与 retry 保留 admitted capability profile;provider unavailable 不能静默改变 Run + 的 operation inventory。 diff --git a/src/cosh-ng/docs/design/acp-gateway/runtime-security.md b/src/cosh-ng/docs/design/acp-gateway/runtime-security.md new file mode 100644 index 0000000000..081d590599 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/runtime-security.md @@ -0,0 +1,130 @@ +# Runtime Security Boundary + +[中文版](runtime-security_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Threat model + +Agent Runtime code and its descendants are untrusted. They may be buggy, +compromised, or intentionally adversarial. A Runtime can produce protocol +frames and request capabilities, but it is not an operator and does not inherit +Gateway authority. + +The security boundary must hold even when Runtime and operator software are +installed by the same user. Filesystem permissions alone are insufficient when +both processes run as the same kernel principal. + +## Required isolation + +A production Runtime must not be able to: + +- connect to the Gateway command socket as an approving actor; +- read or modify Gateway SQLite, WAL, SHM, backup, or audit files; +- signal or debug the Gateway process; +- change Gateway configuration, executable, workspace binding, or unit state; +- escape the service lifecycle owner and leave effect-capable descendants; +- inherit ambient credentials or injection variables not required by profile. + +This requires a kernel-enforced principal, sandbox, or service boundary. A +presentation-layer check or an in-process actor label is not sufficient. + +## Process ownership + +- Each child process has exactly one lifecycle owner. +- Runtime launch creates a dedicated process group or stronger containment. +- Normal shutdown propagates cancellation, waits for protocol grace, then + escalates TERM/KILL and reaps exactly once. +- Daemon hard failure is owned by an external service manager or containment + boundary that kills every descendant before restart becomes ready. +- Runtime cannot create a sibling service or cgroup outside that ownership. + +Linux packaging must verify effective service-manager properties rather than +trusting only a unit template. Unsupported platforms fail production admission +or use an independently reviewed owner. + +## Executable and workspace identity + +Production admission pins executable and workspace authority before accepting +Tasks: + +- absolute configured path; +- descriptor-backed device/inode identity; +- required file type and executable/directory mode; +- trusted installation provenance and profile identity; +- workspace identity shared with governed execution targets. + +Launch uses the pinned descriptor or fails closed. A path rename, symlink +retarget, or same-name replacement must never cause a queued Task to execute a +different artifact or workspace. + +Descriptor pinning does not attest an entire interpreter or package dependency +tree. Script adapters additionally require a trusted interpreter and immutable +or verified package closure. + +## Environment + +Runtime launch starts from a cleared environment and explicitly allows only +required values such as locale, selected proxy settings, and approved +authentication entry points. It rejects dynamic-loader, Node injection, +shell-function, and arbitrary inherited configuration variables. + +Credentials are scoped to the Runtime profile and are not written to Task, +event, audit, test transcript, or PR evidence. + +## Local endpoint admission + +Gateway authenticates local clients from kernel-provided peer identity and an +installation-scoped policy. It does not trust a caller-supplied Actor ID. + +Production admission validates configured Runtime profile, target, workspace, +containment proof, and service identity before binding a public command socket. +Test or interoperability flags cannot silently enable the durable production +scheduler. + +## Profile admission and platform portability + +Capability dependencies are mandatory only for the selected profile. A +`task-only-v1` daemon does not open or validate a checkpoint socket and must not +advertise a checkpoint tool. A `ws-ckpt-v1` daemon requires Linux plus the +reviewed service lifecycle, peer identity, socket, workspace binding, and +filesystem support of its `ws-ckpt` provider. + +If a host cannot satisfy those requirements, `ws-ckpt-v1` fails admission +before the command socket is published. The operator may explicitly select a +smaller supported profile, but Gateway never downgrades an already selected +profile. The admitted profile identity and operation inventory remain fixed +for the Run and are checked against the Runtime handshake. + +Adding another checkpoint implementation does not inherit `ws-ckpt` trust. +Its executable or service identity, data durability, audit barrier, +reconciliation, and crash-containment evidence are reviewed independently. + +## Filesystem authority + +Security-sensitive files are opened relative to a trusted directory descriptor +with owner, mode, type, and identity checks held across open. Validation followed +by a new pathname lookup is vulnerable to replacement races. + +The same rule applies to database, WAL/SHM companions, backup destination, +audit files, adapter artifacts, and governed Unix sockets. + +## Audit + +Audit is append-only, bounded, redacted, and durably framed. A partial write or +sync failure poisons the writer until explicit recovery; a later record cannot +be appended to a corrupt tail and treated as durable evidence. + +## Acceptance invariants + +- An adversarial Runtime cannot approve its own request. +- Runtime cannot read Gateway durable state or audit evidence. +- Replacing an executable or workspace path after admission cannot change what + launches. +- SIGKILL of Gateway cannot leave an effect-capable descendant outside the + lifecycle owner. +- Environment injection and service-manager escape attempts fail closed. +- Security evidence comes from effective runtime properties and adversarial + fixtures, not configuration intent alone. +- Unsupported platform dependencies reject only the profile that requires + them; they never leave an advertised operation without an admitted target. diff --git a/src/cosh-ng/docs/design/acp-gateway/runtime-security_zh.md b/src/cosh-ng/docs/design/acp-gateway/runtime-security_zh.md new file mode 100644 index 0000000000..0a033c20a1 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/runtime-security_zh.md @@ -0,0 +1,113 @@ +# Runtime 安全边界 + +[English](runtime-security.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## Threat model + +Agent Runtime 及其 descendant 都不可信。它们可能有 bug、被攻击或主动对抗。Runtime +可以发送 protocol frame 和请求 capability,但它不是 operator,也不继承 Gateway authority。 + +即使 Runtime 与 operator software 由同一用户安装,安全边界仍必须成立。当两个进程使用 +同一 kernel principal 时,只依赖 filesystem permission 不足以隔离权限。 + +## 必须具备的隔离 + +Production Runtime 不得: + +- 作为 approving actor 连接 Gateway command socket; +- 读取或修改 Gateway SQLite、WAL、SHM、backup 或 audit file; +- signal 或 debug Gateway process; +- 改变 Gateway config、executable、workspace binding 或 unit state; +- 逃离 service lifecycle owner 并留下能够产生 effect 的 descendant; +- 继承 profile 不需要的 ambient credential 或 injection variable。 + +这要求 kernel-enforced principal、sandbox 或 service boundary。Presentation check 或进程内 +Actor label 都不能替代该边界。 + +## Process ownership + +- 每个 child process 只能有一个 lifecycle owner。 +- Runtime launch 创建独立 process group 或更强 containment。 +- 正常 shutdown 先传播 cancellation,等待 protocol grace,再升级 TERM/KILL,并只 reap 一次。 +- Daemon hard failure 由外部 service manager 或 containment boundary 负责,在 replacement + ready 前清理全部 descendant。 +- Runtime 不能在 ownership 外创建 sibling service 或 cgroup。 + +Linux package 必须验证 service manager 的 effective property,不能只相信 unit template。 +不支持的平台必须拒绝 production admission,或使用独立评审过的 owner。 + +## Executable 与 workspace identity + +Production admission 在接受 Task 前固定 executable 与 workspace authority: + +- absolute configured path; +- descriptor-backed device/inode identity; +- 正确 file type 与 executable/directory mode; +- 可信 installation provenance 与 profile identity; +- 与 governed execution target 共享的 workspace identity。 + +Launch 使用 pinned descriptor,否则 fail closed。Path rename、symlink retarget 或同名 replacement +都不能让 queued Task 执行不同 artifact 或 workspace。 + +Descriptor pinning 不等于整个 interpreter/package dependency tree 的 attestation。Script adapter +还需要可信 interpreter 和 immutable 或 verified package closure。 + +## Environment + +Runtime 从清空的 environment 启动,只显式允许 locale、选定 proxy setting 和经批准的 +authentication entry point。Dynamic-loader、Node injection、shell function 与任意 inherited +config variable 必须拒绝。 + +Credential 只在 Runtime profile 范围内使用,不进入 Task、event、audit、test transcript 或 +PR evidence。 + +## Local endpoint admission + +Gateway 从 kernel-provided peer identity 与 installation-scoped policy 认证本地 client,不相信 +caller 自报的 Actor ID。 + +Production admission 在绑定公共 command socket 前验证 configured Runtime profile、target、 +workspace、containment proof 与 service identity。Test/interoperability flag 不能静默启用 durable +production scheduler。 + +## Profile admission 与平台可移植性 + +Capability dependency 只对 selected profile 强制。`task-only-v1` daemon 不打开或校验 +checkpoint socket,也不得发布 checkpoint tool。`ws-ckpt-v1` daemon 要求 Linux,并要求其 +`ws-ckpt` provider 的 service lifecycle、peer identity、socket、workspace binding 与 +filesystem support 全部通过评审和 admission。 + +Host 无法满足这些要求时,`ws-ckpt-v1` 必须在发布 command socket 前拒绝 admission。 +Operator 可以显式选择更小且受支持的 profile,但 Gateway 不得自动 downgrade 已选择的 +profile。Admitted profile identity 与 operation inventory 在 Run 内保持不变,并与 Runtime +handshake 精确核对。 + +新增 checkpoint implementation 不继承 `ws-ckpt` 的信任。其 executable/service identity、 +data durability、audit barrier、reconciliation 与 crash-containment evidence 需要独立评审。 + +## Filesystem authority + +Security-sensitive file 必须相对可信 directory descriptor 打开,并跨 open 保持 owner、mode、type +与 identity 校验。Validation 后重新 pathname lookup 会暴露 replacement race。 + +Database、WAL/SHM companion、backup destination、audit file、adapter artifact 与 governed +Unix socket 都遵守同一规则。 + +## Audit + +Audit 必须 append-only、bounded、redacted 且 framing durable。Partial write 或 sync failure 后 +writer 保持 poisoned,直到显式 recovery;不能在 corrupt tail 后追加新 record 并把它当作 +durable evidence。 + +## 验收不变量 + +- 对抗 Runtime 不能批准自己的 request。 +- Runtime 不能读取 Gateway durable state 或 audit evidence。 +- Admission 后替换 executable/workspace path 不能改变实际 launch 对象。 +- Gateway 被 SIGKILL 后不能留下 lifecycle owner 之外、可产生 effect 的 descendant。 +- Environment injection 与 service-manager escape 尝试 fail closed。 +- Security evidence 来自 effective runtime property 与 adversarial fixture,而非配置意图。 +- 不支持的平台依赖只拒绝需要它的 profile,不能留下没有 admitted target 却仍被发布的 + operation。 diff --git a/src/cosh-ng/docs/design/acp-gateway/rust-1.88-decision.md b/src/cosh-ng/docs/design/acp-gateway/rust-1.88-decision.md new file mode 100644 index 0000000000..10a97808fb --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/rust-1.88-decision.md @@ -0,0 +1,82 @@ +# Rust 1.88 Toolchain Decision + +[中文版](rust-1.88-decision_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Context + +The official `agent-client-protocol` 2.0.0 package declares MSRV 1.88.0. +cosh-ng needs one reproducible compiler baseline for local development, CI, +RPM builds, and ACP Runtime integration. + +## Decision + +The cosh-ng minimum Rust version and pinned toolchain are **1.88.0**. + +This changes the compiler baseline only. It does not require moving existing +crates from Rust edition 2021 to edition 2024. The toolchain change remains +independent from SDK adoption, protocol code, and Gateway features so each can +be reviewed and rolled back separately. + +## Rationale + +- Satisfy the explicit MSRV of the official ACP Rust SDK 2.0.0. +- Remove drift between developer machines, CI, RPM builders, and release jobs. +- Keep protocol failures separate from toolchain failures. +- Use the dependency's minimum required version instead of an arbitrary newer + stable compiler. + +## Workspace requirements + +| Location | Requirement | +| --- | --- | +| `src/cosh-ng/Cargo.toml` | `workspace.package.rust-version = "1.88"` | +| `src/cosh-ng/rust-toolchain.toml` | Pin `channel = "1.88.0"` with rustfmt and Clippy | +| cosh-ng CI | Install and use 1.88.0 rather than runner default stable | +| RPM/build image | Fail clearly when Rust 1.88 is unavailable | +| Developer docs | State MSRV, installation, and troubleshooting impact | + +These locations change atomically. A future compiler upgrade follows the same +rule. + +## Validation gate + +Toolchain or dependency changes run on Linux: + +```bash +cd src/cosh-ng +rustc --version +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --locked -- -D warnings +cargo test --workspace --locked +cargo build --workspace --release --locked +``` + +`rustc --version` must report 1.88.x. Public API or rustdoc changes also run: + +```bash +cargo doc --workspace --no-deps --locked +``` + +The actual RPM build environment is validated independently; success on a +GitHub runner does not prove the release image can provide the toolchain. + +## Compatibility impact + +- Source builders using an older Rust compiler must upgrade first. +- Existing binaries and runtime protocols do not change merely because the + compiler changed. +- Edition remains 2021 to avoid unrelated semantic changes. +- Rust 1.88 does not authorize unrelated dependency upgrades. + +## Upgrade and rollback + +Compiler, CI, and RPM baselines move together. If a supported build environment +cannot provide the pinned version, revert the toolchain change as a unit. ACP +must not enter main through a forked SDK, copied generated types, or bypassed +MSRV checks; such an alternative requires a new architecture decision. + +## Reference + +- [agent-client-protocol 2.0.0 manifest](https://docs.rs/crate/agent-client-protocol/2.0.0/source/Cargo.toml) diff --git a/src/cosh-ng/docs/design/acp-gateway/rust-1.88-decision_zh.md b/src/cosh-ng/docs/design/acp-gateway/rust-1.88-decision_zh.md new file mode 100644 index 0000000000..7fcf75ae02 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/rust-1.88-decision_zh.md @@ -0,0 +1,81 @@ +# Rust 1.88 工具链决策 + +[English](rust-1.88-decision.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## 背景 + +官方 `agent-client-protocol` 2.0.0 声明 MSRV 1.88.0。为了让本地开发、CI、RPM +构建和 ACP Runtime 使用同一可复现环境,cosh-ng 统一工具链基线。 + +## 决策 + +cosh-ng 的最低 Rust 版本和固定 toolchain 统一为 **1.88.0**。 + +该决策只提升编译器基线,不要求把现有 crate 的 Rust edition 从 2021 改为 2024。 +工具链升级与 ACP SDK、协议实现和 Gateway 功能保持独立,以便单独判断构建影响并安全 +回滚。 + +## 原因 + +- 满足官方 ACP Rust SDK 2.0.0 的明确 MSRV。 +- 固定开发机、CI、RPM 构建和发布环境,避免 stable 漂移导致不可复现。 +- 让所有贡献者从一致基线开始,避免协议代码与工具链故障混在同一变更中。 +- 1.88.0 是依赖要求的最小版本,不主动抬高到更新 stable。 + +## Workspace 要求 + +工具链基线必须在以下位置保持一致: + +| 位置 | 要求 | +|------|------| +| `src/cosh-ng/Cargo.toml` | `workspace.package.rust-version = "1.88"` | +| `src/cosh-ng/rust-toolchain.toml` | 固定 `channel = "1.88.0"`,保留 rustfmt 和 clippy | +| cosh-ng CI job | 安装并使用 1.88.0,不依赖 runner 默认 stable | +| RPM/build image | 构建前检查 `rustc` 满足 1.88,缺失时明确失败 | +| 开发文档 | 更新 MSRV、安装和故障提示 | + +不得只修改 Cargo manifest 而让 CI 或 RPM 使用隐式工具链。未来升级 Rust 时也必须原子 +更新这些位置。 + +## 验证门禁 + +工具链或依赖变更需要在 Linux 环境完成: + +```bash +cd src/cosh-ng +rustc --version +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --locked -- -D warnings +cargo test --workspace --locked +cargo build --workspace --release --locked +``` + +`rustc --version` 必须报告 1.88.x。涉及 public API 或 rustdoc 的同期调整还需执行: + +```bash +cargo doc --workspace --no-deps --locked +``` + +还要在项目实际使用的 RPM 构建环境中验证一次,确认系统仓库或构建镜像能够稳定提供 +1.88,而不是只在 GitHub Actions 中成功。 + +## 兼容性影响 + +- 使用旧版 Rust 的源码构建者需要先升级工具链。 +- 已发布二进制和运行时协议不因编译器升级自动发生变化。 +- edition 继续使用 2021,降低一次迁移中无关语义变化的范围。 +- 其他依赖仍需独立评审,Rust 1.88 不构成接受任意新版依赖的授权。 + +## 升级与回滚 + +Rust 基线升级独立于协议和功能变更,并同时验证 CI 与 RPM 环境。升级后的构建环境无法 +稳定提供目标版本时,整体回滚该次工具链升级。ACP 实现不得通过 fork SDK、复制生成 +类型或绕过 MSRV 检查进入主干;替代方案需要新的架构决策。 + +贡献者使用仓库中的 `rust-toolchain.toml` 获取一致工具链,不应依赖系统默认 stable。 + +## 参考 + +- [agent-client-protocol 2.0.0 manifest](https://docs.rs/crate/agent-client-protocol/2.0.0/source/Cargo.toml) diff --git a/src/cosh-ng/docs/design/acp-gateway/task-runtime-model.md b/src/cosh-ng/docs/design/acp-gateway/task-runtime-model.md new file mode 100644 index 0000000000..5b308c21a6 --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/task-runtime-model.md @@ -0,0 +1,135 @@ +# Task and Runtime Model + +[中文版](task-runtime-model_zh.md) + +Related architecture: [COSH Gateway and ACP Architecture](README.md) + +## Purpose + +This document defines the durable identities and provider-neutral port between +Gateway and an Agent Runtime. It prevents process, provider, and channel state +from becoming a second Task state machine. + +## Identity hierarchy + +```text +Installation + -> Actor + -> Task + -> Run + -> RuntimeBinding + -> Turn + -> Agent SessionBinding + -> Request / ToolUse / Approval / Execution +``` + +Each identifier has one meaning and one namespace: + +| Identity | Authority and lifetime | +| --- | --- | +| `InstallationId` | One installed Gateway authority domain | +| `ActorId` | Authenticated caller principal within an installation | +| `TaskId` | Durable user-visible work unit | +| `RunId` | One attempt of a Task | +| `RuntimeBindingId` | Fenced binding between one Run and one Runtime instance | +| `TurnId` | One prompt-to-terminal exchange inside a Run | +| `SessionBinding` | Mapping to a provider or ACP Session identifier | +| `RequestId` | One callback or input request | +| `ApprovalId` | Durable decision record for one bounded request | +| `PermitId` | Single-use authority for one execution | +| `ExecutionId` | One attempted external effect | + +IDs are never substituted across domains. External IDs are stored as bounded +references and are always paired with their internal binding. + +## Task, Run, and Turn + +- A Task survives client disconnect, Runtime exit, and daemon restart. +- A Task can have multiple Runs, but only one active Run. +- A Run owns one lease generation and zero or one active RuntimeBinding. +- A Turn belongs to one Run. Turn completion does not automatically terminate + a multi-turn Run. +- A retry creates a new Run; it never reopens a terminal Run. + +Task events are append-only facts. A pure reducer validates expected revision, +state transition, and identity correlation before updating a projection. + +## AgentRuntimePort + +Gateway talks to runtimes through versioned, provider-neutral commands and +events. + +Commands cover: + +- initialize/start; +- prompt or turn input; +- exact response to a pending input request; +- cancellation and shutdown; +- approval acknowledgement and typed brokered result delivery. + +Events cover: + +- bounded observations; +- tool-use lifecycle; +- provider-native permission request; +- brokered operation request; +- exact input request; +- one terminal Run or Turn outcome. + +Provider-specific payloads are normalized at the bridge. Channel-specific +presentation is derived later from durable events. + +Runtime initialization also declares a bounded hosted-operation inventory. +Gateway compares it with the selected capability profile before accepting Task +work. `task-only-v1` requires an empty inventory; `ws-ckpt-v1` requires the +exact versioned checkpoint request and typed-result capability. Missing, +additional, or downgraded operations fail admission rather than being hidden +by presentation logic. + +The Runtime can request only an operation. It cannot select the concrete +`ExecutionTarget`, socket, service, credential, or fallback path. Those remain +trusted daemon configuration bound to the admitted profile. + +## Runtime binding fence + +A callback is accepted only when all of the following match durable state: + +- Actor, Task, and Run; +- RuntimeBinding ID and generation; +- current Run lease generation; +- request identity and expected revision; +- monotonic event sequence. + +Lease renewal may change a lease revision without changing its authority +generation. A new generation fences every callback from the previous Runtime. + +## Terminal semantics + +Prompt completion, process exit, transport close, cancellation, and execution +uncertainty are distinct facts. The Runtime adapter emits at most one terminal +observation, and the Task reducer determines the durable Task outcome. + +Late observations and callbacks after cancellation or terminal settlement fail +closed. A response-loss replay returns durable state and does not write to the +Runtime a second time. + +## Versioning and bounds + +- Gateway/Task and Runtime schemas version independently. +- Every string, collection, frame, and aggregate has an explicit bound. +- Unknown versions and unsupported operations return stable typed errors. +- A breaking Runtime change increments Runtime schema without implicitly + changing ACP wire or Task schema. +- Machine-readable fixtures cover encoding, decoding, unknown fields, limits, + and backward/forward compatibility. + +## Acceptance invariants + +- Two provider sessions cannot collide in the same internal identity. +- A stale Runtime cannot mutate a replaced Run. +- Retry creates a new Run and a new fence. +- A late permission or input response is rejected without partial mutation. +- Exactly one terminal outcome is observable through the port. +- Core and ACP adapters pass the same neutral-port contract suite. +- Runtime hosted-operation inventory exactly matches the admitted capability + profile before a Run starts. diff --git a/src/cosh-ng/docs/design/acp-gateway/task-runtime-model_zh.md b/src/cosh-ng/docs/design/acp-gateway/task-runtime-model_zh.md new file mode 100644 index 0000000000..86b6e47a9e --- /dev/null +++ b/src/cosh-ng/docs/design/acp-gateway/task-runtime-model_zh.md @@ -0,0 +1,123 @@ +# Task 与 Runtime 模型 + +[English](task-runtime-model.md) + +关联架构:[COSH Gateway 与 ACP 架构](README_zh.md) + +## 目的 + +本文定义 Gateway 与 Agent Runtime 之间的持久身份和 provider-neutral Port,避免进程、 +Provider 或渠道状态形成第二套 Task 状态机。 + +## 身份层级 + +```text +Installation + -> Actor + -> Task + -> Run + -> RuntimeBinding + -> Turn + -> Agent SessionBinding + -> Request / ToolUse / Approval / Execution +``` + +每种 ID 只有一个语义和一个命名空间: + +| 身份 | 权限与生命周期 | +| --- | --- | +| `InstallationId` | 一个已安装 Gateway 的权限域 | +| `ActorId` | Installation 内经过认证的调用主体 | +| `TaskId` | 用户可见的持久工作单元 | +| `RunId` | Task 的一次执行尝试 | +| `RuntimeBindingId` | 一个 Run 与一个 Runtime 实例的 fenced binding | +| `TurnId` | Run 内一次 prompt 到 terminal 的交互 | +| `SessionBinding` | 与 Provider 或 ACP Session ID 的映射 | +| `RequestId` | 一次 callback 或 input request | +| `ApprovalId` | 针对一个有界请求的持久决策记录 | +| `PermitId` | 一次执行的单次消费权限 | +| `ExecutionId` | 一次外部副作用尝试 | + +不同领域的 ID 不得互相替代。外部 ID 只保存为有界 reference,并始终绑定内部 identity。 + +## Task、Run 与 Turn + +- Task 跨客户端断线、Runtime 退出和 daemon 重启持续存在。 +- 一个 Task 可以有多个 Run,但只能有一个 active Run。 +- 一个 Run 拥有一个 lease generation 和零或一个 active RuntimeBinding。 +- Turn 属于一个 Run。Turn 完成不自动终结一个多 Turn Run。 +- Retry 创建新 Run,不重新打开 terminal Run。 + +Task event 是 append-only 事实。纯 reducer 在更新 projection 前验证 expected revision、 +状态转换和 identity correlation。 + +## AgentRuntimePort + +Gateway 只通过有版本、provider-neutral 的 command 和 event 与 Runtime 通信。 + +Command 包括: + +- initialize/start; +- prompt 或 Turn input; +- 对 pending input request 的准确响应; +- cancellation 和 shutdown; +- approval acknowledgement 与 typed brokered result delivery。 + +Event 包括: + +- 有界 observation; +- tool-use 生命周期; +- provider-native permission request; +- brokered operation request; +- 准确 input request; +- 唯一的 Run 或 Turn terminal outcome。 + +Provider 私有 payload 在 Bridge 内归一化。渠道 presentation 再由持久 event 派生。 + +Runtime initialization 还需要声明有界 hosted-operation inventory。Gateway 在接收 Task work +前,将其与 selected capability profile 精确比较。`task-only-v1` 要求 inventory 为空; +`ws-ckpt-v1` 要求准确版本的 checkpoint request 与 typed-result capability。缺失、额外或 +downgrade operation 必须拒绝 admission,不能由 presentation logic 隐藏。 + +Runtime 只能请求 operation,不能选择具体 `ExecutionTarget`、socket、service、credential +或 fallback path。这些内容属于绑定 admitted profile 的可信 daemon configuration。 + +## Runtime binding fence + +Callback 只有在以下字段全部匹配持久状态时才被接受: + +- Actor、Task 和 Run; +- RuntimeBinding ID 与 generation; +- 当前 Run lease generation; +- request identity 与 expected revision; +- 单调 event sequence。 + +Lease renewal 可以改变 lease revision,但不改变 authority generation。新 generation 会 +fence 上一 Runtime 的全部 callback。 + +## Terminal 语义 + +Prompt completion、process exit、transport close、cancellation 与 execution uncertainty +是不同事实。Runtime adapter 最多发出一次 terminal observation,由 Task reducer 决定 +持久 Task outcome。 + +取消或 terminal settlement 后的 late observation/callback 必须 fail closed。响应丢失后的 +重放返回持久状态,不得再次写 Runtime。 + +## 版本与边界 + +- Gateway/Task schema 与 Runtime schema 独立演进。 +- 每个 string、collection、frame 和 aggregate 都有显式上限。 +- Unknown version 与 unsupported operation 返回稳定 typed error。 +- Runtime breaking change 只升级 Runtime schema,不隐式改变 ACP wire 或 Task schema。 +- Machine-readable fixture 覆盖编解码、unknown field、边界与前后向兼容。 + +## 验收不变量 + +- 两个 Provider Session 不能在内部 identity 上碰撞。 +- Stale Runtime 不能修改被替换的 Run。 +- Retry 创建新 Run 和新 fence。 +- Late permission/input response 被拒绝且没有 partial mutation。 +- Port 只能观察到一个 terminal outcome。 +- Core 与 ACP Adapter 通过同一 neutral-port contract suite。 +- Run 启动前,Runtime hosted-operation inventory 必须与 admitted capability profile 精确匹配。