Search that understands what you meant.
Index your notes, docs, or tickets and find them by meaning instead of exact words. Then hand the matches to an AI and let it answer from your own material. It runs on your project's Postgres, so there is no vector database to go set up.
Two files. One is the index, one is the answer.
Every retrieval system is the same two halves: put text in so it can be found, then find it and use it. Here is what your agent writes for both, in the shape the platform teaches it.
import { db, knowledge } from 'hatchable';
export const methods = ['POST'];
export const access = 'member';
export default async function (req, res) {
const docs = knowledge.base('help_docs', {
dimensions: 1536,
});
const { title, body } = req.body;
const { rows } = await db.query(
`INSERT INTO articles (title, body)
VALUES ($1, $2) RETURNING id`,
[title, body]
);
// chunkText is your own helper
await docs.add(chunkText(body).map((text, i) => ({
id: `article:${rows[0].id}:chunk:${i}`,
text,
metadata: { articleId: rows[0].id, title },
})));
res.json({ id: rows[0].id });
}
import { knowledge, ai } from 'hatchable';
export const methods = ['POST'];
export const access = 'member';
export default async function (req, res) {
const docs = knowledge.base('help_docs', {
dimensions: 1536,
});
// nearest six by meaning, not by keyword
const hits = await docs.search(
req.body.question, { topK: 6 }
);
const context = hits
.map((h, i) => `[${i + 1}] ${h.metadata._text}`)
.join('\n\n');
const { text } = await ai.generateText({
model: 'sonnet',
system: `Answer using ONLY the context below.
Cite sources by number.\n\n${context}`,
prompt: req.body.question,
purpose: 'rag-answer',
});
res.json({
answer: text,
sources: hits.map(h => h.metadata.title),
});
}
Retrieval, without the shopping list.
The pieces you would otherwise assemble from an embedding API, a vector store, and a chunking library. All three are already here and already talking to each other.
Finds it when the words don't match
Results come back ranked by how close the meaning is, not by how many words overlap. Someone can ask in their own phrasing and still land on the right paragraph.
"How do I stop paying" finds the page titled "Cancelling your subscription".
An AI that answers from your material
Pull the closest passages, hand them to a model as context, get back an answer grounded in your own documents. Each hit carries its original text and metadata, so citing the source is a one-liner.
A support box that answers from your manual and links the section it used.
It lives where your data lives
A knowledge base is a table in your project's own Postgres, with the search index built on it the first time you use it. One database to reason about, one place your rows live.
Nothing new to provision, and nothing new to keep in sync.
Text in, text out
Adding an item takes plain text and does the embedding for you. Searching takes a plain question and embeds that too. The vector maths is real, it just isn't yours to write.
docs.add([{ id, text }]) is the entire indexing step.
Search inside one person's content
Tag items with metadata when you index, then narrow by it at search time. The narrowing happens before ranking, so the best matches come from inside that slice rather than being filtered out after the fact.
Two customers, one knowledge base, and neither can retrieve the other's notes.
Fill it without writing code
The project console has a Knowledge tab where you paste text or drop a .txt or .md file. The platform splits it into roughly 500-token pieces, embeds each one, and lists what it stored, chunk counts and all.
You paste the FAQ once. The app only ever calls search.
Written down in the project
Your agent declares each knowledge base in the project's config file with a name, a size, and who is expected to fill it. Deploy checks the declaration, and the console grows a card for every one so nothing sits half configured.
A template can ship with an empty base and a prompt telling the new owner to fill it.
Plain SQL when you need it
The simple call covers most of it. When it doesn't, the knowledge base hands you its table name and a helper for the query vector, so you can join similarity ranking to your own tables in one query.
Rank by meaning, but only among the articles you have actually published.
The spec sheet, in plain terms.
knowledge.base('name', { dimensions: 1536 }). Dimensions are required, on purpose. Names use lowercase letters, digits and underscores, up to 63 characters.add([{ id, text, metadata }]) embeds and stores in one call, up to 1,000 items at a time. Adding the same id again updates it in place.search(query, { topK, filter }) returns id, similarity and metadata, closest first. topK defaults to 10. Filters match metadata exactly and apply before ranking.Numbers current as of August 2026 and read from the same limits table the pricing page renders from.
Say it like this.
Nobody has to say the word "embedding". These are ordinary asks that turn into an index, a query, and an answer.
Asked and answered.
Do I need a separate vector database?
No. The vectors live in your project's own Postgres, in a table sitting next to your ordinary ones. There is nothing extra to sign up for, no second connection string, and no second bill.
Does this need an AI key?
Yes. Turning text into something searchable by meaning is a paid call to an embedding provider, and Hatchable does not hold provider keys. Set an OpenAI key on the project or on your account and both indexing and searching work. Without one you get a plain error pointing at the console page that fixes it.
How is this different from a keyword search?
Keyword search looks for the words you typed. This looks for what those words mean, so "how do I stop paying" finds an article titled "Cancelling your subscription". Ordinary SQL is still there for exact matches, and you can combine the two in one query.
Do I have to prepare the documents first?
Not if you go through the console. Paste text or drop a .txt or .md file into the Knowledge tab and the platform splits it into roughly 500-token pieces, embeds each one, and stores them. When your app indexes content from its own code instead, splitting long documents into pieces is your side of the job.
Can each person search only their own content?
Yes. Attach metadata when you index, then pass a filter when you search. The filter is applied before ranking, so the results come from inside that person's content only. Worth wiring up on day one in any app with more than one customer.
What if I outgrow the simple search call?
Drop into SQL. A knowledge base hands you its table name and a helper for the query vector, so you can join similarity ranking to your own tables and add whatever conditions you want. Same rows, full control.
The full surface lives in the SDK reference, and the declaration format in the config reference.
Stop shopping for a vector database.
Connect the AI you already use, tell it what should be findable, and the embedding, the index, and the query all arrive with the project.
Want the technical surface? The SDK reference covers knowledge.base, add, search, and the SQL escape hatch.