Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 决策
Expand Down Expand Up @@ -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` 到底是什么
Expand Down
1 change: 1 addition & 0 deletions docs/reference/protocols/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
234 changes: 234 additions & 0 deletions docs/reference/protocols/peer-agent-directory-and-observation-v0.md
Original file line number Diff line number Diff line change
@@ -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.