rsearch is a multi-source search aggregator. It queries multiple independent search providers in adaptive priority order and returns the first successful result set. Provider ordering is determined by a score combining success rate (70%) and response speed (30%).
The root endpoint / serves a backend-rendered HTML page.
When no query is provided, a landing page with a search form is shown.
When a query is submitted, results are displayed in a structured format with
title, URL, description, and optional content preview.
| Parameter | Default | Description |
|---|---|---|
query | empty | Search query string. When empty, the landing page is shown. |
count | 10 | Number of results to return (1-100). |
content | false | Set to true to fetch full page content for each result.
Content is extracted using trafilatura/BeautifulSoup and displayed as a truncated preview with the full text available in hidden HTML for scrapers. |
cache | true | Set to false to bypass all cache layers (page cache, search result cache, content cache).
Forces fresh requests to search providers and content URLs. |
ai | false | Set to true to enable AI mode.
The query text serves as a prompt for the AI assistant. See AI Mode section below. |
When ai=true, the system operates differently:
Example with curl:
curl "https://rsearch.app.molodetz.nl/?query=What+is+the+capital+of+France%3F&ai=true"
GET /search returns JSON and supports all the same parameters as the web interface:
query, count, content, cache, and ai.
The behavior is identical. Response format:
{
"query": "search terms",
"source": "provider_name",
"count": 10,
"results": [
{
"title": "Result Title",
"url": "https://example.com",
"description": "Result description",
"source": "provider_name",
"extra": {},
"content": "Full page content (when content=true)"
}
],
"ai_response": "AI answer (when ai=true, null otherwise)",
"ai_error": null,
"timestamp": "2026-01-01T00:00:00Z",
"success": true,
"error": null
}
When ai=true, the ai_response and ai_error fields are included.
If the AI answered without searching, source is "ai" and results is empty.
Cache bypass (cache=false) applies to search and content caches identically to the web interface.
The /chat endpoint provides direct access to the configured AI model for
chat completions without search integration. Responses are cached for 2 weeks by default.
Supports both GET and POST methods.
Outer markdown code fences are always stripped from responses automatically.
| Property | Value |
|---|---|
| Max context window | 131,072 - 1,048,576 tokens (varies by model) |
| Max output tokens | Dynamic (derived from model context window minus prompt size) |
| Temperature | 0.0 (deterministic) |
| Cache TTL | 2 weeks |
| Parameter | Default | Description |
|---|---|---|
prompt | required | The text prompt to send to the AI model. |
system | built-in default | Custom system message to control the AI behavior and persona. When omitted, a default instruction is used. Becomes part of the cache key. |
json | false | Set to true to enforce JSON output.
The model is instructed to respond with valid JSON only and any markdown code fences are stripped. |
cache | true | Set to false to bypass the chat cache and force a fresh AI call. |
Pass parameters as query string values.
curl "https://rsearch.app.molodetz.nl/chat?prompt=What+is+the+capital+of+France%3F"
curl "https://rsearch.app.molodetz.nl/chat?prompt=List+three+programming+languages&json=true"
curl "https://rsearch.app.molodetz.nl/chat?prompt=Hello&cache=false"
curl "https://rsearch.app.molodetz.nl/chat?prompt=Translate+hello+to+French&system=You+are+a+translator"
Send parameters as form data or JSON body.
curl -X POST https://rsearch.app.molodetz.nl/chat -d "prompt=What is the capital of France?"
curl -X POST https://rsearch.app.molodetz.nl/chat -H "Content-Type: application/json" \
-d '{"prompt": "List three colors", "json": true}'
curl -X POST https://rsearch.app.molodetz.nl/chat -H "Content-Type: application/json" \
-d '{"prompt": "Summarize quantum computing", "system": "You are a physics professor. Explain concepts clearly."}'
{
"response": "The capital of France is Paris.",
"prompt": "What is the capital of France?",
"json_mode": false,
"max_context_window": "(dynamic, based on model)",
"max_output_tokens": "(dynamic, context minus prompt)",
"usage": {
"prompt_tokens": 42,
"completion_tokens": 12,
"total_tokens": 54,
"cost_usd": 0.0
},
"elapsed": 1.2345,
"cached": false,
"timestamp": "2026-01-01T00:00:00Z",
"error": null
}
Outer markdown code fences are always stripped from responses.
When json=true, the response field contains raw JSON (as a string) and
the model is additionally instructed to produce valid JSON only.
When served from cache, cached is true and token usage reflects the original call.
The system parameter is part of the cache key, so different system messages produce separate cache entries.
The /describe endpoint accepts images for AI vision analysis. Three methods are supported:
Describe an image by URL. The image is fetched by the vision model directly.
curl "https://rsearch.app.molodetz.nl/describe?url=https://en.wikipedia.org/static/images/project-logos/enwiki.png"
Upload an image file. The file is read, MIME type is auto-detected from file headers (PNG, JPEG, GIF, WebP, BMP), converted to a base64 data URI, and sent to the vision model. Maximum size: 10 MB.
curl -X POST https://rsearch.app.molodetz.nl/describe -F "file=@photo.jpg"
Send raw image bytes in the request body with the appropriate Content-Type header. If Content-Type is not an image type, MIME detection runs on the raw bytes.
curl -X POST https://rsearch.app.molodetz.nl/describe -H "Content-Type: image/png" --data-binary @photo.png
Response format (all methods):
{
"description": "A detailed description of the image...",
"mime_type": "image/png",
"size": 12345,
"elapsed": 2.1234,
"timestamp": "2026-01-01T00:00:00Z"
}
Results are cached for 7 days by content hash (uploaded data) or URL. Auto-detected MIME types: PNG, JPEG, GIF, WebP, BMP.
GET /health returns JSON with service status, provider ordering by score,
per-provider statistics (success rate, average response time), and cache entry counts.
All cache layers are filesystem-based under ~/.cache/rsearch/ and shared across all workers:
pages/search/content/vision/chat/When cache=false, all layers are bypassed and fresh data is fetched.
Results are still stored in cache for subsequent requests.
To clear all caches: rm -rf ~/.cache/rsearch/
HTML responses include structured metadata for automated consumption:
<meta name="rsearch:*"> tags in <head> with query, source, count, response time, cache status, and timestamp.<article> element with data-source, data-url, and data-content-length attributes.<div class="content-full"> element within each result article.Every HTTP response includes debug headers with AI token usage and cache status:
| Header | Description | Default |
|---|---|---|
X-AI-Prompt-Tokens |
Input tokens sent to AI model | 0 |
X-AI-Completion-Tokens |
Output tokens from AI model | 0 |
X-AI-Total-Tokens |
Sum of prompt and completion tokens | 0 |
X-AI-Cost-USD |
Total dollar cost for AI calls in this request | 0.000000 |
X-Cache-Search |
Whether search results were served from cache | false |
X-Cache-Page |
Whether the full HTML page was served from cache | false |
X-Cache-Content |
Whether fetched page content was served from cache | false |
X-Cache-Vision |
Whether AI image descriptions were served from cache | false |
X-Cache-Chat |
Whether chat response was served from cache | false |
Token counts accumulate across all AI calls within a single request (chat rounds, tool calls, vision). Cache headers reflect whether any result of that type was served from cache during the request.
When all search providers fail, a 503 status page is returned with the message "All search providers are currently exhausted." This page is not cached. When content fetching fails for individual results, the HTTP method and status code are displayed (e.g., "Content unavailable (GET 403)").