Tools & Plugins / Tools
Web search
The web_search tool searches the web using your configured provider and
returns results. Results are cached by query for 15 minutes (configurable).
Genesis also includes x_search for X (formerly Twitter) posts and
web_fetch for lightweight URL fetching. In this phase, web_fetch stays
local while web_search and x_search can use xAI Responses under the hood.
web_search is a lightweight HTTP tool, not browser automation. For
JS-heavy sites or logins, use the Web Browser. For
fetching a specific URL, use Web Fetch.
Quick start
Choose a provider
Pick a provider and complete any required setup. Some providers are key-free, while others use API keys. See the provider pages below for details.
Configure
genesis configure --section web
This stores the provider and any needed credential. You can also set an env
var (for example BRAVE_API_KEY) and skip this step for API-backed
providers.
Use it
The agent can now call web_search:
await web_search({ query: "Genesis plugin SDK" });
For X posts, use:
await x_search({ query: "dinner recipes" });
Choosing a provider
-
Brave Search Structured results with snippets. Supports
llm-contextmode, country/language filters. Free tier available. -
DuckDuckGo Key-free fallback. No API key needed. Unofficial HTML-based integration.
-
Exa Neural + keyword search with content extraction (highlights, text, summaries).
-
Firecrawl Structured results. Best paired with
firecrawl_searchandfirecrawl_scrapefor deep extraction. -
Gemini AI-synthesized answers with citations via Google Search grounding.
-
Grok AI-synthesized answers with citations via xAI web grounding.
-
Kimi AI-synthesized answers with citations via Moonshot web search.
-
MiniMax Search Structured results via the MiniMax Coding Plan search API.
-
Ollama Web Search Key-free search via your configured Ollama host. Requires
ollama signin. -
Perplexity Structured results with content extraction controls and domain filtering.
-
SearXNG Self-hosted meta-search. No API key needed. Aggregates Google, Bing, DuckDuckGo, and more.
-
Tavily Structured results with search depth, topic filtering, and
tavily_extractfor URL extraction.
Provider comparison
| Provider | Result style | Filters | API key |
|---|---|---|---|
| Brave | Structured snippets | Country, language, time, llm-context mode |
BRAVE_API_KEY |
| DuckDuckGo | Structured snippets | -- | None (key-free) |
| Exa | Structured + extracted | Neural/keyword mode, date, content extraction | EXA_API_KEY |
| Firecrawl | Structured snippets | Via firecrawl_search tool |
FIRECRAWL_API_KEY |
| Gemini | AI-synthesized + citations | -- | GEMINI_API_KEY |
| Grok | AI-synthesized + citations | -- | XAI_API_KEY |
| Kimi | AI-synthesized + citations | -- | KIMI_API_KEY / MOONSHOT_API_KEY |
| MiniMax Search | Structured snippets | Region (global / cn) |
MINIMAX_CODE_PLAN_KEY / MINIMAX_CODING_API_KEY |
| Ollama Web Search | Structured snippets | -- | None by default; ollama signin required, can reuse Ollama provider bearer auth |
| Perplexity | Structured snippets | Country, language, time, domains, content limits | PERPLEXITY_API_KEY / OPENROUTER_API_KEY |
| SearXNG | Structured snippets | Categories, language | None (self-hosted) |
| Tavily | Structured snippets | Via tavily_search tool |
TAVILY_API_KEY |
Auto-detection
Native OpenAI web search
Direct OpenAI Responses models use OpenAI's hosted web_search tool automatically when Genesis web search is enabled and no managed provider is pinned. This is provider-owned behavior in the bundled OpenAI plugin and only applies to native OpenAI API traffic, not OpenAI-compatible proxy base URLs or Azure routes. Set tools.web.search.provider to another provider such as brave to keep the managed web_search tool for OpenAI models, or set tools.web.search.enabled: false to disable both managed search and native OpenAI search.
Native Codex web search
Codex-capable models can optionally use the provider-native Responses web_search tool instead of Genesis's managed web_search function.
- Configure it under
tools.web.search.openaiCodex - It only activates for Codex-capable models (
openai-codex/*or providers usingapi: "openai-codex-responses") - Managed
web_searchstill applies to non-Codex models mode: "cached"is the default and recommended settingtools.web.search.enabled: falsedisables both managed and native search
{
tools: {
web: {
search: {
enabled: true,
openaiCodex: {
enabled: true,
mode: "cached",
allowedDomains: ["example.com"],
contextSize: "high",
userLocation: {
country: "US",
city: "New York",
timezone: "America/New_York",
},
},
},
},
},
}
If native Codex search is enabled but the current model is not Codex-capable, Genesis keeps the normal managed web_search behavior.
Setting up web search
Provider lists in docs and setup flows are alphabetical. Auto-detection keeps a separate precedence order.
If no provider is set, Genesis checks providers in this order and uses the
first one that is ready:
API-backed providers first:
- Brave --
BRAVE_API_KEYorplugins.entries.brave.config.webSearch.apiKey(order 10) - MiniMax Search --
MINIMAX_CODE_PLAN_KEY/MINIMAX_CODING_API_KEYorplugins.entries.minimax.config.webSearch.apiKey(order 15) - Gemini --
GEMINI_API_KEYorplugins.entries.google.config.webSearch.apiKey(order 20) - Grok --
XAI_API_KEYorplugins.entries.xai.config.webSearch.apiKey(order 30) - Kimi --
KIMI_API_KEY/MOONSHOT_API_KEYorplugins.entries.moonshot.config.webSearch.apiKey(order 40) - Perplexity --
PERPLEXITY_API_KEY/OPENROUTER_API_KEYorplugins.entries.perplexity.config.webSearch.apiKey(order 50) - Firecrawl --
FIRECRAWL_API_KEYorplugins.entries.firecrawl.config.webSearch.apiKey(order 60) - Exa --
EXA_API_KEYorplugins.entries.exa.config.webSearch.apiKey(order 65) - Tavily --
TAVILY_API_KEYorplugins.entries.tavily.config.webSearch.apiKey(order 70)
Key-free fallbacks after that:
- DuckDuckGo -- key-free HTML fallback with no account or API key (order 100)
- Ollama Web Search -- key-free fallback via your configured Ollama host; requires Ollama to be reachable and signed in with
ollama signinand can reuse Ollama provider bearer auth if the host needs it (order 110) - SearXNG --
SEARXNG_BASE_URLorplugins.entries.searxng.config.webSearch.baseUrl(order 200)
If no provider is detected, it falls back to Brave (you will get a missing-key error prompting you to configure one).
All provider key fields support SecretRef objects. Plugin-scoped SecretRefs
under plugins.entries.<plugin>.config.webSearch.apiKey are resolved for the
bundled Exa, Firecrawl, Gemini, Grok, Kimi, Perplexity, and Tavily providers
whether the provider is picked explicitly via tools.web.search.provider or
selected through auto-detect. In auto-detect mode, Genesis resolves only the
selected provider key -- non-selected SecretRefs stay inactive, so you can
keep multiple providers configured without paying resolution cost for the
ones you are not using.
Config
{
tools: {
web: {
search: {
enabled: true, // default: true
provider: "brave", // or omit for auto-detection
maxResults: 5,
timeoutSeconds: 30,
cacheTtlMinutes: 15,
},
},
},
}
Provider-specific config (API keys, base URLs, modes) lives under
plugins.entries.<plugin>.config.webSearch.*. See the provider pages for
examples.
Tor and .onion services
web_search shares the same tools.web.tor config as web_fetch. When Tor is
enabled, any provider request whose endpoint hostname ends with .onion is
routed through the configured SOCKS5 proxy. Clearnet provider endpoints stay on
the normal direct path.
{
tools: {
web: {
tor: {
enabled: true,
mode: "external",
socksHost: "127.0.0.1",
socksPort: 9050,
},
},
},
}
This is most useful for self-hosted providers such as SearXNG
that may expose an .onion instance. .onion provider endpoints are blocked
when Tor is not enabled.
web_fetch fallback provider selection is separate:
- choose it with
tools.web.fetch.provider - or omit that field and let Genesis auto-detect the first ready web-fetch provider from available credentials
- today the bundled web-fetch provider is Firecrawl, configured under
plugins.entries.firecrawl.config.webFetch.*
When you choose Kimi during genesis onboard or
genesis configure --section web, Genesis can also ask for:
- the Moonshot API region (
https://api.moonshot.ai/v1orhttps://api.moonshot.cn/v1) - the default Kimi web-search model (defaults to
kimi-k2.6)
For x_search, configure plugins.entries.xai.config.xSearch.*. It uses the
same XAI_API_KEY fallback as Grok web search.
Legacy tools.web.x_search.* config is auto-migrated by genesis doctor --fix.
When you choose Grok during genesis onboard or genesis configure --section web,
Genesis can also offer optional x_search setup with the same key.
This is a separate follow-up step inside the Grok path, not a separate top-level
web-search provider choice. If you pick another provider, Genesis does not
show the x_search prompt.
Storing API keys
Config file
Run genesis configure --section web or set the key directly:
{
plugins: {
entries: {
brave: {
config: {
webSearch: {
apiKey: "YOUR_KEY", // pragma: allowlist secret
},
},
},
},
},
}
Environment variable
Set the provider env var in the Gateway process environment:
export BRAVE_API_KEY="YOUR_KEY"
For a gateway install, put it in ~/.genesis/.env.
See Env vars.
Tool parameters
| Parameter | Description |
|---|---|
query |
Search query (required) |
count |
Results to return (1-10, default: 5) |
country |
2-letter ISO country code (e.g. "US", "DE") |
language |
ISO 639-1 language code (e.g. "en", "de") |
search_lang |
Search-language code (Brave only) |
freshness |
Time filter: day, week, month, or year |
date_after |
Results after this date (YYYY-MM-DD) |
date_before |
Results before this date (YYYY-MM-DD) |
ui_lang |
UI language code (Brave only) |
domain_filter |
Domain allowlist/denylist array (Perplexity only) |
max_tokens |
Total content budget, default 25000 (Perplexity only) |
max_tokens_per_page |
Per-page token limit, default 2048 (Perplexity only) |
Not all parameters work with all providers. Brave llm-context mode
rejects ui_lang, freshness, date_after, and date_before.
Gemini, Grok, and Kimi return one synthesized answer with citations. They
accept count for shared-tool compatibility, but it does not change the
grounded answer shape.
Perplexity behaves the same way when you use the Sonar/OpenRouter
compatibility path (plugins.entries.perplexity.config.webSearch.baseUrl /
model or OPENROUTER_API_KEY).
SearXNG accepts http:// only for trusted private-network or loopback hosts;
public SearXNG endpoints must use https://.
Firecrawl and Tavily only support query and count through web_search
-- use their dedicated tools for advanced options.
x_search
x_search queries X (formerly Twitter) posts using xAI and returns
AI-synthesized answers with citations. It accepts natural-language queries and
optional structured filters. Genesis only enables the built-in xAI x_search
tool on the request that serves this tool call.
xAI documents x_search as supporting keyword search, semantic search, user
search, and thread fetch. For per-post engagement stats such as reposts,
replies, bookmarks, or views, prefer a targeted lookup for the exact post URL
or status ID. Broad keyword searches may find the right post but return less
complete per-post metadata. A good pattern is: locate the post first, then
run a second x_search query focused on that exact post.
x_search config
{
plugins: {
entries: {
xai: {
config: {
xSearch: {
enabled: true,
model: "grok-4-1-fast-non-reasoning",
inlineCitations: false,
maxTurns: 2,
timeoutSeconds: 30,
cacheTtlMinutes: 15,
},
webSearch: {
apiKey: "xai-...", // optional if XAI_API_KEY is set
},
},
},
},
},
}
x_search parameters
| Parameter | Description |
|---|---|
query |
Search query (required) |
allowed_x_handles |
Restrict results to specific X handles |
excluded_x_handles |
Exclude specific X handles |
from_date |
Only include posts on or after this date (YYYY-MM-DD) |
to_date |
Only include posts on or before this date (YYYY-MM-DD) |
enable_image_understanding |
Let xAI inspect images attached to matching posts |
enable_video_understanding |
Let xAI inspect videos attached to matching posts |
x_search example
await x_search({
query: "dinner recipes",
allowed_x_handles: ["nytfood"],
from_date: "2026-03-01",
});
// Per-post stats: use the exact status URL or status ID when possible
await x_search({
query: "https://x.com/huntharo/status/1905678901234567890",
});
Examples
// Basic search
await web_search({ query: "Genesis plugin SDK" });
// German-specific search
await web_search({ query: "TV online schauen", country: "DE", language: "de" });
// Recent results (past week)
await web_search({ query: "AI developments", freshness: "week" });
// Date range
await web_search({
query: "climate research",
date_after: "2024-01-01",
date_before: "2024-06-30",
});
// Domain filtering (Perplexity only)
await web_search({
query: "product reviews",
domain_filter: ["-reddit.com", "-pinterest.com"],
});
Tool profiles
If you use tool profiles or allowlists, add web_search, x_search, or group:web:
{
tools: {
allow: ["web_search", "x_search"],
// or: allow: ["group:web"] (includes web_search, x_search, and web_fetch)
},
}
Related
- Web Fetch -- fetch a URL and extract readable content
- Web Browser -- full browser automation for JS-heavy sites
- Grok Search -- Grok as the
web_searchprovider - Ollama Web Search -- key-free web search through your Ollama host