YouBothAgent▾
You — Business rules and flows you own. Read these yourself.
Both — Know the idea; your agent follows the details.
Agent — Conventions and references your agent follows. Look up as needed.

Interface▾


Observability▾text role in constant.ts.q.search(text) from a filter in document.ts.listBySearch, sorted by "relevance".{ text: "title" }.document.ts. The service gets methods named after it, like listBySearch.{ text: "title" }. Pick the role by what the value is, not by how badly you want it found: each role carries its own ranking weight.| Role | Weight |
|---|---|
| ↳ Use | |
| title | 10 |
| The name a person types into the search box. Ranked above everything else. | |
| tag | 3 |
| A keyword list. Ranked below the title and above prose. | |
| desc | 1 |
| Prose. It matches, but should not beat a name match. | |
| filter | 0 |
| A scoping value like status or owner. Searchable, never a reason to rank first. | |
| thumb | — |
| Stored with the entry so you can draw the result. Not indexed, so it never matches. | |
title, tag and desc take a String. filter and thumb also take an ID or a relation such as field(File), and a string enum counts as a String.[String] indexes every item, and a role inside an embedded scalar is indexed through its parent. A field inside a Map indexes nothing.


field.secret, field.hidden and resolve() take no text role. The index stores plain text, so an indexed secret would leak through search. The type check refuses it.q.search() is a query node like any other, so it combines with ordinary conditions inside q.all(). You do not need a slice to search from a service..arg() is required, .opt() may be left out and comes after every .arg(). Both reach .query() in the order declared, followed by q.{} adds no condition. With no statuses given, only the search narrows the results..query() in the dictionary, arguments included:{ sort, skip, limit } argument orders and pages them.exec to return.q.search().Ken misses Kenny.thumb is not indexed, so it is not a column.follow-up finds “follow-up” and “follow up”.| When sort is |
|---|
| ↳ Order |
"relevance" |
| Best match first. |
Any other key, like "latest" |
| That key wins over the score. |
| Left off, in a service call |
| Best match first, because the query holds a search. |
| Left off, on a slice endpoint |
"latest" is filled in, so the score is never used. |


"relevance" by name. A slice endpoint fills in "latest" when sort is left off, so it never falls through to the score..slice() with a .desc(). An MCP agent picks the tool by that description.st.do.initProductBySearch(text, statuses, { sort: "relevance" })..live() slice holding one declares { fallback: "invalidate" }.

init({ guards }). The slice() map covers the root slice and generated CRUD. With no guards of its own, the search is open to anyone over HTTP and left out of MCP.q.search() throws. Filters that declare it still build; only a query that reaches it fails.unicode61 needs unaccent unless it is remove_diacritics 0, and trigram needs pg_trgm. Akan creates it if its database role has the privilege; otherwise run CREATE EXTENSION unaccent (or pg_trgm) as a role that has it.LC_CTYPE, such as en_US.UTF-8 or C.UTF-8. Otherwise case is ignored for ASCII letters only, where SQLite ignores it for every letter.unicode61, Postgres indexes the first 20,000 characters of a document's title, tag and filter text and the first 200,000 of its desc.q.search() cannot go, and what else tends to surprise people:q.search() sits at an AND position only. Under q.any() or q.not() the query throws.updateOne / updateMany / removeOne / removeMany and the generated updateBySearch / removeBySearch family refuse it (the error names updateOneByQuery or updateManyByQuery), because a bulk write cannot join the index.schema.index() has nothing to do with search. Even schema.index({ name: "text" }) builds an ordinary lookup index.