Latest verdict
- Status:
VALID
- Checked at:
2026-09-02T12:04:40Z
- Evidence: Remote default branch
main remains 2f3ddab. A live public-API probe on that commit showed both recipients initially receiving one instruction, then agent A's global done update removing it from agent B's open inbox immediately and after restart/JSONL replay. The current event model, status update and replay, and inbox filtering remain event-wide; issue #8 is unassigned with no comments, no issue or PR supersedes it, and make verify passes.
Area
New API, UI, or Deployment Capabilities
Candidate
Add recipient-scoped inbox status to targeted events, so each human or agent can acknowledge and complete a shared instruction independently without clearing it from every other recipient's inbox.
Why this should be the next strategic priority
Agora already supports fan-out: an event can target several agents, all is a wildcard target, and the reporting skill tells each agent to acknowledge and complete actionable inbox items. But lifecycle state is one scalar on the event.
That makes every multi-target instruction behave like an accidental single-consumer queue. The first recipient to mark it done, resolved, or rejected changes the event globally, so the item disappears from every recipient's actionable inbox. A coordinator also cannot distinguish partial handling from completion by everyone.
This blocks several high-value workflows at their foundation:
- Parallel coding agents cannot independently accept and finish the same review, validation, or rollout instruction.
- A human cannot broadcast a decision to
all while retaining it for agents that have not acknowledged it.
- CI, reviewer, and deployer handoffs cannot show which consumers have acted.
- Teams must duplicate events per recipient, fragmenting the shared timeline and undermining multi-target events.
Integrations would inherit this ambiguity. Fixing recipient ownership first makes Agora's existing event and inbox model safe to extend.
Current behavior
Event has multiple Targets but only one Status.
UpdateStatus records the actor and overwrites that one status without considering recipients.
- JSONL replay applies a
status_change globally and does not retain actor-specific handling state.
- Inbox filtering evaluates the event-wide status for every target.
- The server exposes only the event-wide status endpoint, and the CLI always uses it.
- The browser actions also update status globally for the selected actor.
- The reporting skill requires every recipient to acknowledge and complete actionable inbox items, which is unsafe for multi-target and
all events today.
The current behavior reproduces with one instruction:
POST /api/events
Content-Type: application/json
{
"type": "instruction",
"actor": "human",
"thread": "release",
"title": "Validate release",
"targets": ["agent-a", "agent-b"]
}
Both open inboxes initially contain the event. When agent A uses the current status API:
POST /api/events/<event-id>/status
Content-Type: application/json
{"actor":"agent-a","status":"done"}
the result is:
agent-a open inbox before: [<event-id>]
agent-b open inbox before: [<event-id>]
agent-a marks done: event.status=done
agent-a open inbox after: []
agent-b open inbox after: []
agent-b after restart: []
The JSONL log contains actor: "agent-a" on one status_change, but replay applies it globally. The same failure applies to targets: ["all"].
Proposed design
Keep global lifecycle and add recipient handling
Retain the current endpoint and Event.status semantics for intentional event-wide transitions:
POST /api/events/<event-id>/status
{"actor":"human","status":"resolved"}
Add a recipient-scoped operation:
POST /api/agents/agent-a/inbox/<event-id>/status
Content-Type: application/json
{"actor":"agent-a","status":"done"}
- Require the event to target the recipient directly or through
all.
- Reuse the existing status vocabulary instead of adding a parallel lifecycle.
- Store both
recipient and actor; they are normally equal, but retaining both preserves the audit trail when an operator acts on behalf of an agent.
- Treat recipient state as coordination metadata, not authentication. Local, shared-token, and Kubernetes deployments keep their existing bearer-token behavior.
For an agent inbox, derive effective status in this order:
- A terminal global status (
done, resolved, or rejected) closes the event for everyone.
- Otherwise, use that recipient's latest status when present.
- Otherwise, fall back to the global event status.
Apply open=true and repeated status filters to effective status before applying limit.
Keep responses event-shaped and add optional fields only:
{
"id": "evt_...",
"status": "open",
"targets": ["agent-a", "agent-b"],
"recipient_status": "done",
"recipient_statuses": {
"agent-a": "done",
"agent-b": "acknowledged"
}
}
An inbox response needs only recipient_status for its named recipient. Timeline and detail responses may include recipient_statuses so a coordinator can see partial completion. status remains the canonical global lifecycle; no automatic global closure is required.
Persist receipts additively
Append a new JSONL record kind:
{
"kind": "recipient_status_change",
"recipient_status": {
"event_id": "evt_...",
"recipient": "agent-a",
"actor": "agent-a",
"status": "done",
"created_at": "..."
}
}
Replay it into an event ID -> recipient -> latest status index. Existing event and status_change records retain their current meaning, so existing JSONL files need no migration. For all, create recipient entries lazily as agents act; Agora does not need an agent registry.
Update first-party consumers
- Add
agora status --recipient agent-a <event-id> done; keep unscoped agora status global for compatibility and coordinator use.
- Change
skills/agora-reporting to use recipient-scoped status for work obtained from the agent's inbox.
- When the browser's selected actor is a direct or
all target, make acknowledge and done actions recipient-scoped and render that actor's effective status. Keep global closure as an explicit coordinator action.
- Do not add environment variables, per-agent tokens, or Kubernetes resources.
Compatibility
- Existing API clients and the global status endpoint retain their behavior.
- Existing event fields, status values, target matching, and forward polling remain valid.
- Added response fields are optional and can be ignored by old clients.
- Existing JSONL logs replay unchanged; missing recipient state falls back to global status.
AGORA_URL, AGORA_AGENT, AGORA_THREAD, and AGORA_TOKEN keep their meanings.
- A global terminal update remains available when a coordinator wants to close the event for everyone.
Acceptance criteria
- An open instruction targeted to
agent-a and agent-b appears in both open inboxes.
- After agent A acknowledges and completes it through the recipient endpoint, it leaves agent A's actionable inbox but remains actionable for agent B.
- Agent B can independently acknowledge and complete the same event.
- The same isolation works for
all, with recipient records created lazily.
- A terminal global update still removes the event from every recipient's open inbox.
- Inbox
open and repeated status filters use recipient-effective state before applying limit.
- Recipient changes survive restart, while a fixture containing only existing JSONL record kinds replays identically.
- Updating a recipient not targeted by the event returns a focused
400 response.
- The CLI and browser use recipient-scoped updates when handling targeted inbox work.
- The reporting skill's acknowledge/complete loop cannot clear another recipient's item.
- Tests cover two explicit recipients,
all, global closure, filtering before limit, persistence/replay, and unchanged existing-client behavior.
make verify passes.
Latest verdict
VALID2026-09-02T12:04:40Zmainremains 2f3ddab. A live public-API probe on that commit showed both recipients initially receiving one instruction, then agent A's globaldoneupdate removing it from agent B's open inbox immediately and after restart/JSONL replay. The current event model, status update and replay, and inbox filtering remain event-wide; issue #8 is unassigned with no comments, no issue or PR supersedes it, andmake verifypasses.Area
New API, UI, or Deployment Capabilities
Candidate
Add recipient-scoped inbox status to targeted events, so each human or agent can acknowledge and complete a shared instruction independently without clearing it from every other recipient's inbox.
Why this should be the next strategic priority
Agora already supports fan-out: an event can target several agents,
allis a wildcard target, and the reporting skill tells each agent to acknowledge and complete actionable inbox items. But lifecycle state is one scalar on the event.That makes every multi-target instruction behave like an accidental single-consumer queue. The first recipient to mark it
done,resolved, orrejectedchanges the event globally, so the item disappears from every recipient's actionable inbox. A coordinator also cannot distinguish partial handling from completion by everyone.This blocks several high-value workflows at their foundation:
allwhile retaining it for agents that have not acknowledged it.Integrations would inherit this ambiguity. Fixing recipient ownership first makes Agora's existing event and inbox model safe to extend.
Current behavior
Eventhas multipleTargetsbut only oneStatus.UpdateStatusrecords the actor and overwrites that one status without considering recipients.status_changeglobally and does not retain actor-specific handling state.allevents today.The current behavior reproduces with one instruction:
Both open inboxes initially contain the event. When agent A uses the current status API:
the result is:
The JSONL log contains
actor: "agent-a"on onestatus_change, but replay applies it globally. The same failure applies totargets: ["all"].Proposed design
Keep global lifecycle and add recipient handling
Retain the current endpoint and
Event.statussemantics for intentional event-wide transitions:Add a recipient-scoped operation:
all.recipientandactor; they are normally equal, but retaining both preserves the audit trail when an operator acts on behalf of an agent.For an agent inbox, derive effective status in this order:
done,resolved, orrejected) closes the event for everyone.Apply
open=trueand repeatedstatusfilters to effective status before applyinglimit.Keep responses event-shaped and add optional fields only:
{ "id": "evt_...", "status": "open", "targets": ["agent-a", "agent-b"], "recipient_status": "done", "recipient_statuses": { "agent-a": "done", "agent-b": "acknowledged" } }An inbox response needs only
recipient_statusfor its named recipient. Timeline and detail responses may includerecipient_statusesso a coordinator can see partial completion.statusremains the canonical global lifecycle; no automatic global closure is required.Persist receipts additively
Append a new JSONL record kind:
{ "kind": "recipient_status_change", "recipient_status": { "event_id": "evt_...", "recipient": "agent-a", "actor": "agent-a", "status": "done", "created_at": "..." } }Replay it into an
event ID -> recipient -> latest statusindex. Existingeventandstatus_changerecords retain their current meaning, so existing JSONL files need no migration. Forall, create recipient entries lazily as agents act; Agora does not need an agent registry.Update first-party consumers
agora status --recipient agent-a <event-id> done; keep unscopedagora statusglobal for compatibility and coordinator use.skills/agora-reportingto use recipient-scoped status for work obtained from the agent's inbox.alltarget, make acknowledge and done actions recipient-scoped and render that actor's effective status. Keep global closure as an explicit coordinator action.Compatibility
AGORA_URL,AGORA_AGENT,AGORA_THREAD, andAGORA_TOKENkeep their meanings.Acceptance criteria
agent-aandagent-bappears in both open inboxes.all, with recipient records created lazily.openand repeatedstatusfilters use recipient-effective state before applyinglimit.400response.all, global closure, filtering before limit, persistence/replay, and unchanged existing-client behavior.make verifypasses.