Context
The Sunset Protocol currently emits the end-of-session handover to three surfaces: GitHub issue comments (ticket-scoped), chat to the human commander (interactive), and Sandman memory persistence (vector-store). It pre-dates the A2A mailbox substrate (add_message / list_messages) and does not leverage it.
When session 48197e2e booted at 2026-04-25T23:26Z (consuming the prior session's b5a17132 handover), the Sunset Protocol's "future-self entry point" pointed at Sandman memory ID a745b31e-4d1b-421e-b046-03a21de94c35. get_message returned "Message not found: a745b31e-..." — a durability gap between the writing session's vector-store write and the reading session's vector-store read. Boot fell back to fetching the three carry-over tickets directly via get_local_issue_by_id, which worked but is a less direct substrate match for "general session-arc state" (vs ticket-scoped state).
The mailbox substrate (Nodes table in SQLite, surfaced via A2A graph topology with SENT_TO/SENT_BY edges) has stronger durability guarantees than the Chroma vector store. A self-DM via add_message(to: '<own-identity>', ...) written at sunset, read via list_messages at boot, closes the durability gap with a complementary lightweight bridge.
The change also progresses the broader wakeup-events goal (collaboration target with Gemini): validating the self-routing path of A2A (sender = receiver = same identity node) is a substrate-confidence dividend. Same identity binding, same SENT_TO/SENT_BY edge mechanics that wakeup events depend on.
The Problem
Three failure modes in the current Sunset Protocol:
- Sandman memory durability gap. Vector-store writes from session N may not be retrievable in session N+1 (collection rebuild, embedding-version mismatch, missing message ID, etc.). Empirically observed this session.
- Substrate redundancy without primary owner. GitHub issue comments are public + ticket-scoped; chat to human is human-mediated; Sandman memory is the intended cross-session bridge but has the durability gap. No single substrate cleanly owns "the next-session greeting from past-self."
- Identity self-sufficiency miss. Agents have stable identities (
@neo-opus-ada, @neo-gemini-pro) but the protocol doesn't use the agent's own mailbox as a persistence substrate. "Get a heads-up from yesterday" via list_messages would immediately clarify "this is not a standalone session."
The Architectural Reality
Current state:
AGENTS.md §14 (A2A Contextual Bridge Protocol — End of Session Handoff) codifies the Origin Session ID embedding pattern. Three steps: horizon scan, telemetry payload, ingestion mandate.
AGENTS_STARTUP.md §6 (Memory Core check) covers boot Memory Core healthcheck + get_context_frontier() + get_all_summaries() + sandman_handoff.md parse.
- A2A mailbox tools
add_message / list_messages are operational (per ai/mcp/server/memory-core/openapi.yaml /mailbox/messages paths).
- Healthcheck identity block surfaces
identity.source (env-var | gh-cli | oidc | unresolved) and identity.bound — provides the gate for "is the agent's identity stable enough to write a self-DM."
What needs to change:
AGENTS.md §14 extended with a step: at session end, if identity is bound, send a handover self-DM via add_message(to: '<own-identity>', subject: 'Sunset Protocol Handover — session <ID>', taggedConcepts: ['sunset-protocol-handover'], originSessionId, ...).
AGENTS_STARTUP.md §6 extended with a step: at boot, after Memory Core healthcheck, call list_messages({status: 'unread'}) (or with taggedConcepts filter once supported) and parse messages tagged sunset-protocol-handover. Apply context, then mark_read.
The Fix
Phase 1 (this ticket's MVP scope):
AGENTS.md §14 extension — add step "End-of-Session Self-DM":
- Trigger condition: at sunset, if
healthcheck() returns identity.bound: true.
- Call
add_message({to: '<own-identity>', subject, body, taggedConcepts: ['sunset-protocol-handover'], originSessionId}).
body mirrors the handover narrative posted to ticket comments — implementation guidance, mental-model state, carry-over tickets, pickup signal.
taggedConcepts MUST include sunset-protocol-handover for list_messages filtering.
originSessionId MUST be the sunsetting session ID.
- Failure mode: if
identity.bound: false or add_message errors, skip self-DM gracefully — GitHub comments + Sandman memory remain the canonical surfaces.
AGENTS_STARTUP.md §6 extension — add step "Self-Handover Mailbox Check":
- Placement: after Memory Core healthcheck +
get_context_frontier() + get_all_summaries(), before the existing sandman_handoff.md parse.
- Call
list_messages({status: 'unread'}) (or with taggedConcepts filter once supported).
- For each unread message tagged
sunset-protocol-handover: parse body, apply context, optionally mark_read (or batch at end of boot).
- Multiple stacked handovers (multi-session sunset without resume): read in chronological order; latest wins for state but earlier ones provide context drift.
Acceptance Criteria
Out of Scope
- Implementing
taggedConcepts server-side filter on list_messages — parser-layer filtering is fine for MVP; server-side push-down is an optimization for later if message volume grows.
@self sentinel resolution in add_message — explicit identity is sufficient; sentinel sugar is premature.
- Cross-agent (A → B) sunset handover — different shape; ticket comments + Origin Session ID already cover this surface.
- Multi-handover consolidation / rollup — read-each-in-order is fine for MVP; only optimize if backlog grows large.
- Sunset-protocol-as-skill graduation — currently codified inline in
AGENTS.md; promotion to a .agent/skills/sunset-protocol/ Progressive Disclosure skill is a separate decision if the protocol grows beyond a few paragraphs.
- Changes to Sandman memory write path — vector-store durability is a #9999 / #10030 concern; this ticket adds a complementary substrate, not a replacement.
Avoided Traps
- "Replace Sandman memory with mailbox" framing — rejected. Sandman memory serves the Retrospective daemon (semantic search across the corpus); self-mailbox handover serves future-self only. Both substrates have distinct consumers; both stay.
- "Broadcast handover to
@AGENT:*" — rejected. Pollutes other agents' inboxes with another agent's session-arc state. Identity-scoped self-DM is correct routing.
- "Always self-DM unconditionally" — rejected. If
identity.source === 'unresolved' (single-tenant fallthrough or env-var missing), the self-DM has no durable destination. Identity-bound gate is mandatory.
- "Skip GitHub ticket comments if self-DM is the new substrate" — rejected. GitHub comments serve human commanders + cross-agent handoff (next agent picking up the ticket); self-DM serves future-self only. Both surfaces have distinct consumers; both stay.
- "Tag with session ID instead of
taggedConcepts" — rejected. taggedConcepts: ['sunset-protocol-handover'] is the routing key; originSessionId provides per-message provenance. Two distinct fields, two distinct purposes.
- "Inline a link to external state in
body" — rejected. Body is rich markdown self-contained; don't link to state that may not be retrievable next session.
Related
AGENTS.md §14 — current End-of-Session protocol (this ticket extends it).
AGENTS_STARTUP.md §6 — current Memory Core boot check (this ticket extends it).
- #9999 — Cloud-Native KB epic; addresses Sandman memory durability gap at substrate level. Complementary, not blocking.
- #10030 — Native Edge Graph topology; same domain as Sandman memory.
- #10347 — Antigravity-side intermittent SENT_TO cull; gates reliable mailbox routing for Gemini's resume path. Claude-side path is stable per empirical evidence.
- #10341 (PR #10348) — pr-review §5.3 MCP-tool-description budget audit; tangentially related as both touch agent-facing infrastructure discipline.
Origin Session ID: 48197e2e-3e95-47eb-9eb8-bbb032948845
Retrieval Hint: query_raw_memories(query='sunset protocol self-DM mailbox handover boot pickup list_messages add_message taggedConcepts identity-bound')
Context
The Sunset Protocol currently emits the end-of-session handover to three surfaces: GitHub issue comments (ticket-scoped), chat to the human commander (interactive), and Sandman memory persistence (vector-store). It pre-dates the A2A mailbox substrate (
add_message/list_messages) and does not leverage it.When session
48197e2ebooted at 2026-04-25T23:26Z (consuming the prior session'sb5a17132handover), the Sunset Protocol's "future-self entry point" pointed at Sandman memory IDa745b31e-4d1b-421e-b046-03a21de94c35.get_messagereturned"Message not found: a745b31e-..."— a durability gap between the writing session's vector-store write and the reading session's vector-store read. Boot fell back to fetching the three carry-over tickets directly viaget_local_issue_by_id, which worked but is a less direct substrate match for "general session-arc state" (vs ticket-scoped state).The mailbox substrate (
Nodestable in SQLite, surfaced via A2A graph topology with SENT_TO/SENT_BY edges) has stronger durability guarantees than the Chroma vector store. A self-DM viaadd_message(to: '<own-identity>', ...)written at sunset, read vialist_messagesat boot, closes the durability gap with a complementary lightweight bridge.The change also progresses the broader wakeup-events goal (collaboration target with Gemini): validating the self-routing path of A2A (sender = receiver = same identity node) is a substrate-confidence dividend. Same identity binding, same SENT_TO/SENT_BY edge mechanics that wakeup events depend on.
The Problem
Three failure modes in the current Sunset Protocol:
@neo-opus-ada,@neo-gemini-pro) but the protocol doesn't use the agent's own mailbox as a persistence substrate. "Get a heads-up from yesterday" vialist_messageswould immediately clarify "this is not a standalone session."The Architectural Reality
Current state:
AGENTS.md §14(A2A Contextual Bridge Protocol — End of Session Handoff) codifies the Origin Session ID embedding pattern. Three steps: horizon scan, telemetry payload, ingestion mandate.AGENTS_STARTUP.md §6(Memory Core check) covers boot Memory Core healthcheck +get_context_frontier()+get_all_summaries()+sandman_handoff.mdparse.add_message/list_messagesare operational (perai/mcp/server/memory-core/openapi.yaml/mailbox/messagespaths).identity.source(env-var | gh-cli | oidc | unresolved) andidentity.bound— provides the gate for "is the agent's identity stable enough to write a self-DM."What needs to change:
AGENTS.md §14extended with a step: at session end, if identity is bound, send a handover self-DM viaadd_message(to: '<own-identity>', subject: 'Sunset Protocol Handover — session <ID>', taggedConcepts: ['sunset-protocol-handover'], originSessionId, ...).AGENTS_STARTUP.md §6extended with a step: at boot, after Memory Core healthcheck, calllist_messages({status: 'unread'})(or withtaggedConceptsfilter once supported) and parse messages taggedsunset-protocol-handover. Apply context, thenmark_read.The Fix
Phase 1 (this ticket's MVP scope):
AGENTS.md §14extension — add step "End-of-Session Self-DM":healthcheck()returnsidentity.bound: true.add_message({to: '<own-identity>', subject, body, taggedConcepts: ['sunset-protocol-handover'], originSessionId}).bodymirrors the handover narrative posted to ticket comments — implementation guidance, mental-model state, carry-over tickets, pickup signal.taggedConceptsMUST includesunset-protocol-handoverforlist_messagesfiltering.originSessionIdMUST be the sunsetting session ID.identity.bound: falseoradd_messageerrors, skip self-DM gracefully — GitHub comments + Sandman memory remain the canonical surfaces.AGENTS_STARTUP.md §6extension — add step "Self-Handover Mailbox Check":get_context_frontier()+get_all_summaries(), before the existingsandman_handoff.mdparse.list_messages({status: 'unread'})(or withtaggedConceptsfilter once supported).sunset-protocol-handover: parse body, apply context, optionallymark_read(or batch at end of boot).Acceptance Criteria
AGENTS.md §14extended with the End-of-Session Self-DM step (trigger condition, call shape,taggedConceptsmandate, identity-bound gate, failure mode).AGENTS_STARTUP.md §6extended with the Self-Handover Mailbox Check step (placement, call shape, parsing/marking semantics, multi-handover ordering).AGENTS.md §14andAGENTS_STARTUP.md §6are bidirectional (each cites the other).taggedConcepts: ['sunset-protocol-handover']codified in both docs as the canonical retrieval key.AGENTS.md §14(skip self-DM ifidentity.source === 'unresolved').48197e2e'sget_message(a745b31e-...)"Message not found" failure as the durability-gap motivator.pull-requestandpr-reviewskills (likely no change — sunset is session-arc scope, not PR-cycle scope).Out of Scope
taggedConceptsserver-side filter onlist_messages— parser-layer filtering is fine for MVP; server-side push-down is an optimization for later if message volume grows.@selfsentinel resolution inadd_message— explicit identity is sufficient; sentinel sugar is premature.AGENTS.md; promotion to a.agent/skills/sunset-protocol/Progressive Disclosure skill is a separate decision if the protocol grows beyond a few paragraphs.Avoided Traps
@AGENT:*" — rejected. Pollutes other agents' inboxes with another agent's session-arc state. Identity-scoped self-DM is correct routing.identity.source === 'unresolved'(single-tenant fallthrough or env-var missing), the self-DM has no durable destination. Identity-bound gate is mandatory.taggedConcepts" — rejected.taggedConcepts: ['sunset-protocol-handover']is the routing key;originSessionIdprovides per-message provenance. Two distinct fields, two distinct purposes.body" — rejected. Body is rich markdown self-contained; don't link to state that may not be retrievable next session.Related
AGENTS.md §14— current End-of-Session protocol (this ticket extends it).AGENTS_STARTUP.md §6— current Memory Core boot check (this ticket extends it).Origin Session ID:
48197e2e-3e95-47eb-9eb8-bbb032948845Retrieval Hint:
query_raw_memories(query='sunset protocol self-DM mailbox handover boot pickup list_messages add_message taggedConcepts identity-bound')