Skip to content

Let notices target a lineage conversation: recipient.conversation / recipient.root matched against request.lineage #458

Description

@ScriptedAlchemy

Problem

A notice cannot be addressed to one agent conversation. AgentRecipient has actor | host | session | workspace, and the notice principal is built from the same four axes — lineage is not part of it. So a plugin that wants to tell the other subagent something ("you and I are both editing src/shared.ts") can only target:

The #99 scope note (2026-09-03) says directed notices "should target session, workspace, or the conversation tree via request.lineage" — but the kernel has no recipient axis for that yet.

Evidence (main @ 284141958)

  • packages/rsc-runtime/src/notices/contract.ts:34-39 (AgentRecipient), :41-46 (AgentNoticePrincipal: actor/host/session/workspace).
  • packages/rsc-runtime/src/agent-request.ts:493-499openRequest({ principal: { actor, host, session, workspace } }); lineage is on the request (:489, :505) but not on the principal.
  • packages/rsc-runtime/src/notices/state.ts:185-202recipientMatchesPrincipal compares the four axes only.
  • packages/agent-bundle/src/mcp-server-runtime.ts:134-150actor is http.authInfo.clientId; :759-788 — event scopes mount host/session/workspace/lineage, no actor. Same for standalone hooks, packages/agent-bundle/src/adapters/hook-contract.ts:730-741.
  • packages/rsc-runtime/src/lineage-native.ts:40-54 — Claude/Codex: conversation = agent_id ?? session_id, root = session_id; Cursor: conversation = conversation_id.
  • examples/worktree-proximity/src/events/tool/before.tsx:67-82 — publishes with recipient: { workspace: { root: conflict.worktreeRoot } } while dedupeKey still names the target actor.
  • examples/worktree-proximity/README.md:96-102: "Generated event principals in v1 mount host, session, and workspace identity, but not actor identity. Proximity notices therefore target the recipient worktree through recipient.workspace.root … Actor-directed delivery remains future work tied to actor-principal mounting in the Add recipient-aware notices and capability-gated delivery #99/Track remaining #98 state-kernel scope: warm-runtime process state, generated-runtime state mounting, budgets, lifetime visibility #233 lineage."
  • README.md:77-81: tool envelopes carry no agent_id, so peers in one directory collapse to the derived worktree:<root> identity — the workspace axis cannot separate two agents in one worktree.

Proposed shape (small)

interface AgentRecipient {
  // …existing…
  /** Matches when request.lineage.conversation === conversation (a specific agent thread). */
  readonly conversation?: string;
  /** Matches when request.lineage.root === root (every agent under one root). */
  readonly root?: string;
}
interface AgentNoticePrincipal {
  // …existing…
  readonly lineage: Observed<AgentLineage>;
}

recipientMatchesPrincipal treats an unavailable lineage like an unavailable axis today (no match). Ledger schema gains two optional recipient fields — no state-definition id bump needed if the schema is additive (state.ts notice schema). The next-event admission, inbox, resources/updated, and receipt discipline are unchanged; attempted stays the strongest state, exactly as #99 records.

Design question (from the same use-case): is a thin peer-messaging façade worth adding on top — notices.send({ to: { conversation }, content }) / notices.read() — or is the recipient axis enough and the façade stays app-level? The #99 survey already establishes that no pinned host offers a directed push channel, so the façade would only be sugar over publish + next-event admission.

Out of scope / related

Acceptance

In examples/worktree-proximity: tool/before.tsx publishes with recipient: { conversation: <other actor's lineage conversation> }; the route-unit test "attempts and surfaces a notice on the recipient next event" (tests/route-unit/routes.test.ts) passes with two actors bound to the same worktree (today impossible), and the cross-process journey suite (packages/agent-bundle/tests/worktree-proximity-journeys.test.ts) still proves workspace-directed delivery for the existing journeys. A new ledger test proves a conversation-addressed notice is not admitted on a sibling's event.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthost-integrationAgent host capabilities, projection, discovery, and lifecycleruntimeRuntime context, state, rendering, or execution

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions