Round.propose
Round.propose({ id, proposerId, voters, quorum })
Constructs a new pending round. Throws if voters are empty or quorum is unreachable.
A September 2026 analysis of every major agent interoperability protocol -- MCP, A2A, ACP, ANP, ERC-8004 -- found that voting and dissent preservation are universally absent. Agora is a reference implementation of exactly those missing primitives.
agora answers one question: how do a group of agents jointly decide, dissent, and record why -- without a new protocol?
Ties resolve to "rejected". A veto short-circuits the round regardless of the vote tally. Resolution is idempotent -- calling evaluate() again after resolution returns the same Resolution.
A veto reason is mandatory: an unexplained veto isn't auditable.
import { Round } from "agora-protocol";
const round = Round.propose({
id: "delete-prod-bucket",
proposerId: "cleanup-agent",
voters: ["cleanup-agent", "ops-agent"],
vetoers: ["safety-agent"],
quorum: { type: "count", value: 2 },
});
round.castVote({ agentId: "cleanup-agent", choice: "yes" });
round.castVeto({ agentId: "safety-agent", reason: "no confirmed backup" });
round.evaluate();
// { outcome: "vetoed", ... } -- unanimous "yes" still loses
Round.propose({ id, proposerId, voters, quorum })
Constructs a new pending round. Throws if voters are empty or quorum is unreachable.
round.castVote({ agentId, choice }) / castVeto({ agentId, reason })
Register a vote or a blocking veto. Duplicate votes are last-write-wins.
round.evaluate(now?)
Resolves if veto, timeout, or quorum applies -- checked in that order. Idempotent once resolved.
Every major agent interoperability protocol handles messaging and tool calls -- none define a quorum primitive, a preference-aggregation rule, or a way to record that a proposal was rejected and why. Every team currently hand-rolls this logic, differently, inside their own orchestration code.
Agora is a small, dependency-free state machine for propose → vote/veto → resolve, plus reference adapters for MCP and A2A.
round: delete-prod-bucket
cleanup-agent yes · ops-agent yes
safety-agent VETO: "no confirmed backup"
evaluate() → outcome: vetoed
unanimous "yes" still loses to one veto