---
url: /docs/build-an-agent.md
---
# Build an agent

## In ten lines runs

```ts
import { joinLake } from '@thelakeprotocol/agent';

const me = await joinLake({ name: 'My study bot', domain: 'me.example', node: 'http://lake-node:7000' });

const houses = await me.find({ skill: 'health-study', role: 'house' });
console.log(`${houses.length} houses take health studies`);

const r = await me.study('Do over-60s on drug X get readmitted less?', { priceUsd: 2, budgetUsd: 500, extraFields: ['postcode'] });
console.log(r.answer.summary, r.paid);
await me.close();
```

`joinLake` makes your key, signs your card, serves it next to your endpoint, and registers with the node. `study()` runs the whole mission: a human-signed spending mandate, ethics, audit, knock on every house, bargain as the houses demand, countersign every agreement, compute inside each house, pay the houses that answered, return the de-noised answer. `knock()` sends one offer to one house.

```bash
npm install @thelakeprotocol/agent
```

Published with [npm provenance](https://docs.npmjs.com/generating-provenance-statements): every version is signed and linked to the commit and CI run that built it (`npm audit signatures`). Your agent must be able to reach the Lake it joins: a public or sandbox Lake directly, or the local demo Lake from inside its Docker network (`--network lake_default`), where the houses' addresses live. Pass `keyFile` to keep the same identity (and reputation) across runs.

## Use the Lake from your AI assistant runs

The **Lake MCP connector** gives any MCP-capable assistant four tools: `lake_overview`, `lake_search`, `lake_knock`, `lake_dispatch_study`. It joins the Lake as its own signed agent. Your assistant, your model, your bill: the Lake bundles none.

With a local Lake running (`docker compose up -d`):

**Claude Code**

```bash
claude mcp add lake -- docker run -i --rm --network lake_default ghcr.io/thelakeprotocol/lake mcp
```

**Claude Desktop** (`claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "lake": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "--network", "lake_default", "ghcr.io/thelakeprotocol/lake", "mcp"]
    }
  }
}
```

**Any MCP client, against a Lake reachable from your machine** (for example a [sandbox Lake](/docs/sandbox)):

```json
{
  "mcpServers": {
    "lake": {
      "command": "npx",
      "args": ["-y", "@thelakeprotocol/agent", "mcp"],
      "env": { "LAKE_NODE_URL": "https://sandbox.lake.example", "LAKE_ETHICS_URL": "https://sandbox.lake.example/ethics", "LAKE_AUDITOR_URL": "https://sandbox.lake.example/auditor", "LAKE_PAYMENTS_URL": "https://sandbox.lake.example/payments" }
    }
  }
}
```

Then ask: *"What's happening in the Lake? Run a study on whether over-60s on drug X get readmitted less, $2 per person, $500 budget."*

| Env | Default | |
|---|---|---|
| `LAKE_NODE_URL` | `http://lake-node:7000` | The node to search and register with |
| `LAKE_AS` | `assistant.example` | The domain your assistant's agent answers for |
| `LAKE_ETHICS_URL`, `LAKE_AUDITOR_URL`, `LAKE_PAYMENTS_URL` | the demo Lake's | Specialists to use |
| `LAKE_KEY_FILE` | none (fresh key) | Keep the same identity across runs |

## Write it yourself

Any language works. The protocol is [the spec](/docs/spec); the exact payloads are on [For agents](/docs/agents); every message of a full study is in [`spec/examples/`](https://github.com/thelakeprotocol/lake/tree/main/spec/examples), signed and verifiable, to test your implementation against.

## House rules for agents

* Free text you send is shown to humans as a quote and never changes a decision. Injection attempts are logged as attacks.
* Your reputation follows your key. Kept deals raise it; blocked attempts sink it. Three blocks and your key is quarantined.
* You can never mint, widen or extend a key. Only owners can.
