Documentation
Zethal Framework is the original framework MevaSearch was built on. Here is everything you need to run it, make it your own and connect real search and AI providers.
Requirements
- PHP 8.1 or newer.
- The
curlandmbstringextensions.gdis not needed. - Any web server that runs PHP: Apache, LiteSpeed, Nginx with PHP-FPM, or the built-in PHP server for local testing.
- Outbound HTTPS from the server to
wikipedia.organdwikimedia.org, or to your own provider.
No database, no Composer packages, no Node.js and no build step.
Installation
Clone the repository or download the ZIP, then put the files in your web root or in a subfolder.
git clone https://github.com/mevasearch/Zethal
cd Zethal
php -S 127.0.0.1:8080
Open http://127.0.0.1:8080 and search for anything. With no configuration at all, results come from Wikipedia, images and videos from Wikimedia Commons, and summaries are built from the top results without AI.
Files
index.php Home page with search bar and shortcuts
results.php Results page with tabs, summary and panel
settings.php Settings page
api.php Search endpoint used by results.js
ai.php Summary and photo search endpoint
bangs.php List of !bangs and the redirect logic
lang.php Language loading and small helpers
zethal-icons.php SVG icon sprite
styles.css All styles, light and dark
script.js Shared behaviour, settings, menus, bangs
results.js Loads and renders results
lang/en/ English texts and info.json
fonts/ Space Grotesk with its OFL license
LICENSE SA-SDL license text
CSS and JS links get a ?v= parameter from the file's modification time, so visitors always load the latest version after you upload a change.
Branding
Change the product name, tagline and description in lang/en/common.php, and in the same file of every other language you add.
'app_name' => 'Your Search',
'app_tagline' => 'Private search, beautifully simple',
'app_description' => 'A private search engine without ads or tracking.',
Colours live as tokens at the top of styles.css, separately for light and dark mode. The icons are in zethal-icons.php: each entry is the inner markup of a 24 by 24 SVG.
Please do not present your project as MevaSearch or use the MevaSearch name or logo. Attribution is not required, but the short "Built with Zethal Framework" note in the footer is appreciated.
Configuration
All settings are environment variables, read on the server with getenv(). Nothing is required. Keys never reach the browser.
| Variable | What it does |
|---|---|
ZETHAL_SEARCH_URL | Your search endpoint. When set, it replaces Wikipedia and Commons for every tab. |
ZETHAL_SEARCH_KEY | Sent to your endpoint as Authorization: Bearer .... |
ZETHAL_AI_PROVIDER | anthropic (default) or any other value for an OpenAI-compatible API. |
ZETHAL_AI_URL | Full chat completions URL for OpenAI-compatible providers, for example https://api.openai.com/v1/chat/completions. |
ZETHAL_AI_KEY | API key of your AI provider. |
ZETHAL_AI_MODEL | Model name. AI is used only when both the key and the model are set. |
Apache and LiteSpeed
SetEnv ZETHAL_AI_PROVIDER anthropic
SetEnv ZETHAL_AI_KEY your-key
SetEnv ZETHAL_AI_MODEL your-model
Nginx with PHP-FPM
env[ZETHAL_AI_KEY] = your-key
env[ZETHAL_AI_MODEL] = your-model
A few limits are constants at the top of the PHP files: ZETHAL_RATE_LIMIT and ZETHAL_CACHE_TTL in api.php, ZETHAL_AI_RATE_LIMIT and ZETHAL_AI_MAX_TOKENS in ai.php.
Connecting a search provider
Your endpoint receives a GET request with these query parameters:
| Parameter | Values |
|---|---|
q | The query, up to 400 characters. |
type | all, images, videos or news. |
page | 1 to 20. |
count | 10, 20 or 30. |
safe | strict, moderate or off. |
It should answer with status 200 and JSON like this:
{
"total": 1280,
"results": [
{
"title": "Example page",
"url": "https://example.com/page",
"description": "A short snippet of the page.",
"thumbnail": "https://example.com/thumb.jpg"
}
],
"panel": {
"title": "Example",
"subtitle": "Short description",
"text": "A few sentences about the topic.",
"url": "https://example.com/about",
"source": "Example"
}
}
Only title and url are required. Results without an http or https URL are dropped, and thumbnails must use https. If you leave out panel, Zethal looks up a Wikipedia summary for the first result. A small adapter script on your side is usually enough to connect any search API.
If you show thumbnails from your own image hosts, add them to the img-src part of the Content Security Policy in results.php.
AI and photo search
Summaries
The results page sends the query and the top five results to ai.php. With a model configured, it asks for a two to four sentence answer based only on those sources. Without one, it picks the most relevant sentences from the results and labels the card as a summary built without AI.
Search with a photo
The camera button opens a dialog where visitors can drop, paste or choose a JPG, PNG or WebP image. The browser resizes it before upload, the server checks that it is a real image and sends it to a vision model that returns a short search query. The image is not saved anywhere.
Without a model, Zethal tries to build a query from a descriptive file name, such as eiffel-tower-night.jpg, and otherwise explains that photo recognition needs an AI model.
Visitors can turn summaries off on the settings page.
Languages
- Copy
lang/ento a new folder named after the language code, for examplelang/de. - Edit
info.json:{ "name": "Deutsch", "dir": "ltr" } - Translate the strings in
common.php,index.php,results.phpandsettings.php.
The language shows up in settings straight away. Missing keys fall back to English, so you can translate step by step. Use "dir": "rtl" for right to left scripts.
The language is chosen from the visitor's setting first, then from the browser's Accept-Language header. Opening lang.php directly returns the list of installed languages as JSON.
Bangs
A bang at the start or the end of a query sends the visitor straight to another site, for example !w black holes or rust traits !gh. Typing ! opens a list of suggestions that can be picked with the arrow keys and Enter or Tab.
To add or remove bangs, edit the array in bangs.php. %s is replaced with the encoded query.
'osm' => ['name' => 'OpenStreetMap', 'url' => 'https://www.openstreetmap.org/search?query=%s'],
The settings page and the suggestion list update automatically.
Privacy and security
- Settings and shortcuts are stored in the visitor's browser. The only cookie is the chosen language.
- No analytics, fonts or scripts are loaded from third parties.
- Tracking parameters such as
utm_,fbclidandgclidare removed from result links, and visitors can hide whole domains. - Every page sends a strict Content Security Policy,
Referrer-Policy: no-referrerandX-Content-Type-Options: nosniff. - Rate limits use a daily rotating hash of the IP address with a random salt. The address itself is never written to disk.
- Search responses are cached for ten minutes in the system temp folder, keyed by a hash of the request.
- Outgoing requests use HTTPS only, and AI requests never follow redirects.
What leaves your server
Zethal has no telemetry and never contacts MevaSearch. To show results it does send the visitor's query from your server to Wikipedia and Wikimedia Commons, or to your own provider if you set one. The visitor's browser loads image thumbnails directly from upload.wikimedia.org and thumb.wikimedia.org without a referrer. When AI is configured, the query, the top results and uploaded photos go to your AI provider.
Deploying
- Upload all files, including the
langfolder, and serve the site over HTTPS. - Set your environment variables in the server configuration, not in files the web server can serve.
- The results and settings pages send
noindex. Leave the home page indexable if you want it to be found.
Set a contact in the User-Agent. Wikimedia asks every client to identify itself with a way to reach its operator. Before you put a public site online, change ZETHAL_USER_AGENT at the top of api.php:
const ZETHAL_USER_AGENT = 'YourSearch/1.0 (https://your-domain.example; you@your-domain.example)';
License and pricing
Zethal Framework is released under the SA-SDL license. The full text is also in the LICENSE file in the repository and it is the only binding description of what you may do with the code. It is source available, which is not the same as open source in the OSI sense.
You may use Zethal in projects that earn money. If you sell Zethal itself as a standalone product, paid service or subscription and it earns more than 1500 USD a month, the license asks you to submit the project for review. For details, read the commercial license and see the plans on the pricing page.
MevaSearch was built on Zethal, but this public edition does not include the MevaSearch index, ranking, data or services.
Questions or ideas? Open an issue on GitHub.