[← README](../../README.md) · [Docs index](../README.md) · [Search](README.md) # Search by meaning Words find the files that contain them. Search by meaning also finds the files that are *about* what you type, whatever words they use and in whichever language: "what the rocket's fuel costs" finds `Brændstofbudget.docx`. A small multilingual model does it on your own machine; it is off until you turn it on. ![The desktop app's Find with "rocket fuel cost" typed: the Ask row on top, In files with budget.txt and its passage, About this with budget-da.txt, the Danish budget, in italics](../screenshots/search-find.png) ## Contents - [How to use it](#how-to-use-it) - [What you see](#what-you-see) - [How it works](#how-it-works) - [How words and meaning are ranked together](#how-words-and-meaning-are-ranked-together) - [On a Mac's GPU](#on-a-macs-gpu) - [Settings and config.toml](#settings-and-configtoml) - [In the terminal app](#in-the-terminal-app) - [Questions](#questions) ## How to use it **Turn it on** (once). The quickest way is the guided setup, [Smart search in a few minutes](setup.md): **Set up…** in *Settings → Finding files* (or *Overview*), or `coxswain --setup-search`. It finds a model server on your machine and says whether the built-in model or a server suits it. By hand: | Where | How | |---|---| | Desktop app | *Settings → Finding files* → the level *Names, text and meaning*, or *Details → Meaning → Download the model (465 MB) and turn on*. A bar shows *Downloading the model: 120 MB of 465 MB*; **Cancel** stops it | | Terminal app | `coxswain --meaning on`: prints *Downloading: 42 %*, then turns it on (with a [server](servers.md) as the engine, nothing is downloaded) | | A row in Find | *Find files about your words too, in any language, even without the words.* under *About this*, with *Set up* (it opens the guided setup; in the terminal app it runs `coxswain --setup-search`); **Delete** sends it away. Also and the [notice](../panels/notices.md) *New: search by meaning finds files about your words, in any language. Turn it on*: in the desktop app under *Settings → Overview → What's new* (**Show me**), in the terminal app once in the status line | It needs *Words inside files*: choosing the level or the button turns them on too. Then: 1. **Ctrl+F** for [Find](find-file.md). 2. Type a question or a few words, in any language. 3. Files with your words are under *In files*, those close in meaning ahead; files found by meaning alone are under **About this**. For meaning alone, **Tab** to the *About* kind or type `about:` first: `about: brændstof`. **Turn it off:** *Turn off* in Settings (or `coxswain --meaning off`) stops it and keeps the model. **Delete the model** (or `coxswain --meaning delete`) turns it off and deletes the model. `coxswain --meaning` alone prints `on` or `off`, and with the built-in model a second line with where it runs: `Built-in model · on the GPU (Metal)`. ## What you see **In Find**, a file found by meaning alone is under *About this*, with the start of the passage that was closest (up to 24 words) in italics, wherever in the document that passage is. Only files close to the best match are shown (within 0.10 of its score with the built-in model, 0.15 with bge-m3 and other server models, and above what unrelated text scores: 0.77 and 0.45), so unrelated files stay out. A file found by both its words and its meaning is shown once, under *In files*, raised by its meaning. The footer counts the files with vectors: *meaning for 8,120*, and while files are still to go, *meaning for 8,120 of 31,208 (26 %)*. A file that changed in the last five minutes is not to go yet but *changing*: the footer adds *1 file changing* ([why](#why-does-it-say-a-file-is-changing)). **In Settings → Finding files**, the *Meaning* line of the status: *8,120 of 31,208 files · the built-in model on the GPU (Metal)* (or *on the CPU*, or on a Mac that could not use its GPU *on the CPU (this Mac has no Metal GPU to use)*; with a server, *bge-m3 at localhost*), and while files are still to go, a progress bar with the percent done (in the terminal app `██░░░░░░░░ 26 %` after the counts) and *About 3 hours until every file is done.* Files that changed in the last five minutes are not in those counts or that time; the note under the line says *1 file is changing: it gets its vectors once it has been unchanged for 5 minutes.* Any error is in red, with **Set up…**. While off: *Off*, *Files about your words are not found.*, and **Set up…**. **In Settings → Finding files → Details → Meaning**, from top to bottom: - *Meaning*, with the hint *Finds files about your words, not only files with them, in any language: “rocket fuel cost” finds a Danish budget.* Under it the buttons: while on, **Turn off** and **Delete the model**; while off, with the model there, **Turn on** and **Delete the model**; without it, **Download the model (465 MB) and turn on**. With the built-in model, the model's folder with **Show in panel**. - *Made by*: *Built-in model, on this machine (465 MB once)*, *Ollama*, or *A server with the OpenAI API (Lemonade, LM Studio, llama.cpp …)*. The last two are on [their own page](servers.md). - On a Mac, the switch *Use the CPU only*. **In Find's footer**: *meaning for 8,120* once it runs, *meaning for 8,120 of 31,208 (26 %)* while files are still to go, and *· 2 files changing* while files changed in the last five minutes. **In Settings → Disk use** (the store's report): *Files waiting for vectors*, and apart from them *Files changing (vectors after 5 minutes unchanged)*. ## How it works - **The model** is [multilingual-e5-small](https://huggingface.co/intfloat/multilingual-e5-small), downloaded once from Hugging Face at a pinned version: three files, 465 MB as the apps count it (488 million bytes), each checked against its SHA-256 before it is used. It is kept in Coxswain's cache folder under `models/multilingual-e5-small-614241f6`. - **It runs on the CPU**, with [candle](https://github.com/huggingface/candle) in pure Rust, on two threads, so the machine stays yours, on Linux and Windows. **On a Mac with Apple Silicon it runs on the GPU** through Metal ([below](#on-a-macs-gpu)). For a GPU elsewhere, see [servers](servers.md). - **What gets vectors:** the whole text of each file, in passages of up to 120 words. A passage ends at a paragraph's end once it has 60 words; a paragraph longer than that is cut, and the next passage starts with the last 20 words of the cut one, so nothing said across a cut is lost. In Markdown files (`.md`, `.markdown`, `.mdx`) each heading starts a new passage. A passage with fewer than 20 letters is skipped, and one ends after 1,200 characters however few words it has: 120 words of prose are about 800, so prose is never cut, while a line of minified JSON or a list of paths is one "word" of thousands, and a server would otherwise read all of it (the built-in model stops at 512 tokens anyway). - **What the model is shown** of each passage is a first line with the file's name, its folder and, in Markdown, the heading it sits under (`budget.md · rocket/notes · Fuel`), then the passage. A question that names a file, a folder or a section finds it. - **The cap:** 256 passages a file, about 25,000 words. Of a longer file, the first 16 passages, the last 4, the first passage under each heading (up to 128) and passages spread evenly over the rest get vectors. Search by words keeps the first 4 MB of a file's text. A text, code, CSV or log file with more text than that has its passages chosen from the whole file, read line by line twice (once to count them, once to keep the chosen ones), never held whole: a 300 MB log gets its 256 passages from its start to its end, and those passages are kept with their vectors. Of a file larger than 1 GB, its first gigabyte is read that way. So does a Word, OpenDocument, spreadsheet (`.xlsx`, `.xlsm`, `.xlsb`, `.xls`, `.ods`) or presentation file, book (`.epub`) or web page with about 3 MB of text or more: it is read twice as it is unpacked (a Word or OpenDocument text, book or web page for at most 20 seconds each time, the time the model takes not counted). [Long files](long-files.md) set to *Everything*, for every folder or one, lift the cap: every passage gets a vector, and search by words keeps all the text. Each vector (384 numbers) is packed into a byte a number and kept in `search.db`. - **When:** the [helper](helper.md) makes them a few files at a time (the passages of several short files go to the model together, 64 at least, so their batches are full; a few files' passages are made ahead while the model works), each file's vectors written whole, and not on [battery](battery.md) unless you press *Read now*. With the built-in model it rests as long as the work took; with a [server](servers.md) it rests a quarter of that, since the work is the server's. New and changed files get theirs once they have been unchanged for five minutes, at the helper's next pass after that, within ten minutes; their words are searchable at once. Until then they count as *changing*, not as to go: a file an app saves every few seconds (`~/.claude.json`, a browser's session) would otherwise get new vectors over and over and never let the count reach 0. A file whose date is in the future (a clock that was wrong when it was saved) counts as changing until a later scan finds it unchanged, size and date, and is then to go. A long backlog (the first vectors on a big home folder, hours on the processor) stops every minute to read what you saved meanwhile, so a saved file is found by its words within a minute even then. - **A search:** your question gets a vector too. A first sieve over one bit per number keeps the 1,000 closest passages; their full vectors are then scored. A file counts with its best passage, and a little more (0.005) for each further passage that is close too, up to four, so a document that keeps coming back to your question goes ahead of one that mentions it once. - **A new way of cutting passages** (as in 1.39.0, which covers whole documents where earlier versions took the first 960 words) is noticed when the helper opens `search.db`: it keeps the number of the way its vectors were made (`passages` in its table of facts). When that differs, the vectors go, the text stays, and every file gets new ones in the background, the last changed first. Nothing else is read again. This happens once per store, on whichever machine the store is: a copied or synced cache folder is renewed where it is opened. ## How words and meaning are ranked together A search in the files' text runs two searches: by words (every word, or, when fewer than 10 files have them all, any of the longer words) and by meaning. Their two lists are fused by **reciprocal rank fusion**: a file scores ``` 1 / (60 + its rank among the files with every word) + 2 / (60 + its rank by meaning) ``` (a term is 0 when the file is not in that list). The files with the words are ordered by this score, so a file that has the words *and* is close in meaning comes first, and one that has them all keeps its place among the rest. A file with only some of the words counts by meaning alone, and is shown only when meaning finds it too. Files found by meaning alone follow, closest first. The weights were chosen with the [search-quality questions](../reference/performance.md#search-quality): meaning weighs twice as much as words because, on those questions, it ranks the right file first more often. ## On a Mac's GPU On a Mac the built-in model tries Apple's GPU first, through Metal, and makes the vectors there in batches of up to 32 passages: several times faster than on the CPU (the notice says how much the probe measured). Nothing changes in what it finds. **How it decides**, each time the [helper](helper.md) starts: 1. It looks for a Metal GPU. Apple Silicon (M1 and later) has one; most Intel Macs and virtual machines do not, and stay on the CPU. 2. It loads the model there and turns a probe sentence into a vector on both the GPU and the CPU. The two must point the same way (cosine at least 0.999), and the GPU must be the faster; otherwise the CPU does the work. 3. If the GPU fails later while it works, the CPU takes over for the rest of the helper's run. **How to see which:** | Where | What it says | |---|---| | Desktop app | *Settings → Finding files*, the *Meaning* line of the status: *… files · the built-in model on the GPU (Metal)*, or *… on the CPU (why)* | | Terminal app | `coxswain --meaning` prints `on`, then `Built-in model · on the GPU (Metal)` | | A notice, once | *Search by meaning now uses your Mac's GPU (Metal): about 6× faster*, or on a Mac that could not use it *Search by meaning runs on the CPU: …* with the reason. In the desktop app under *Settings → Overview → What's new*, in the terminal app in the status line | The reasons for the CPU: *chosen in Settings*, *this Mac has no Metal GPU to use*, *the GPU could not load the model: …*, *the GPU's results differed from the CPU's (0.9871)*, *the GPU was slower than the CPU*, *the GPU failed: …*. **To keep it on the CPU:** tick *Use the CPU only* in Settings (shown on a Mac only), or run `coxswain --meaning cpu`; `coxswain --meaning auto` goes back. Both set `meaning_device` and start the helper again. The vectors stay: the GPU and the CPU make the same ones. **A server with a stronger model:** Ollama and LM Studio run on Metal too. When one here has a stronger embedding model than multilingual-e5-small (`bge-m3`, `qwen3-embedding`, `snowflake-arctic-embed2`), *Settings → Finding files* says so under *Meaning* in grey, as a tip, not in red: *bge-m3:latest on Ollama runs on Metal too, and finds by meaning better than the built-in model.*, with **Use bge-m3:latest** (terminal: **Enter** on the line). Taking it reads every file's meaning again, said and asked first. A weaker one (`nomic-embed-text`) says nothing. The same rules for Ask's chat model are in [the built-in chat model](ask-builtin.md#on-a-mac-a-tip-when-a-server-has-more). On Linux and Windows the built-in model always runs on the CPU; the setting changes nothing there. For a GPU on those, use [Ollama or another server](servers.md). ## Settings and config.toml | Settings item | Key under `[search]` | Type | Default | |---|---|---|---| | *Turn on* / *Turn off* | `meaning` | bool | `false` | | *Made by* | `meaning_engine` | `"builtin"`, `"ollama"` or `"openai"` | `"builtin"` | | *Server*, *Model*, *API key from the environment variable* | `meaning_url`, `meaning_model`, `meaning_key_env` | strings | `""` | | *Use the CPU only* (on a Mac) | `meaning_device` | `"auto"` or `"cpu"` | `"auto"` | | *Long files* | `long_files` | `"sample"` or `"everything"` | `"sample"` ([Long files](long-files.md)) | The last three are for [servers](servers.md). Search by meaning also needs `text = true`. ## In the terminal app The same search and the same *About this* group, its passages dimmed in italics. Turn it on, off or delete it with `coxswain --meaning on|off|delete`; on a Mac, `coxswain --meaning cpu|auto` keeps the built-in model on the CPU or lets it use the GPU, and `coxswain --meaning` says where it runs. `coxswain --meaning bench [URL MODEL]` times the model on 64 passages ([above](#how-fast-is-it-here-and-would-another-model-be-faster)). Its Settings (**F12** → *Finding files*) show the *Meaning* line with the files done and to go (and, under it, *1 file is changing: …* for files changed in the last five minutes), and *Measure speed*, as the desktop app's do. While the vectors are renewed, Find's footer adds *Renewing search by meaning for whole documents: 23,088 files to go, about 3 hours*, and the notice says it once. While it is off, *About this* says *Find files about your words too, in any language, even without the words.* with *Set up*. When vectors stop coming, *About this* says why: *No vectors: http://localhost:11434: Connection refused*, or *Reading stopped: …* when reading itself failed. ## Questions #### Why is search by meaning off? It needs a 465 MB model that Coxswain does not ship, and CPU (or, on a Mac, GPU) time to read your files with it. You choose whether that is worth it: turn it on in Settings (the level *Names, text and meaning* under *Finding files*) or with `coxswain --meaning on`. #### Why does it find nothing yet? The vectors are made in the background, a few files at a time: Settings shows how many are done (*8,120 of 31,208 files*, with a progress bar and the time left) and Find's footer the percent. The time left is the files to go, times the passages a file has had so far, times what one passage takes on your machine; it settles after the first few hundred files. On a laptop's CPU that takes hours for a large home folder, and it waits while on battery. A [server with a GPU](servers.md) is much faster. #### Why does it say a file is changing? A file changed in the last five minutes gets no vectors yet: it is found by its words at once, and by its meaning once it has been unchanged for five minutes, at the helper's next pass after that (within ten minutes). Find's footer says *1 file changing* and Settings → Finding files *1 file is changing: it gets its vectors once it has been unchanged for 5 minutes.* (both apps). A file that stays changing is one an app keeps saving: `~/.claude.json`, which Claude Code rewrites every few seconds, a browser's session file, a log. Such a file is never counted as to go, so the count of files to go reaches 0 instead of hanging at *1 file to go*; nothing needs doing. It gets its vectors whenever the app leaves it alone for five minutes. #### Vectors stopped coming. Why? Both apps say why, in red: Settings on the *Meaning* line of *Finding files* (desktop) and the status line of Find's *About this* group (both apps), and a [notice](../panels/notices.md) in the status line of both (in the desktop app also under *Settings → Overview → What's new*). *No vectors: …* is the server or the model: Ollama not running (`systemctl start ollama`), or the model not pulled (`ollama pull bge-m3`, or *Pull* in Settings). *Reading stopped: …* means a scan failed before the vectors' turn; vectors come only after the text is read. Before 1.26.4 a store whose Markdown files were read again after an update failed every scan that way, silently, and vectors stopped after the first few hundred files: 1.26.4 mends such a store by itself. #### Does the built-in model use my Mac's GPU? On Apple Silicon, yes: through Metal, in batches, several times faster than the CPU. *Settings → Finding files* says *… the built-in model on the GPU (Metal)* on the *Meaning* line, and `coxswain --meaning` prints the same line. An Intel Mac usually has no Metal GPU the model can use and stays on the CPU, which Settings says with the reason. See [On a Mac's GPU](#on-a-macs-gpu). #### My Mac's Settings suggests bge-m3 on Ollama in grey. Should I take it? If you search in many languages or long documents, yes: bge-m3 reads up to 8,000 tokens a passage and finds by meaning better than the built-in multilingual-e5-small; Ollama runs it on Metal too. It is a tip, not a fault: the built-in model stays fine, and the line stays plain until you choose. **Use bge-m3:latest** reads every file's meaning again, which takes a while on a large store. #### Why does my Mac say "on the CPU"? Settings gives the reason in brackets. *this Mac has no Metal GPU to use*: an Intel Mac or a virtual machine. *the GPU's results differed from the CPU's*: the GPU's vectors were not the same, so they are not used. *the GPU failed*: it broke while working; the next start of the helper tries again (*Turn off*, then *Turn on*, or `coxswain --meaning on`). *chosen in Settings*: *Use the CPU only* is ticked. #### How do I keep it off the GPU? Tick *Use the CPU only* under *Settings → Finding files → Details → Meaning*, or `coxswain --meaning cpu`. The vectors already made stay. #### How fast is it here, and would another model be faster? *Measure speed* on the *Meaning* line of Settings → Finding files (both apps) embeds 64 passages of prose with your model, the way the helper sends them, and says *12.4 passages a second with openai:Qwen3-Embedding-0.6B-GGUF. At that speed the 199,000 files still to go take about 2 days.* Nothing is stored. From a shell, `coxswain --meaning bench` says the same, and `coxswain --meaning bench URL MODEL` tries another server with the OpenAI API first, without changing anything, so you can compare before a switch that starts the queue over. A server loads its model on the first passage, which is not timed. #### Why does it say Ollama would be faster? The full answer: [Why does it say Ollama would be faster?](setup.md#why-does-it-say-ollama-would-be-faster) in the setup guide. #### Is a document found by what its last chapter is about? Yes, since 1.39.0: the whole text gets vectors, up to 256 passages (about 25,000 words). A longer file has its start, its end, the start of each section and passages evenly between. Search by words keeps the first 4 MB of a file's text. A text, code, CSV or log file with more text than that has its passages spread over the whole file (since coxswain 2.33.0), and so does a Word, OpenDocument, spreadsheet or presentation file with about 3 MB of text or more; a PDF's passages come from its first 4 MB of text. To give every part of a long file a vector of its own, choose *Everything* for its folder ([Long files](long-files.md)). Before 1.39.0 only the first 960 words counted. #### Why is search by meaning re-reading everything? Once after an update that changes how files are cut into passages: 1.39.0 (whole documents, not the first 960 words) and 2.18.0 (code cut at its functions and classes, with its lines, [Ask about code](ask-code.md)); 2.33.0 made again only the vectors of text, code, CSV and log files with more than 4 MB of text and of Word, OpenDocument, spreadsheet and presentation files with about 3 MB of text or more, whose passages now come from the whole file. Choosing *Everything* for long files reads those files again or makes their vectors again, once ([What is read again](long-files.md#what-is-read-again)). Vectors made the old way cannot be mixed with the new ones. The helper notices it when it opens the store, drops the old vectors and makes new ones in the background, the most recently changed files first. The text is not read again, except files of code once with their indentation, and search by words works all the while. Both apps say it once: *Search by meaning is being renewed to read your files better: 23,088 files, about 3 hours on this machine* (the time is measured on the first files). Settings (desktop) and Find's footer (both apps) show the files to go. Until a file has its new vectors, it is found by its words only. A store copied to another machine is renewed there the same way. #### How long does the renewal take? Somewhat longer than turning search by meaning on took the first time: a long file now gets up to 256 vectors where it had 8, a short one the same as before. Measured on this documentation (93 pages, many of them long), per 1,000 files: about an hour with the built-in model on the CPU (40 minutes before), 4 minutes with bge-m3 on a laptop's GPU (2 before), twice that with the rests between files ([Performance](../reference/performance.md#search-by-meaning-whole-documents)). It waits on battery, as always; *Read now* skips the rests. The notice says how long it is likely to take on your machine, from the first files. #### Why did the renewal crawl on a large store? Before 2.8.1, choosing the next few files read the text of every file still waiting: with 300,000 waiting, two seconds for each eight files, more than the server took to make their vectors. From 2.8.1 an index finds them at once, and a server's work is followed by a shorter rest. Folders a program marked as its cache (`CACHEDIR.TAG`, as in Cargo's build folders) are no longer read either, see [Choosing the folders](folders.md): their text already in the store goes at the helper's next walk of the folders read. #### Why does it show files that have nothing to do with my question? It shows the files closest to your question, above a floor. When nothing in your files is about it, the closest may still pass. Files with your words are under *In files*, apart from them; use more specific words. #### Where is the model kept and how do I delete it? In Coxswain's cache folder under `models/` (`coxswain --paths` prints it as `model`; Settings shows it under *Finding files → Details → Meaning*, and under *Privacy and updates → Where things are kept*). **Delete the model** there, or `coxswain --meaning delete`. #### Does the model send anything anywhere? No. The download is the only network use; after it, the model runs on your machine and nothing you have leaves it. See [Privacy](../reference/privacy.md). #### Can I type the question in English and find Danish files? Yes. The model is multilingual: a question and a passage about the same thing get close vectors whatever their languages. #### Does it slow my machine down? It works on two threads (or the GPU on a Mac), in batches with rests, and not on battery. Searching is quick; making the vectors the first time is the slow part. #### Why did turning it on turn on *Words inside files* too? Search by meaning works on the text the helper keeps, so it needs *Words inside files*. The level *Names, text and meaning* and the button *Download the model … and turn on* turn them on with it. --- [← Previous: Removable disks](removable-disks.md) · [Next: Long files: sample or everything →](long-files.md)