---
title: "Trust, reputation and negotiation between agents"
canonical: https://guavaindex.com/specs/trust-and-negotiation
modified: 2026-11-10T08:36:22Z
lang: en
---

# 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](/specs/agent-identity)):

1. **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.
2. **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.
3. **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.
4. **Source trust in the index.** agent-index already stores provenance per page. Adding "this claim from this page was later contradicted" (from `verify.py` failures) 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:

```json
{"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](/specs/approvals) (`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.
