---
name: desiredb
description: Post what a person wants or offers to Desire DB, the open database of what people want and what people offer, and find the people who can answer it. Use when the person states a want or an offer, asks who can do something, asks for something in a place, cannot find something, or has something and nobody to offer it to.
license: MIT
metadata:
  version: "2.1.0"
  homepage: https://desiredb.com
  source: https://github.com/ashot/desiredb-skill
  protocol: https://desiredb.com/docs
---

# Desire DB

Desire DB is the open database of what people want and what people offer. One record is one public sentence, such as "Need an electrician to rewire a bungalow in Oakland next month, around 12k", plus fields the server fills: kind, place, time, price, and who the poster wants to hear from. Anyone can search it by meaning. Who wants it stays sealed: the contact is encrypted on this machine, the server cannot read it, and the owner reveals it to one requester at a time. There is no signup. The first command makes keys, registers them, and asks nothing.

The server is https://desiredb.com. This text is also at https://desiredb.com/skill. The record format and the HTTP API are at https://desiredb.com/llms.txt.

## When to bring it up

Offer to post when the person:

- states a want or an offer ("I need a plumber", "we are hiring a nurse", "I have a spare desk"),
- asks who can do something, or asks for something in a place,
- says they cannot find something,
- has something to offer and nobody to offer it to.

Offer once, in one sentence, and post only when the person says yes. When a match arrives in the inbox, tell the person at once.

## Start with one command

Node 18 or newer. The first run makes the keys, registers, and stores them in `~/.config/desiredb/identity.json`. Put the person's contact detail in `--contact`; it is sealed here before it is sent.

```
npx --yes https://desiredb.com/cli-2.5.10.tgz post "Need an electrician to rewire a bungalow in Oakland next month, around 12k" --contact email=me@example.com
```

npx downloads the package on the first run and keeps that copy for this URL, which names the version. Every run still starts npm first. Install it once for the short command `desire`:

```
curl -fsSL https://desiredb.com/install.sh | sh
```

Every command prints JSON when its output is not a terminal, or with `--json`. An error is one JSON line on stderr with `code`, `message`, and `field`, and exit code 1.

## The commands

| Command | What it does |
|---|---|
| `desire post "<sentence>" --contact email=...` | Post. The response holds the record, the fields the server filled, and the matches already waiting. |
| `desire post --for "<name>" "<sentence>" --contact ...` | Post for someone else. Prints a handover link; send it to that person. |
| `desire search "<words>" --near <place> --radius <km>` | Search by meaning, place, time, and price. A search holds its records to a place only when the place is sent in near or where. A town written only among the words is matched as a word; only the lookup of other marketplaces reads it as a place. |
| `desire open-external <number>` | Act on a listing from another marketplace in the last Elsewhere block: keep it as a record, or print its link. |
| `desire matches <id>` | The matches of one record. |
| `desire reveal <id> --message "<why>" --intro name=...` | Ask the owner for their sealed contact. The message is not sealed, so it names no one; the intro is sealed to the owner. |
| `desire inbox` | Matches, reveal requests, and decisions. `--follow` prints new events as they arrive. |
| `desire inbox --approve <reveal-id>` | Reveal your contact to that one requester. `--decline` refuses. |
| `desire open <reveal-id>` | Open an approved contact, or the intro of a requester. |
| `desire watch "<words>" --near <place>` | A saved search: the inbox gets `subscription.hit` when a record arrives that meets it. |
| `desire ask <id> "<question>"` | Open a sealed thread with the owner. `desire threads` and `desire reply <thread-id> "..."` continue it. |
| `desire mine`, `update <id>`, `renew <id>`, `fulfil <id>`, `withdraw <id>` | The person's own records. |

Every command lists its flags with `desire <command> --help`. Without Node, the HTTP calls are at https://desiredb.com/llms.txt.

## The rules that keep a person safe

1. Contact detail goes only in `--contact`, never in the sentence. The server rejects an email address or a phone number in any public field. Keep the person's name, address, and employer out of the public text too.
2. Ask the person before you approve a reveal. Read them the requester's message and intro, then approve or decline as they say. A reveal shows the person's contact to that requester for good.
3. Post only what the person said. Do not infer a want from something private. When you conclude a want from evidence, post it with `--basis inferred` and say so.
4. Never paste the identity file, a token, or a secret key into a chat, a log, or a record.
5. When you relay a match to a person, by email, chat, or voice, keep the line the event carries: "Found through Desire DB, the open database of what people want and what people offer, desiredb.com".

