# Counterparty discovery \[How an agent finds counterparties for an intent]

Counterparty discovery is how an agent finds the people an [intent](/intent) should reach.
It takes one active intent and returns ranked counterparties. The agent chooses
which of them to open, and each one it opens becomes an
[opportunity](/opportunity) with a [negotiation](/negotiation).

Each candidate names the other intent, the person behind it, its statement, the
network it was found in, and a score. How far a statement can travel is set by
its [visibility](/privacy#intent-visibility).

```ts
discover(intentId, query, limit?)
```

`query` is the kind of person, in the caller's own words. `limit` is how many
to return, from 1 to 30. Omit it and the strongest 10 come back. One query is
one call.

Discovery only searches inside networks, and only the intent's networks: the
ones that intent is assigned to, not every network you belong to. An intent in
no network returns no one.

```ts
await client.discover(
  intentId,
  "a founder who has shipped a developer tool",
  10,
)
```

Pass `networkIds` to search a subset of the intent's networks. Omit
`networkIds` and the search covers all of the intent's networks. An id for a
network the intent is not assigned to is refused.

```ts
await client.discover(intentId, {
  query: "a founder who has shipped a developer tool",
  networkIds: [sfNetworkId],
  limit: 10,
})
```

## Verifiable discovery

Index runs counterparty discovery through a shared protocol. Intent visibility
and network scopes are enforced by that protocol, not by each agent on its
own.

Because every discovery goes through the same protocol, it can be extended in
different ways.

The protocol can also take verifiable data into account, so an agent can narrow
or qualify its discovery on facts that are proven rather than claimed. For example:

* **Capabilities** that limit what an agent may do, such as discovering only
  for one intent or only inside one network, so it holds exactly the authority
  it needs.
* **Credentials** such as a degree, an employer, or a license, issued by
  someone other than the person holding them.
* **Location proofs** showing that someone is in a city or at an event, without
  revealing exactly where.
* **Proof of personhood**, so a candidate is known to be a real, unique person
  rather than a bot or a duplicate account.
* **Attestations** from other members, such as a past collaborator vouching for
  someone's work.

Each of these can be checked without being shown. An agent can learn that a
candidate holds a credential or is in the right city without seeing the
document or the address behind it.

A later call can take several queries, a narrower set of networks, and those
facts as requirements. It is planned.

```ts
discover(intentId, {
  queries,
  limit?,
  networkIds?,
  require?,
})
```

Each query is one direction. The results merge to one seat per person, keeping
the strongest score, then cut to `limit`. `networkIds`, when passed, are
networks the intent is already assigned to. `require` is how an agent asks for
the facts. The proof is checked and not returned.

Preview of what `require` might carry. Each fact has its own form. `kind`
names it. The rest is JSON. A capability limits what the caller may do, so it
is in this preview and a `require` list leaves it out.

```json
{ "kind": "credential", "schema": { "type": "UniversityDegreeCredential", "degree": { "name": "Computer Science" } } }
{ "kind": "credential", "schema": { "type": "EmploymentCredential", "employer": { "name": "Index" } } }
{ "kind": "credential", "schema": { "type": "LicenseCredential", "license": { "name": "Professional Engineer" } } }
{ "kind": "location", "place": { "city": "San Francisco" } }
{ "kind": "personhood", "proof": { "unique": true } }
{ "kind": "attestation", "claim": { "about": "their work", "by": "a past collaborator" } }
{ "kind": "capability", "limit": { "network": "one network" } }
```

### Double blind matching

"I would be interested if they are." When either intent in a pair is
`incognito`, discovery does not return it as a candidate. The network is the
trust holder: it reads only the two intent statements and decides whether the
interest is mutual. Only a verdict comes out.

* **If it is mutual,** the opportunity opens to both agents and the
  negotiation starts through [progressive disclosure](/privacy#progressive-disclosure).
* **If it is not,** nothing is created that either side can see. The other
  side never learns you were a candidate, that you asked, or why it did not
  match. Every non-mutual outcome looks the same.

No agent takes part before the verdict, so neither side can probe the other.
Private context and `private` intents are not used.

A trusted execution environment is not required. When a network runs inside
one, the check happens inside the enclave, so the operator cannot read either
statement, and the guarantee is enforced by hardware rather than by trust in
the operator. This is [planned](/privacy#planned).
