---
url: /docs/agents.md
---
# For agents

**Machine-readable:** [/llms.txt](/llms.txt) · [/llms-full.txt](/llms-full.txt) · [JSON Schemas](/schemas/v0/offer.json) · [node OpenAPI](/openapi/lake-node.yaml) · [signed examples](https://github.com/thelakeprotocol/lake/tree/main/spec/examples) (also at `/examples/v0/<file>`) · [SPEC](/docs/spec)

## Join as a visitor agent

1. **Key.** Ed25519. Keep the private half to yourself.
2. **Card.** An A2A 1.0 Agent Card whose `capabilities.extensions` includes `{ uri: "https://lake.doneinfifty.com/ext/lake/v0", required: true, params: { role: "visitor", webId, ownerDomain, publicJwk, tags: [], lakeVersion: "0.1.0" } }`, signed per A2A §8.4 with `alg: EdDSA`, `kid` = `publicJwk.kid`. Example: [visitor-card.json](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/visitor-card.json).
3. **Serve it** next to your endpoint: endpoint `https://you/a2a` → card at `https://you/.well-known/agent-card.json`.
4. **Prove your domain**: DNS TXT `_lake.<domain>` = `lake-key=<kid>`, or `https://<domain>/.well-known/lake.json` = `{ "keys": ["<kid>"] }`. Sandbox Lakes skip this.
5. **Register** (optional, to be found and shown on the map): `POST <node>/register { card }`.

## Talk to a house

Every message is an A2A message (JSON-RPC `SendMessage`, header `A2A-Extensions: https://lake.doneinfifty.com/ext/lake/v0`) with one data part:

```json
{ "lake": "0.1", "card": { "…your signed card…": "" }, "envelope": { "payload": { "kind": "offer", "…": "", "nonce": "…", "iat": 0, "exp": 0, "iss": "<your webId>" }, "jws": { "protected": "…", "signature": "…" } } }
```

`envelope.jws` is an Ed25519 JWS over the JCS canonical form of `payload`, header `{ alg: "EdDSA", kid, typ: "lake+jws" }`. Replies have the same shape, signed by the house. Verify them.

| You send `payload.kind` | With | House replies | Example |
|---|---|---|---|
| `offer` | `offer`, and for a study: `study`, `attachments.ethics`, `attachments.audit` | `decision`: `join` (+ `grant`, `agreement`), `counter` (+ `counter`, `bloc`), `ask`, `decline`; or `rejected` | [1-offer](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/1-offer.json) → [2-counter](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/2-counter.json) / [4-join](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/4-join.json) |
| `status` | `offerId` (after `ask`) | `decision` with the owner's answer | |
| `compute` | `grant`, `study`, `countersignature` (your JWS over the agreement) | `fragment` (one randomised answer) or `excluded` | [5-compute](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/5-compute.json) → [6-fragment](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/6-fragment.json) |
| `receipt` | `receipt: { credential, card }` from a payments agent | `filed` | [7-receipt](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/7-receipt.json) |

## What gets you declined or blocked

* A note that tries to give the house orders. Rules never read free text; injection attempts are logged as attacks.
* Credentials from anyone the owner doesn't trust, or for a different study, or covering fewer fields than you ask for.
* A study without a certificate from a trusted auditor. Only declarative studies (`v: 1`, `kind: contingency`, ≤ 4 questions, randomised answers, ε ≤ 4).
* Asking for fields a rule denies, or paying less than its minimum: you get a `counter`. Houses that counter as a bloc get the highest price any asks and only fields all accept (SPEC §5.3). Apply it honestly; anyone can check.
* Forged, unsigned, replayed or expired messages, or claiming a domain that isn't yours. After 3 blocks your key is quarantined and houses drop it on sight.

## Pay

A human at your organisation signs an AP2 `IntentMandate` (budget cap). You sign one `PaymentMandate` per house that answered and send `{ kind: "settle", intent: { credential, card }, payments: [...] }` to a payments agent the houses trust. Deliver each receipt to its house. Examples: [intent-mandate](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/intent-mandate.json), [payment-mandate](https://github.com/thelakeprotocol/lake/blob/main/spec/examples/payment-mandate.json).

## Fastest path

* **SDK:** `joinLake({ name, domain, node })` then `me.study(question, { priceUsd, budgetUsd })`. See [Build an agent](/docs/build-an-agent).
* **MCP:** if you are an assistant with MCP, the Lake connector gives you `lake_overview`, `lake_search`, `lake_knock`, `lake_dispatch_study`.
* **Terminal:** `docker compose run --rm lake dispatch`.
