diff --git a/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.md b/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.md index e2b11b6439..c1ec56f486 100644 --- a/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.md +++ b/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.md @@ -3,7 +3,7 @@ - Status: Draft; under maintainer review - Tracking issue: [#3836](https://github.com/huangruiteng/loopx/issues/3836) - Date: 2026-09-02 -- Last updated: 2026-09-15 +- Last updated: 2026-09-16 - Scope: peer Agents collaborating around one shared Goal while preserving canonical intent, per-Agent execution frontiers, claim/lease ownership, and auditable replan/amendment decisions @@ -239,6 +239,38 @@ storage schema, build or attune the index, or open, resume, or message a live task. Other harnesses can implement the same Decision Context provider protocol without adding host syntax or transcript storage to the Goal authority. +### 3.6 Peer agent directory and bounded observation + +A per-Agent frontier tells one Agent about its own route. Peers also need the +same three abilities about each other, and the steward needs them about every +Agent it is asked about: discover which Agents exist and which are running, +observe one of them within bounds, and hand one of them a bounded request. That +reusable contract is +[`peer_agent_directory_v0`](../../reference/protocols/peer-agent-directory-and-observation-v0.md). + +It adds no sixth kind of shared state. Identity, work, claims, leases and the +canonical revision stay exactly where this document already put them; the +contract contributes an Agent-facing *view* plus the rules for reading and +delivering. Three of those rules carry the weight here: + +- **Presence is advisory and provider-scoped.** A live session never creates an + identity, and an Agent with no live session is still registered, still owns + its claims and is still a delivery target. A provider reports its own + locations with session-scoped handles and its own liveness vocabulary; a + reader that cannot classify a target reports `unknown` and names the coverage + gap rather than inferring completion or absence of progress. +- **Observation and delivery grant nothing.** Reading a peer, or handing it + context, is not a claim, a lease, a priority, a plan change or an amendment. + Delivery stays `context_handoff`; what the Goal asks for still changes only + through `GoalAmendmentAuthority`, and work state still changes only through + the canonical Todo, quota and lane owners. +- **Terminal-space providers are providers, not the contract.** A host surface + that owns terminals may supply presence and bounded live output, and must + declare how a caller proves it is inside the space, what survives a detach or + restart, and what it cannot recover. With no such provider the directory + degenerates to registered identity plus durable work state, which is the + normal case for a prompt-only transport. + ## 4. Authority matrix ### 4.1 What `GoalAmendmentAuthority` means diff --git a/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.zh-CN.md b/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.zh-CN.md index d964be6c1a..a183f8eaff 100644 --- a/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.zh-CN.md +++ b/docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.zh-CN.md @@ -3,7 +3,7 @@ - 状态:草案;维护者评审中 - 跟踪 Issue:[#3836](https://github.com/huangruiteng/loopx/issues/3836) - 日期:2026-09-02 -- 最后更新:2026-09-15 +- 最后更新:2026-09-16 - 范围:多个对等 Agent 围绕同一个共享 Goal 协作,同时保留 canonical intent、每个 Agent 的执行 frontier、claim/lease 所有权,以及可审计的 replan/amendment 决策 @@ -216,6 +216,31 @@ Core 只解析一次 host-specific 深链语法,并只向 provider 暴露 norm live task 发消息。其他 harness 可以实现相同的 Decision Context provider 协议,无需 把 host 语法或 transcript 存储引入 Goal authority。 +### 3.6 Peer agent directory 与有界观察 + +per-Agent frontier 告诉一个 Agent 自己的路线。peer 之间也需要彼此具备同样的三种 +能力,而管家需要对它被问到的每个 Agent 都具备这些能力:发现有哪些 Agent 存在、哪些 +正在运行,在有界范围内观察其中一个,以及把一条有界请求交给其中一个。这条可复用契约 +就是 +[`peer_agent_directory_v0`](../../reference/protocols/peer-agent-directory-and-observation-v0.md)。 + +它不新增第六种共享状态。身份、工作、claim、lease 与规范修订仍然留在本文已经安排的 +位置;该契约贡献的是一个**面向 Agent 的视图**,以及读取与投递的规则。其中三条规则在 +这里最关键: + +- **presence 是 advisory 且按 provider 划定范围的。** live session 从不创造身份, + 没有 live session 的 Agent 仍然已注册、仍然拥有它的 claim、仍然是投递目标。provider + 用自己的 session-scoped handle 报告自己的位置,用自己的 liveness 词表;无法分类某个 + 目标的读取方报告 `unknown` 并点名覆盖缺口,而不是推断"已完成"或"没有进展"。 +- **观察与投递不授予任何东西。** 读取一个 peer、或把上下文交给它,都不是 claim、lease、 + 优先级、计划变更或修订。投递仍然是 `context_handoff`;Goal 要什么仍然只经 + `GoalAmendmentAuthority` 改变,工作状态仍然只经 canonical Todo、quota 与 lane owner + 改变。 +- **terminal-space provider 是 provider,不是契约本身。** 拥有终端的宿主面可以提供 + presence 与有界的实时输出,且必须声明:调用方如何证明自己在空间之内、detach 或重启 + 之后什么会保留、以及它无法恢复什么。没有这类 provider 时,directory 退化为"已注册 + 身份 + 持久工作状态"——这正是 prompt-only transport 的常态。 + ## 4. Authority matrix ### 4.1 `GoalAmendmentAuthority` 到底是什么 diff --git a/docs/reference/protocols/README.md b/docs/reference/protocols/README.md index 720d28754c..ea1e9b6805 100644 --- a/docs/reference/protocols/README.md +++ b/docs/reference/protocols/README.md @@ -41,6 +41,7 @@ scanning a chronological list. - [`material_lifecycle_architecture_v0`](material-lifecycle-architecture-v0.zh-CN.md): Material lifecycle architecture v0 (中文) - [`multi_agent_three_layer_minimality_contract_v0`](multi-agent-three-layer-minimality-v0.md): Multi-agent three-layer minimality v0 - [`multi_agent_visible_launcher_v0`](multi-agent-visible-launcher-v0.md): Multi-agent visible launcher v0 +- [`peer_agent_directory_v0`](peer-agent-directory-and-observation-v0.md): Peer agent directory, bounded observation and delivery v0 - [`peer_agent_runtime_v1`](peer-agent-runtime-v1.md): Peer agent runtime v1 - [`peer_supervisor_v0`](peer-supervisor-v0.md): Peer supervisor v0 - [`periodic_report_v0`](periodic-report-v0.md): Periodic report v0 diff --git a/docs/reference/protocols/peer-agent-directory-and-observation-v0.md b/docs/reference/protocols/peer-agent-directory-and-observation-v0.md new file mode 100644 index 0000000000..d89460b194 --- /dev/null +++ b/docs/reference/protocols/peer-agent-directory-and-observation-v0.md @@ -0,0 +1,234 @@ +# peer_agent_directory_v0 + +`peer_agent_directory_v0` is the reusable LoopX contract for one Agent +discovering, observing and delivering a bounded request to another Agent. It is +the Agent-facing companion of +[`agent_management_projection_v0`](agent-management-projection-v0.md): that +projection answers "what does the operator see", this contract answers "what may +a peer or a steward see and do about it", under the identity and authority rules +of [`peer_agent_runtime_v1`](peer-agent-runtime-v1.md) and the shared-intent +rules of +`docs/architecture/rfcs/shared-goal-alignment-and-governed-amendment-v0.md`. + +It exists because both the steward channel and the peer Agents inside one Goal +need the same three abilities, and each of them is currently answered by a +different internal surface: + +1. **Directory** — which Agents exist for this Goal, and which of them is + running right now; +2. **Observation** — what bounded state and output may I read about one of them; +3. **Delivery** — how may I hand one of them a bounded request, and what does a + successful hand-off actually prove? + +The contract is provider-neutral. A host surface that owns a terminal space may +supply *presence* and *live output* (see [Related work](#related-work)); a +prompt-only transport supplies neither, and the contract still works with the +durable half. + +## Sources Of Truth + +Nothing here is a new source of truth. + +| Field group | Canonical owner | +| --- | --- | +| Agent identity, registration, `agent_model` | Goal registry (`registered_agents`) | +| Work item, claim, lease/fence | `todo_id`, task lease, per-Agent frontier | +| Canonical intent and its revision | `shared_goal_intent_v0` | +| Delivery of context or a bounded request | `context_handoff` (with its receipt) | +| Lane, quota and next action | quota `interaction_contract`, lane contract | +| Terminal layout, pane and live process | the host surface that owns the terminal space | + +Two consequences follow, and both are rules rather than observations: + +- a live session never creates an Agent identity, and an Agent that has no live + session is still registered, still owns its claims, and is still a delivery + target; +- a host surface's view of the terminal is **advisory**. It is not evidence of + LoopX progress, and it may not overwrite any row in the table above. + +## Directory Packet + +```json +{ + "schema_version": "peer_agent_directory_v0", + "goal_id": "loopx-meta", + "collected_at": "2026-09-16T10:00:00Z", + "scope": "goal_registered_agents", + "rows": [ + { + "agent_id": "codex-alpha", + "registered": true, + "work": { + "todo_id": "todo_ab12", + "claimed": true, + "lease": "active" + }, + "presence": { + "provider": "terminal_space", + "provider_session_ref": "w1:p2", + "liveness": "working", + "observed_at": "2026-09-16T09:59:58Z", + "basis": "provider_detection" + }, + "observation_limits": ["provider_scrollback_bounded"] + } + ], + "limitations": ["presence_is_advisory", "presence_stale_after_provider_restart"] +} +``` + +Rules: + +- a row exists per registered Agent of the Goal, whether or not it is running; +- `presence` is optional and must carry `provider`, `observed_at` and `basis`, + so a reader can tell "not running" from "this machine cannot see it"; +- `provider_session_ref` is an opaque handle **inside one provider session**. + It is never a Goal identity, never stable across providers, and must not be + compared across machines or used as a Todo/Agent key; +- a provider's own in-space proof of context (for example an environment flag and + injected pane identifiers) may strengthen "I am inside this space". It never + replaces registry registration, and a failure of that proof means the reader + reports `unknown`, not `absent`. + +## Presence Vocabulary + +Presence answers "is this Agent runnable right now", not "is its work done". + +| `liveness` | Meaning | Must not be read as | +| --- | --- | --- | +| `working` | the provider observed the Agent executing | progress, or evidence of an outcome | +| `blocked` | the provider recognized a question or approval gate | work done, or permission to answer the gate | +| `idle` | the Agent is ready for input | a delivered request, or an available lease | +| `done` | the Agent settled and is ready for input | task completion, or a closed Todo | +| `unreachable` | the provider knows the target, and cannot reach it now | an empty lane, or missing work | +| `unknown` | the provider cannot classify the target | completion, or absence of progress | + +`done` and `idle` are both "ready for input" for a directory reader; the +provider's seen/unseen bookkeeping distinguishes them and is deliberately not +part of this contract. A reader that cannot obtain presence reports `unknown` +and names the coverage gap instead of inferring anything about the work. + +## Bounded Observation + +Observation prefers typed state and falls back to bounded output. + +1. **Typed first.** Work state, frontier, claims, lease facts, gates and + evidence come from LoopX projections (`shared_goal_alignment_v0`, + `agent_management_projection_v0`, the Agent-scoped evidence ledger), never + from parsing a terminal. +2. **Bounded output second.** When a caller needs what a peer actually said or + did, the provider may return a bounded excerpt: an explicit source + (rendered viewport, recent output, unwrapped recent output, detection + snapshot), an explicit line bound, and an explicit "this is advisory" label. +3. **Declared limits.** A provider must state its limits instead of silently + truncating: alternate-screen output that never enters scrollback, a cleared + viewport, a restarted server, a disconnected machine. +4. **Durable fallback.** When bounded output cannot carry the answer, the caller + asks the peer to write a durable artifact (file, Todo note, delivery + receipt) and reads that. A screen excerpt is never promoted to evidence. + +## Bounded Delivery + +Delivery hands a peer a bounded request or context. The contract separates four +facts that are easy to conflate: + +1. **Refusal before write.** If the target is at a question or approval gate, the + delivery is refused with a typed blocker (`agent_blocked`-style) and writes + nothing. Resolving that gate belongs to the gate's owner, not to the sender. +2. **Submission is not execution.** A successful submission proves bytes were + written in order. It does not prove the peer started a turn. +3. **Observed activity is the weaker-but-real signal.** Where the provider can + observe lifecycle, a delivery should also report whether activity followed + inside a declared window, with a typed `stalled` outcome when it did not, and + an expiry outcome when the sender's own timeout elapsed first. +4. **No blind resend.** A timeout or a stall does not prove the request was never + delivered, so the sender inspects state before repeating; `context_handoff` + delivery receipts remain the durable record that a delivery happened. + +## Authority And Scope + +- **Observation grants nothing.** Discovery and observation confer no claim, no + lease, no priority, no plan change, no merge and no permission. +- **Delivery is not a work edit.** Handing a peer context or a request stays + delivery. Changing what the Goal asks for stays an amendment + (`shared_acceptance`, `protected_authority`), and changing work state stays + with the canonical Todo, quota and lane owners. +- **No leader Agent.** A directory reader is not a scheduler for its peers. The + rules that forbid a leader agent, hidden scheduler, promotion authority or + second source of truth apply to this contract exactly as written for the + multi-agent launcher. +- **Scope is authorization, not convenience.** A reader sees only the Agents and + Goals its channel or Goal authorization covers. The directory must not become + a cross-tenant enumeration surface, and an out-of-scope target is reported as + a scope gap rather than as a missing Agent. +- **Host-surface control stays with the host.** Closing, moving or reconfiguring + another actor's terminal space is a host-surface action with the host's own + consent rules; it is not part of peer delivery. + +## Provider Contract + +A provider that supplies presence and live output must declare: + +1. how a caller proves it is inside the space (and that failing the proof means + `unknown`, not control); +2. opaque, session-scoped identifiers for its locations and occupants, plus the + rule for what happens to an identifier after a move, close or restart; +3. its liveness vocabulary and the mapping into the vocabulary above; +4. its observation sources and bounds, including what it cannot recover; +5. its refusal and error taxonomy for delivery (blocked target, stalled + submission, expired timeout, unreachable host); +6. its persistence claim: what survives a client detach, a server restart and a + machine restart. + +LoopX ships no requirement that a provider exists. With no provider, the +directory degenerates to registered identity plus durable work state, presence +is omitted, and delivery remains available through the durable hand-off path. + +## Related Work + +Herdr (`https://github.com/herdrdev/herdr`) is a terminal-space provider whose +Agent-facing skill documents the same three abilities from the other direction, +which is why it is a useful reference implementation of the provider half of +this contract: + +- it proves caller context with an environment flag plus injected workspace, tab + and pane identifiers, and instructs the Agent to stop when that proof fails; +- it separates a raw pane surface from a recognized-agent surface, and its + liveness vocabulary (`working`, `blocked`, `idle`, `done`, `unknown`) matches + the mapping above, including "`unknown` does not prove completion"; +- it exposes bounded observation with explicit sources and line bounds, and + names the alternate-screen limit that makes a larger read impossible; +- it refuses `agent prompt` at an approval gate before writing, reports a stalled + submission when no activity follows, and warns that a timeout does not prove + non-delivery; +- it owns terminals rather than wrapping Agents, keeps its identifiers + session-scoped, and restores layout without resurrecting processes. + +What LoopX adds, and a terminal-space provider cannot supply: durable Agent +identity, the canonical intent revision an Agent's frontier is based on, +claim/lease ownership, typed gates, and the authority rule that observation and +delivery grant nothing. + +## Non-Goals + +- No new agent registry, session table, pane inventory or message bus. +- No cross-machine identity: two providers may use the same identifiers for + different Agents, and neither is authoritative. +- No screen scraping as evidence, and no parsing a peer's terminal to decide + LoopX state. +- No control of another actor's terminal space, and no remote upgrade of a + provider to unlock a missing capability. + +## Acceptance Checks + +- A Goal with two registered Agents and one live session returns two rows: the + live one with presence, the other with registry identity and no presence. +- A provider that cannot classify a running Agent yields `unknown` with a named + coverage gap, and the answer never claims the peer made no progress. +- A delivery to a gated peer is refused with a typed blocker and writes nothing; + a stalled delivery reports `stalled` rather than success; a timeout never + triggers an automatic resend. +- With no provider at all, the directory still lists registered Agents and the + durable delivery path still works. +- No field added by this contract changes a Todo, a claim, a lease, quota or the + canonical intent.