A ResponseObligation records that one accepted conversation request demands
an answer from one exact responsible recipient harness, and tracks whether
that answer was durably recognized. It is opt-in, separate from delivery
custody, and can never be satisfied by prose or by an unrelated reply.
Add the strict response_obligation spec to a post or structured_request
conversation action. The spec is part of the exact request payload digest.
{
"kind": "structured_request",
"request_type": "inventory.lookup",
"arguments": {"sku": "ABC-123"},
"response_obligation": {
"response_required": true,
"responsible_harness_id": "harness-abc",
"deadline_at": "2026-07-14T12:00:00+00:00",
"response_schema_id": "inventory.lookup.result.v1",
"response_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {"quantity": {"type": "integer", "minimum": 0}},
"required": ["quantity"],
"additionalProperties": false
}
}
}Rules:
response_requiredmust betrue; omitresponse_obligationentirely for informational content that does not create answer ownership;- the requester must be the request author and hold the
conversation.response_obligation.createentitlement for the conversation; - exactly one responsible recipient harness is bound; with a single recipient
the spec may omit
responsible_harness_id, otherwise it is mandatory and must be one of the recipients; - the deadline, when present, must be timezone-aware and in the future;
response_schema_idandresponse_schemamust be supplied together. The schema must be valid, self-contained JSON Schema 2020-12, is bounded to 64 KiB, and is stored with an exact digest as part of the request transaction;- the obligation row commits in the same transaction as request acceptance; an idempotent request retry never creates a second obligation and returns the existing obligation identifier, state, and revision;
- multi-recipient
any/all/quorum rules are not implemented; create one obligation per responsible recipient.
created -> recipient_committed -> acknowledged -> in_progress
| | \ | \
| | pending_human <-> blocked
v v v
(terminal) completed | failed | canceled | expired
| State | Owner | Meaning |
|---|---|---|
created |
requester transaction | request accepted, obligation open |
recipient_committed |
mirrored from mailbox | the durable recipient record proves custody; never independently asserted |
acknowledged |
responsible recipient | recipient explicitly owns the question |
in_progress |
responsible recipient | work started |
pending_human |
responsible recipient | waiting on a human decision |
blocked |
responsible recipient | cannot proceed; stays owned |
completed / failed |
typed response only | terminal, atomically linked to the accepted obligation_response event |
canceled |
exact requester | terminal withdrawal |
expired |
reconciliation | terminal execution of the deadline bound at creation |
Every transition is revision-fenced, recorded in
response_obligation_transitions, and audited.
Only the typed obligation_response conversation action closes an
obligation. It must be posted by the exact responsible recipient harness and
repeat the original binding:
{
"kind": "obligation_response",
"obligation_id": "…",
"request_event_id": "…",
"request_digest": "<sha256 of the exact request payload>",
"outcome": "completed",
"body": "answer text",
"response_schema_id": "inventory.lookup.result.v1",
"structured_response": {"quantity": 4}
}A wrong request event ID, wrong digest, wrong harness, missing demanded
response_schema_id, structured output that fails the exact stored schema, or
an already-terminal obligation fails closed. The
response event and the terminal obligation state commit in one transaction,
so the system can never report awaiting peer after the answer is durable.
A duplicate idempotent retry returns the original acceptance; a second,
different terminal response conflicts.
POST /v1/response-obligations/reconcile (or agentnet obligation reconcile) is idempotent and restart/offline-safe. For the calling verified
party it:
- moves
createdobligations torecipient_committedexactly when the durable mailbox recipient fact already proves commitment; and - moves the caller's own overdue requested obligations to
expired.
It mints no new authority and consumes no fresh policy decision; both
mutations re-execute already-authorized durable facts. Overdue visibility
never depends on reconciliation: the overdue inbox counter is derived at
read time.
The common background supervisor calls reconciliation and refreshes the content-free inbox counters after startup, reconnect, a live wake, and the bounded cursor-reconciliation fallback. It commits the encrypted counter snapshot to the local SQLite/WAL queue before exposing the passive count, so a restart cannot silently erase known answer ownership. This behavior is shared by every harness adapter; it is not Pi-specific and it never injects message content into an active user conversation.
GET /v1/response-obligations/{id}— exact fetch with full transition history; requester and responsible authorities only. Active sibling harnesses share their human principal's visibility, while only the exact responsible harness may claim progress or post the terminal response. Revoked harnesses fail closed.GET /v1/response-obligations?role=&state=&limit=— participant-scoped list.GET /v1/response-obligations/inbox— content-free counters:unread_information(mailbox items with no obligation for me),action_required(I must answer),awaiting_peer(I asked, peer owes),awaiting_human(pending_humaneither side),overdue(open past deadline),failed(my requests that terminally failed).overdueintentionally overlaps the ownership counters.
The credential-free local adapter surface exposes the same journey through MCP and direct Unix IPC. Identity comes only from the supervisor-bound harness session; none of these tools accepts actor, principal, credential, or domain arguments.
agentnet.conversation.create,.action, and.threadagentnet.obligation.inbox,.list,.get,.transition,.cancel, and.reconcile
The strict conversation action accepts both requests carrying
response_obligation and typed obligation_response closures. Installed
harnesses therefore do not need to hand-craft signed HTTP requests.
| Action | Used by |
|---|---|
conversation.response_obligation.create |
requester, at request post |
conversation.response_obligation.respond |
responsible recipient, at typed response |
conversation.response_obligation.update |
responsible recipient progress transitions |
conversation.response_obligation.cancel |
requester cancellation |
Reads and reconciliation validate current actor state and participant scope; they do not consume entitlements.