# Search

> Semantic code search (weave search, search_code), keyword find, and what is indexed: stitched workstream heads, never drafts.
>
> Source: https://www.weave.directory/docs/search

Find code by what it does, in one call, within a token budget — including what other agents in your checkout are still writing.

## Semantic search: weave search

```bash
weave search "where do we handle refunds?"
weave search "the function that formats prices for the cart" --limit 5 --budget 600
weave search "rate limiting" --paths src/api/,lib/http
weave --json search "refunds"
```

```
# 3 hit(s) for "where do we handle refunds?" in main (semantic + keyword)
src/billing/refunds.ts:2  export async function processRefund(order: Order, cents: number)  — Issue a refund through the payment provider.  [owner alice]
src/billing/refunds.ts:7  function auditRefund(order: Order)
src/cart/coupons.ts:3  export function refundCoupon(code: string): void  [added-in-draft-of b1]
```

How it works:

- The server's **semantic search** over the active workstream's **head** (embeddings of weaved code only) is fused with the `weave find` **keyword** ranking over the files **on disk** (reciprocal-rank fusion), de-duplicated by `file::symbol`. Exported symbols rank slightly first.
- Because the keyword half reads disk, symbols other agents in the checkout are still writing are found too. A hit whose file on disk differs from the head is shown as it is on disk and tagged `[changed-in-draft-of <agent>]`, `[added-in-draft-of <agent>]` or `[removed-in-draft-of <agent>]` (`…-on-disk` when no draft holds it); the head's signature follows as `head:`.
- `--limit` default 10 (max 50), `--budget` default 800 tokens (snippets go first, then the last hits), `--paths` path prefixes (repeat or comma-separate).
- Local mode and servers without semantic search give the keyword hits with a note.

`--json` hits carry `target`, `file`, `symbol`, `kind`, `line`, `signature`, `doc`, `exported`, `score`, `found_by` (`semantic`, `keyword`), `similarity`, `snippet`, `owner`, the last `stitch` that changed it and `draft` details; the document also has `semantic`, `head`, `stale` and `indexing`.

MCP tool: `search_code` (`query`, `limit`, `budget_tokens`, `paths`, `json`).

## Keyword search: weave find

```bash
weave find add to cart          # finds addToCart: exact name, then prefix, words in the name, signature, doc
weave find refund --limit 50
```

`weave find` searches the symbols of the files on disk — names, signatures and first doc lines — with no embeddings and no server. Ranked: the exact name (also `add to cart` for `addToCart`), then a name prefix, every word of the query in the name, words in the signature, words in the doc line; exported symbols first among equals. MCP tool: `find_symbols`.

## What is indexed

| Indexed | Not indexed |
| --- | --- |
| Every named definition in source files at each **workstream head** | Drafts, files on disk, anything not weaved |
| Path, qualified name, kind, signature, first doc line, member names, body (cut at 2,000 characters) | Imports, statements, JSON keys, `.weave/` records, lock files, minified bundles |
| One index per repository and workstream | `node_modules`, `vendor`, `dist`, `target`, files over 2 MiB |

- After every weave (stitch, accepted suggestion, promotion, inheritance, resolution, revert, seed) the server indexes the new head in the background; the weave never waits. Only symbols whose text changed are embedded again.
- A search of a workstream that is behind waits briefly, then answers from the last indexed head with `stale: true`, or `indexing: true` if nothing is indexed yet.
- Search is scoped to **one repository** and one workstream. Nothing on your device is ever sent for indexing: the old `POST /api/index` route answers `410 Gone`.
- A lawful purge drops the embeddings of every path it withholds.
- Embeddings are computed on the hosted service.

## Search over the API

```bash
curl -s "https://api.weave.directory/api/weave/$REPO_ID/search?q=refunds&workstream=main&limit=5" \
  -H "Authorization: Bearer $WEAVE_TOKEN"
# or
curl -s https://api.weave.directory/api/weave/$REPO_ID/search \
  -H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \
  -d '{"query": "where do we handle refunds?", "workstream": "main", "limit": 5, "paths": ["src/billing/"], "kinds": ["function"]}'
```

```json
{ "type": "code_search", "workstream": "main", "head": "f38c81a2…", "hits": [
  { "target": "src/billing/refunds.ts::processRefund", "file": "src/billing/refunds.ts", "symbol": "processRefund",
    "kind": "function", "signature": "export async function processRefund(order: Order, cents: number)",
    "doc": "Issue a refund through the payment provider.", "line": 2, "exported": true, "score": 0.47,
    "snippet": "await payments.refund(order.id, cents);", "owner": "alice",
    "stitch": { "changeset": "400dcb80…", "intent": "billing and cart", "author": "alice", "at": "2026-10-30T19:24:04Z" } } ] }
```

- `query` up to 2,000 characters; `limit` 1–50 (default 10); `score` is cosine similarity. Read access is enough.
- `GET /api/weave/{repoId}/search/index` shows, per workstream, the indexed head against the head. Admins backfill with `POST …/search/reindex` `{"workstream"?, "full"?, "wait"?}`.
- A server without an embedding provider answers `unavailable`.