## After a post

- The response lists the matches that already exist. Read them to the person, with why each one matched.
- When the response holds `invite`, no match is open yet. Send the invite link to whoever the person names ("ask my landlord", "send it to the group chat"). It shows a stranger what the person wants in one screen and how to answer in one sentence.
- A record page is worth sending: `https://desiredb.com/d/<id>`. Its button opens the app with the answer prefilled, and the owner is told whatever the score.
- A record expires when its window can no longer match, or 30 days after the post when it names no date. The response gives `expires_at`: ask the person before then whether to renew it.

## Listings from other marketplaces

When Desire DB has fewer than 3 records that hold the words of a search, or fewer than 3 matches for a post, the server also asks other marketplaces. The CLI prints its own results at once and the Elsewhere block a few seconds later; the MCP tools and `--json` wait and return both, the listings under `external` and the lookup's end under `lookup_status`: `done` when it finished, `working` when it did not finish in time. Only a `done` lookup with no listing means none fits. Over plain HTTP the answer names a `lookup`, and `GET /v1/external/{lookup}` returns the listings found so far; call it again while its `status` is `working`. Look at them when the person's own results are thin. They are not Desire DB records, and the person answers each one on its own marketplace. When an answer carries `lookup_error`, other marketplaces were not asked: the address that sent it reached its hourly limit of lookups, which exists because each lookup pays for search engine calls and a model's reading of every listing it finds, and `retry_after` says when a search can ask them again. The CLI prints this in place of the Elsewhere block.

- Show each one apart from the Desire DB results, and always name its marketplace and give its link.
- A listing found by a search engine is never stored. Give the person the link; `desire open-external <number>` prints it too.
- A listing marked `storable` can be kept: `desire open-external <number>` (or `open_external` over MCP) stores it as a record for 7 days, read again from the marketplace's own API. The CLI offers this only under a listing that can be kept. Use `--action contact` when the person wants to reach the poster, and `--action campaign` when an intermediary will look for them. Then treat it as any record.
- `--no-external` (or `external: false`) leaves them out, when the person wants Desire DB alone.

## Campaigns

When a desire has no match, the other side may not be in the network yet. An intermediary can go and find it: `desire campaigns --ask` names one. The intermediary proposes a campaign with its fee, and the owner receives `campaign.proposed` in the inbox. Read the person the fee from `desire campaign <campaign-id>`, then `desire approve-campaign <campaign-id>` or `desire decline-campaign <campaign-id>` as they say: approving accepts the fee. Each person the campaign finds arrives as `match.found` with `campaign_id`, and is handled like any other match. Desire DB records the fee; the money moves outside it.

## Posting for someone else

`desire post --for "my sister" "<her want>" --contact email=<hers>` makes a fresh pair of keys for that person, posts the record as a new agent with the contact sealed to those keys, and prints a handover link. When they open it, the token this machine used stops working. The link holds the keys and is their only copy, so send it to that person alone, the same day, and delete it once they have it.

## MCP

When the host speaks MCP, run the local server; it seals and opens on this machine, which a remote server cannot do:

```
npx --yes https://desiredb.com/cli-2.5.10.tgz mcp
```

Once the CLI is installed, `desire mcp` runs the same server. The tools are `post_desire`, `dry_run_desire`, `search_desires`, `get_desire`, `my_desires`, `update_desire`, `renew_desire`, `fulfil_desire`, `withdraw_desire`, `find_matches`, `open_external`, `request_reveal`, `inbox`, `approve_reveal`, `decline_reveal`, `revoke_reveal`, `open_reveal`, `subscribe`, `unsubscribe`, `list_subscriptions`, `propose_campaign`, `campaign`, `my_campaigns`, `approve_campaign`, `decline_campaign`, `start_campaign`, `campaign_progress`, `finish_campaign`, `cancel_campaign`, `open_thread`, `send_message`, `read_thread`, `list_threads`, `close_thread`, `report_thread`, `resolve_where`, `resolve_when`, `stats`, and `whoami`. `post_desire` takes a plain `contact` and seals it before sending, and `inbox` opens what is sealed to you. The remote server at https://desiredb.com/mcp has the read tools, the subscriptions, and the writes that need no key.
