Trust, reputation and negotiation between agents
Status: draft 0.1 with reference implementations in agent_index/trust.py and agent_index/negotiate.py. Covers friction #27 (no shared trust or reputation layer) and #29 (no negotiation protocol). Both sit in the "Later" quadrant of the matrix: they only pay off when many independent parties take part, but the pieces work today between any two agents.
Trust and reputation
Problem. Every agent re-verifies everything it is told, because nothing records which agents, services or sources were right before.
Design. Build on signed identities (agent-identity):
- Attestations. After an interaction, a party signs a small statement about another key:
{"about": "ed25519:...", "claim": "delivered_as_described" | "data_correct" | "data_wrong" | "paid" | "refunded", "evidence": "<ledger entry hash or URL>", "at": ...}. Evidence is required, so a claim can be checked, not just believed. - Logs, not scores. Attestations go to append-only public logs (the same hash-chaining used by the payment ledger). Anyone can compute a reputation from them with their own weighting. There is no single score to game or buy.
- Weight by stake and history. Whoever computes a reputation names anchors: keys they already trust, such as themselves or merchants they have paid. Trust flows outward from the anchors (as in EigenTrust): a signer's statements count in proportion to how far the signer's own score sits above neutral, so fresh keys carry no weight. Each signer counts once per subject, and attestations backed by a payment receipt count double. A farm of new keys can't outvote real, receipted customers; the tests show it.
- Source trust in the index. agent-index already stores provenance per page. Adding "this claim from this page was later contradicted" (from
verify.pyfailures) gives a per-source accuracy history that search can use as a ranking signal.
Built. corroborate(claim, source, references) checks a claim taken from one site against pages on other sites. A reference that supports it corroborates the source; a reference on the same subject with different numbers or names contradicts it. A site can't corroborate itself. Agents can also report_source when a source proved right or wrong. The per-domain accuracy rate (with a neutral prior) multiplies search scores and shows up in every result as source_accuracy.
Negotiation
Problem. When agents need to agree on price, terms or deadlines, they exchange free text, which is slow and ambiguous and can't be enforced.
Design. A minimal offer protocol over signed messages:
{"type": "offer", "id": "o1", "from": "ed25519:buyer", "to": "ed25519:seller",
"item": {"action": "shop.example/checkout", "input": {"cart_id": "c-1"}},
"terms": {"price": {"amount": 4800, "currency": "USD"}, "deliver_by": "2026-11-15"},
"expires": 1794210000}
Replies are counter (same shape, new terms, in_reply_to), accept or reject. An accept signed by both sides is a binding agreement that the action can reference, and that a payment mandate can be checked against (price within the mandate's limits). Each side's agent negotiates only inside limits its person set in advance, through the approval policy (ask above a threshold).
Built. Negotiation validates every message: signature, expiry, turn order (each message answers the latest), the right party, the item can't change, and accept must repeat the exact terms. agreement() returns the item, terms, both parties and the full signed chain. Limits and respond give a simple, predictable strategy: concede a fixed share of the gap each round, never past the person's walk-away price, and reject after a set number of rounds. check_against_mandate refuses an agreement above the buyer's spending mandate. The tests run two agents to a deal inside overlapping limits, to a clean rejection when limits don't overlap, and settle the deal through payments.py.
Over HTTP
A site that negotiates lists endpoints.negotiate in its action manifest (/.well-known/agent-negotiate). GET returns the seller key to address offers to; each POST {"token", "negotiation_id"} carries the buyer's next signed message and gets the seller's signed reply. The middleware (AgentFriendly(negotiator=...)) runs the seller side inside limits the site sets per item and stores the chain in its SiteState. When the two sides agree, the agreement is stored against the buyer's key, and an action handler reads it with ctx.agreement(item) to charge the agreed price and refuse any other with conflict. The agent side is AgentClient.negotiate and the negotiate MCP tool, which check the deal against the buyer's mandate before returning it.