The question, and nothing else about you
The words the member used, with the trigger removed. Not who asked, not where, not what came before.
Out, and not out
What goes out is the question, in the member's own words, with the trigger phrase removed and a length bound applied. No model rewrites it first. What never goes out is who asked, which group they asked in, what was said before, or which bot is asking.
No page is ever fetched. She sees a title, a snippet and a link, and that is the whole of it.
a provider offering page bodies would be offering a much larger injection surface
Only when asked, and asked deterministically
She searches only when a member asks her to, and the trigger is a deterministic phrase list rather than a judgement. There is deliberately no heuristic for "this sounds like it wants current information": a false positive there is not a clumsy answer, it is an outbound request and a stranger's text entering her prompt.
Refused before anything leaves the machine
The model cannot prevent an outbound request, because it does not see the request until the search has run.
Why the order matters
A request she would refuse never reaches the provider. That ordering is the whole point: the model does not see the request until after the search has run, so a refusal from the model cannot prevent the outbound call. Four categories are refused outright, before anything is sent.
Why there is no threshold to lower
There is deliberately no setting here. A threshold an operator could lower is a threshold that ends with the domains back in the group, and these categories are not a matter of taste. Changing them is a code change and a review.
It is a term list, and a term list has limits: it misses paraphrase, it covers two languages, and it will occasionally refuse a legitimate question that happens to use a screened word. It is a floor under her own refusal, not a replacement for it.
Scored against the question, then discarded
Results are measured for relevance before she sees any of them, and the budgets are a safety control rather than a quality knob.
| Question | Answer |
|---|---|
| The provider | Brave by default, or Serper. Brave requires a paid key with no free tier since February 2026; Serper has a free monthly allowance and serves scraped results. The key is stored write-only and encrypted, sent in a header, never in the URL and never logged |
| What is sent, and what is not | The query only: the member own words with the trigger phrase removed, trimmed to 300 characters, with no model distillation. Never sent: member identity, group, history, bot name. No page is ever fetched, so title, snippet and URL are all that arrive |
| The trigger | A deterministic phrase list, so a model resolver claiming a lookup nobody asked for is downgraded. One widening: a question about a named thing she has no material for searches first instead of guessing |
| The floor | Every result is scored against the question by the local embedder, with a floor of 0.70, measured over 6 queries and 27 results. The two pages behind the production failure scored 0.58 and 0.55, which is why the knowledge base floor was not copied. Below the floor nothing reaches the model |
| Budgets | Results per search, characters per result and characters in total, plus 5 searches per member and 20 per chat over a 600 second window |
a safety control, not a quality knob
Written by the application, never by her
It names only the results the answer actually used, and a refusal cites nothing at all.
🔎 From search previews, which can be out of date. Check the page: {sources}
⚠️ That number is from a search preview. I have not read the page it came from.
Why it is built that way
The domain is the part a reader judges the answer by, and the numbered link carries the full URL so the page is actually reachable. The number rather than the domain is the visible link text because the chat client requires it: a dot inside the display text makes the whole message render as literal brackets.
The line is written by the application and never by her, it names only the results the answer actually used, and a refusal cites nothing at all. If she declares nothing, the line is omitted rather than guessed at.
Six ways to say it, and no guess
Every way a search can come back empty has its own line, and the operator can edit all of them.
What she says, and when
- unavailable🔌 I could not look that up just now, so I am not going to guess at it. Try me again in a bit.
- zero results🕳️ Looked, and came back with nothing worth repeating. I am not going to invent one for you.
- all below floor🕳️ I looked, and what came back was about something else entirely. I am not going to dress that up as an answer.
- embedder down🌫️ I looked, but I could not check whether any of it was actually about your question, so I am leaving it alone rather than guessing.
- words failed🤐 I did the looking and found something, and then lost the words for it. Ask me again and I will have another go.
- gate refused🚫 I am not searching the web for that. Ask me something else.
she never falls back to answering from training data and presenting it as current
She refused, and the sources shipped anyway
The failure that produced the pre-search gate, and the reason a source line is now minted from the answer.
A member asked her to search for pornography. She refused, twice, in character and correctly.
Not happening.
I don't do that. Try something else.
What happened next
Then the application printed a source line under her refusal, naming the sites the search had returned. The line began From the web: and the domains followed. She had refused; the search had already run.
Both halves, and which is which
Both halves were wrong and both were fixed. The refusal now happens before the request goes out, so there is nothing to cite; and sources are minted only from the results an answer declared it used, so a source line cannot outlive the answer it was attached to. The line quoted above is the one that shipped then, not the one that ships now.