Using Vector

The corpus is the truth; the vectors are derived

Semantic search over your own content is the walkthrough, the reference has every option, and pithy vector is what provisions and reprocesses.

Documents live in your own database. The index holds embeddings of them.

That is the argument for keeping it that way, and it becomes load-bearing the first time you need a rebuild: only what your database holds comes back, because there is nothing else to rebuild from.

Writing a document

Write the text into the corpus with the metadata you declared filterable, and the embedding follows.

Chunking stays yours. How a long document is split into embeddable pieces depends entirely on what your documents are, and a wrong default produces bad search that looks like a model problem.

Write the chunks as separate documents with shared metadata, and the filter you declared is what groups them back together.

Querying

const matches = await vector.query("docs", {
  text: "how do refunds work",
  filter: { ownerId: userId },
  topK: 10,
});

Every filter is typed against the schema, and a filter on a field the schema does not mark filterable is a compile error rather than a silent partial result.

That is the whole point of the capability, and it is worth restating: the store returns partial results silently when you filter on an unindexed field. A compile error is a much better afternoon.

The default result count

Ten, when the caller names none. A search page, not a scan — and the store has its own ceiling above that.

Filtering is a schema decision wearing a query-time costume

Ten metadata indexes per index, and an index created after vectors were written covers none of them, with no backfill.

So which fields can I filter on is answered when you write the schema, not when you write the query.

Think about it before the first write: owner, date range, type, visibility are the four that show up in almost every product.

The boot check

The Worker compares its declarations against what provisioning observed and refuses to serve on drift.

It is the only way somebody who edits the schema and deploys without re-provisioning finds out — because the store answers such a filter with partial results and no error.

Failing at startup with the field named is a much better afternoon than a search that quietly returns half of what it should for a month.

Changing the embedding model

The model is pinned per index for writes and queries alike.

A query embedded with a different model than the vectors it searches produces results that look plausible and are wrong — which is worse than an error, because nobody reports it.

pithy vector reprocess --env staging --all

Without the flag, only the documents whose model differs from config are re-embedded, which is usually what you want. A filter narrows further, parsed in your terminal so a malformed one fails there rather than inside a running Workflow.

Adding a filterable field to a live index

There is no backfill. The repair is a rebuild.

pithy vector reset --env staging --confirm-reset "yes, i really want to reset staging"

Deletes the index, rebuilds it through the ordinary provision path, and re-embeds from your corpus.

Destructive by definition, and the phrase names its environment so one typed for staging cannot be pasted into a command targeting another. dev is free.

Dev costs real queries

There is no local emulation. A dev search reaches a real remote index, which is why the bindings are declared remote.

Budget for it, and know that --env dev on the provision command still needs an account.

What is not here

No chunking, for the reason above.

Not a retrieval framework. No prompt templates, no chains, no reranking. It embeds, indexes and queries; what you do with the matches is your application.

Not keyword search. Semantic and lexical answer different questions, and exactly this string is often the question — which is why the support capability uses a full-text index instead.

ESC