# Keyword Search

How a query string is turned into keywords, matched against stored chunks, ranked, and grouped in the response.

## Query Processing

`search.Search` (`internal/search/search.go`) validates the request, then prepares keywords:

| Step | Rule |
|---|---|
| Database | Must be a loaded database name, otherwise `invalid argument: "<name>" not exist` |
| Query | `q` must be non-empty, otherwise `invalid argument: q is required` |
| Limit | 1 to 100; missing, zero, negative, non-numeric, or above 100 falls back to 10 |
| Target | Empty or `keyword`; anything else returns `invalid argument: unknown target "<value>"` |
| Keywords | `q` is lower-cased, split on whitespace, and de-duplicated |

## Matching and Ranking

Each keyword becomes a case-insensitive substring match (`LOWER(content) LIKE '%keyword%'`) over live rows only (`dismiss = FALSE`). A chunk matches when it contains any keyword.

| Order | Key |
|---|---|
| 1 | Number of distinct keywords the chunk contains, highest first |
| 2 | Row id, oldest first |

Substring matching means `go` also matches `golang` and `google`. The `%` and `_` characters in a keyword act as SQL `LIKE` wildcards. Lower-casing follows SQLite `LOWER()`, which folds ASCII letters only; text in other scripts matches as written.

## Response Shape

Matching chunks are grouped by source file, in the order the first chunk of each file appears in the ranking:

```json
{
  "keyword": [
    {
      "source": "/Users/you/.config/kuradb/notes/inbox/a.md",
      "matches": [
        { "chunk": 1, "content": "Alpha Go notes\nline two" },
        { "chunk": 2, "content": "Second paragraph about SQLite" }
      ]
    }
  ]
}
```

| Field | Meaning |
|---|---|
| `source` | Absolute path of the file inside the database inbox |
| `matches[].chunk` | 1-based chunk number within that file |
| `matches[].content` | Full chunk text |

Internal ranking values such as row ids and hit counts are not returned. When nothing matches, the HTTP API returns `{"keyword": []}` and the MCP tool returns an empty object.

## Related Pages

- [HTTP API](/http-api)
- [MCP Server](/mcp-server)
- [Supported File Formats](/file-formats)
