Search

There are three searches in a workspace and they are different mechanisms, not three spellings of one. Picking the wrong one usually returns nothing, quietly.

6 min

Which one

Start here.

You wantUseIt matches
A document containing a word or a namesearchWords. Ranked by BM25.
Something the team worked out, however it was phrasedthought-searchMeaning, blended with words.
A question with no keyword in it at allsqlStructure — dates, counts, nulls, joins.

Document search is keyword search

Which makes it excellent, and sharp.

beehaven search "vectorize pricing"
beehaven grep pricing ~

It runs full-text search over the title and the body and ranks with BM25. On a corpus full of distinctive identifiers — a constant name, a file name, a ticket key — that is arguably better than a semantic index: there is no chunking to lose a boundary, no re-embedding on edit, and an exact identifier goes straight to the row.

A paraphrase can return nothing. Searching for the exact term in a document finds it immediately; searching for a description of what that term means — the same idea in other words — can return unrelated documents and miss the right one entirely. Nothing errors. Query documents with the vocabulary the document would itself use.

Note search is stemmed, so crediting finds a document that says credits. That is a property of documents specifically — it is not applied to the thought map, whose scoring is calibrated separately.

Thought search is meaning search

Query it with the idea.

beehaven call thought-search '{"query":"what stops two unrelated ideas being joined"}'

The thought map holds the claims a workspace has worked out, and its search blends three signals — a literal match, word overlap, and an embedding comparison — taking the strongest rather than the average. Averaging would drag both good cases toward the threshold via the method that was never going to see them: an identifier match and a clean paraphrase both average to the middle.

So this is the surface to ask a question in your own words. It is also the surface that can answer across time — a decision recorded in one conversation can answer a question asked weeks later in a different one, because there is one map per workspace rather than one per conversation.

If the AI budget is exhausted or the embedding service is unavailable, thought search degrades to word matching rather than failing. Results get worse; nothing breaks.

SQL is for the questions with no keyword

Read-only, and guarded.

beehaven sql "SELECT title, updated_at FROM notes
              WHERE project_id = 'x' AND updated_at > 1757000000000
              ORDER BY updated_at DESC"

“Which documents in this project changed since Monday”, “how many have no body”, “which project holds the most” — none of these has a word to search for. They are WHERE clauses, and before this existed the only route was to list everything and filter by hand, which stops working the moment the list outgrows the window.

AllowedRefused
One statement, SELECT or WITHAnything that writes
Reading your own workspace tablesCredential-bearing tables
Schema discovery via pragma_table_infoA bare PRAGMA statement

Secret-shaped columns come back as [redacted] rather than being removed — an agent that cannot see a column reports that the field does not exist, where one that sees a redaction knows the row holds something it may not read. Rows and cell lengths are capped.

Finding the schema

beehaven sql "SELECT name FROM sqlite_master WHERE type='table'"
beehaven sql "SELECT * FROM pragma_table_info('notes')"

One door per surface

Deliberately.

From a shell, SQL is reached through beehaven sql. An agent with a shell reaches it the same way; an agent without one calls the workspace-sql action. There is no second implementation behind either — two ways to do one job is how a model picks at random, and how one path ends up unguarded while the other keeps passing tests.

workspace-sql takes its statement as query. Passing sql — the obvious guess — used to be dropped by validation, and the empty query returned the schema: ok: true, a confident list of tables, and not your answer. sql and statement are accepted aliases now.