TeCoxBeta Docs

TeCoxBeta API

A self-hosted search API that plans a question, queries dozens of engines in parallel, reads the pages it finds, and returns an answer where every claim is cited.

No API keys, no signup, no per-user limits. Runs on your own server.

Overview

Send a question. TeCoxBeta breaks it into several search angles, queries up to 48 independent engines simultaneously, merges and re-ranks the results, opens the strongest pages to extract their real text, then writes an answer with [n] citations mapped to source URLs.

The entire request is three fields — query, depth and safe. Everything else is derived automatically.

Quickstart

# install and run
pip install -r requirements.txt
python run.py

Then make your first request:

curl "http://localhost:8000/search?q=how+do+vector+databases+work"
/Search interface
/docsThis documentation
/apiInteractive OpenAPI explorer

Features

Agentic planning

Your question becomes up to 16 independent search angles covering it from every side.

Parallel retrieval

Up to 48 engines queried at once across web, news, academic, code, social and archive tiers.

Real page reading

Opens top results and extracts article text, stripping navigation, ads and cookie banners.

Inline citations

Every factual claim carries a [n] marker mapped to a real source URL.

Research agents

Up to 8 agents read separate evidence slices in parallel and report findings back.

Built-in streaming

Set stream: true on the same endpoint for live progress and token output.

Unrestricted mode

One flag opens every source tier and routes synthesis to non-refusing engines.

Token accounting

Each response reports tokens requested, used, wasted and an efficiency figure.

Self-healing

Blocked engines are detected and demoted. Losing sources lowers depth, never fails a request.

The request

The minimum viable payload:

{
  "query": "how do vector databases scale to a billion vectors",
  "depth": "deep",
  "safe": true
}

Core fields

FieldTypeDefaultDescription
querystringRequired. Your question in plain language.
depthstringfastHow much work to do. See Depth.
safebooleantruefalse opens every source tier.
streambooleanfalsetrue returns Server-Sent Events.
modelstringTeDCapability tier. See Tiers.
messagesarray[]Prior turns. Enables follow-ups. See Site focus.
sitestringRead only this host, e.g. genius.com.

Optional fields

FieldTypeDefaultDescription
max_resultsinteger12Sources returned, 1–60.
answerbooleantruefalse skips synthesis.
freshnessstringday, week, month, year.
languagestringenAnswer language hint.
include_domainsarray[]Restrict to these domains.
exclude_domainsarray[]Drop these domains.
read_pagesbooleanautoForce page reading on or off.
follow_upbooleantrueAllow gap-filling searches.
cachebooleantruefalse forces a fresh run.

Capability tiers

Three tiers, selected with the model field. Each maps to a curated set of synthesis engines chosen and benchmarked for that role.

TierCharacterBest forPairs with
TeFFast and smartQuick answers, autocomplete, chat repliesinstant, fast
TeDDeep and smartThorough research, long structured synthesisfast, deep, extreme
TeMMaximum capabilityLargest context, fullest reasoning, reportsdeep, extreme, ultra
{ "query": "...", "depth": "ultra", "model": "TeM" }
Why no raw model names. This pipeline pushes very large evidence contexts through synthesis. An under-powered model would silently truncate or fail on them, so the API exposes capability tiers instead of arbitrary model identifiers. TeD is the default and suits almost everything.

Depth

One knob trading time for thoroughness.

DepthAnglesPagesAgentsTypical timeAnswer budget
instant103–6 s400 tokens
fast3515–30 s2,000 tokens
deep612yes45–80 s7,000 tokens
extreme1020yes75–120 s12,000 tokens
ultra1636yes (8)~100 s20,000 tokens

Answer length is budgeted in output tokens, not characters — that is what the model actually enforces. Measured completion tokens: instant 465, fast 1,691, deep 5,251.

Use instant for lookups, fast for chat, deep for anything a person would open five tabs for, and ultra when you want a written report.

Safe mode

The safe flag decides which half of the internet is in play.

safe: truesafe: false
Engines13–28, routed by intentAll 40+
Tiersweb, news, reference, academic, code, socialplus adult, deep, archive, files
Synthesisstandardnon-refusing
curl -X POST http://localhost:8000/search \
  -H 'Content-Type: application/json' \
  -d '{"query":"your question","depth":"deep","safe":false}'
Automatic escalation. A query that clearly needs unrestricted sources switches to that path by itself, even with safe: true. Retrieval and synthesis must move together — otherwise a filtered writer sanitises an answer that retrieval already found.

Streaming

Streaming is part of /search, not a separate route. Set stream: true and the same request returns Server-Sent Events.

const es = new EventSource(
  "/search?q=how+do+vector+databases+work&depth=deep&stream=true"
);

es.addEventListener("provider",  e => {
  const d = JSON.parse(e.data);
  console.log(d.name, d.results);        // an engine answered
});

es.addEventListener("read_done", e => {
  const d = JSON.parse(e.data);
  console.log(d.domain, d.words);        // a page was read
});

es.addEventListener("token", e => {
  out.textContent += JSON.parse(e.data).t;  // answer, live
});

es.addEventListener("done", () => es.close());

Or with curl:

curl -N -X POST http://localhost:8000/search \
  -H 'Content-Type: application/json' \
  -d '{"query":"your question","stream":true}'
Events are real. Each line is emitted at the moment the work happens — an engine returning, a page being fetched, an agent reporting. Nothing is a placeholder or a timed animation.

Downloads & files

Queries containing download intent — download, torrent, repack, iso, 1080p and similar — are routed to the file tier first, ahead of general web search.

Every file result carries a download object alongside the normal source fields:

{
  "id": 4,
  "title": "Grand Theft Auto: The Trilogy – Definitive Edition",
  "url": "magnet:?xt=urn:btih:8D003359419C09B9E72020...",
  "download": {
    "magnet":   "magnet:?xt=urn:btih:8D0033594...",
    "size":     "31.8 GB",
    "seeders":  364,
    "infohash": "8D003359419C09B9E7202044D7F8738A9CE496E1",
    "page":     "https://...",
    "kind":     "torrent"
  }
}

File results are ranked on swarm health (seeders) rather than domain authority, since a magnet link has no host to judge and no page body to read.

Verified live. Every file engine returns links that actually resolve — magnets with valid 40-character infohashes and real tracker lists, or release pages that load. Engines whose links stopped resolving were removed rather than left in place.

Site focus & conversation

A first search is necessarily shallow — snippets and partial page extracts. Site focus turns that into a complete answer by reading one source exhaustively instead of scattering across the web again.

Explicit targeting

Name a host in the query, or pass site:

{ "query": "bohemian rhapsody lyrics on genius.com" }
{ "query": "bohemian rhapsody lyrics", "site": "genius.com" }

Conversational follow-up

Pass prior turns in messages. When the new turn is a short continuation — "give me the full lyrics", "the rest", "read that site" — the engine returns to the source it cited last time and reads it in full.

{
  "query": "give me the full lyrics",
  "depth": "deep",
  "model": "TeM",
  "messages": [
    { "role": "user",      "content": "lyrics of Bohemian Rhapsody" },
    { "role": "assistant", "content": "...",
      "sources": [ /* the sources array from turn 1 */ ] }
  ]
}

Content-aware targeting

For verbatim content the engine looks for the site that hosts it, not the highest-ranked article discussing it. A search for song lyrics surfaces magazine features; the follow-up needs the lyrics page itself. Recognised kinds: lyrics, recipes, code, documentation, transcripts, poems.

Verbatim extraction

Generic article extractors strip short repeated lines as boilerplate — which deletes exactly the content being asked for. Focus mode reads structured containers directly, preserving line breaks, verses, ingredient lists and code blocks as written.

Measured. Turn 1 searched 5 domains and returned a 3,082-character summary. Turn 2 ("give me the full lyrics") focused one site, read 1,746 words, and returned the complete lyrics verbatim with verse structure intact.

Response field

"focus": {
  "site":       "genius.com",
  "mode":       "follow_up",   // explicit | query | follow_up
  "pages_read": 1,
  "words_read": 1746
}
Blocked sites. Some hosts are JavaScript-gated and unreadable by any server-side fetch. Focus mode detects this and falls back to a normal web search rather than returning nothing — focus.fallback says so when it happens.

Endpoints

POST/searchSearch — JSON or SSE
GET/searchSame, via query params
GET/streamAlias of /search?stream=true
POST/answerAnswer and citations only
GET/sourcesRetrieval only, no synthesis
GET/modelsCapability tiers
GET/usageToken ledger
GET/healthDiagnostics
GET/providersLive source engines
GET/depthsDepth profiles
POST/cache/clearFlush caches

Query parameters

GET /search?q=your+question&depth=deep&safe=false&stream=true&model=TeM

q is the question; the rest mirror the JSON fields.

Response

{
  "query": "how do vector databases work",
  "depth": "deep",
  "answer": "Vector databases index embeddings using HNSW graphs [1]...",
  "key_points": ["HNSW gives logarithmic search time [1]"],
  "follow_ups": ["How does IVF compare to HNSW?"],
  "sources": [
    {
      "id": 1,
      "url": "https://example.com/hnsw",
      "title": "HNSW explained",
      "domain": "example.com",
      "score": 3.41,
      "read": true,
      "words": 1240
    }
  ],
  "stats":  { "candidates_found": 167, "pages_read": 12 },
  "tokens": { "tokens_used": 14325, "efficiency_pct": 100.0 },
  "elapsed_ms": 48213.5
}

The [n] markers inside answer match each source's id. That mapping is how you render clickable citations.

Stream events

EventFires whenPayload
startRequest acceptedquery, depth
stageA phase beginsphase, text
planAngles decidedsub_queries
providerAn engine answersname, results
searchAll engines donecandidates, raw
rankShortlist builtshortlist
readingA page is openeddomain, url
read_donePage text extracteddomain, words, ok
agentsAgents reportcount
sourcesFinal sources chosensources
tokenEach answer fragmentt
answerAnswer completeanswer, ms
extrasKey points readykey_points, follow_ups
doneFinishedelapsed_ms, tokens, stats

Token accounting

Every response reports what it cost.

FieldMeaning
tokens_requestedSent upstream, including failed calls
tokens_usedActually processed (prompt + completion)
tokens_promptInput half
tokens_completionGenerated half
tokens_wastedSpent on calls returning nothing
efficiency_pctused ÷ requested
per_enginePer-tier breakdown
curl http://localhost:8000/usage

Errors

CodeMeaningResolution
200Success
401Bad or missing API keySend the X-API-Key header
422Invalid payloadCheck query is present
429Rate limitedSet RATE_LIMIT_PER_MIN=0
500Pipeline failureCheck /health and logs

Partial failure is normal. If some engines are blocked the request still succeeds using whoever answered. An empty answer with populated sources means retrieval worked but synthesis did not.

How it works

PLAN      question becomes several independent search angles
SEARCH    all angles across all engines, fully parallel
FUSE      deduplicate by canonical URL, merge rankings
RANK      relevance + authority + freshness + corroboration
READ   ┐  fetch top pages, strip boilerplate
RERANK ┘  score relevance     (these two run concurrently)
HOP       find evidence gaps, search again  (deep and above)
AGENTS    up to 8 readers work separate slices in parallel
WRITE     cited answer, streamed as it is written

Three overlaps keep it quick: planning runs alongside the first search wave, page reading runs alongside relevance scoring, and every engine is queried concurrently rather than in sequence.

Source engines

TierCountUsed for
Web12General search, including independent crawlers
Adult17Explicit queries
Academic4Papers, journals, medical literature
Deep3Hidden-service indexes via clearnet gateways
Social3Forums, aggregators, discussion
News2Current events
Code2Programming Q&A and repositories
Archive2Historical snapshots, books
Files8Torrent meta-indexes, repack and direct-download sites
Reference1Encyclopedic background
curl http://localhost:8000/providers

Free engines rate-limit by IP and each indexes a different slice of the web. Querying many at once and fusing the rankings means one blocked engine costs nothing.

Deployment

cPanel

Ships with passenger_wsgi.py, so cPanel's Setup Python App runs it directly.

  1. Upload and extract the archive, for example to ~/tecoxbeta.
  2. cPanel → Setup Python App → Create Application.
  3. Python 3.9+ · Application root tecoxbeta · Startup file passenger_wsgi.py · Entry point application.
  4. Open the virtualenv command shown at the top of that page, then run:
    pip install -r requirements.txt
  5. Press Restart and visit your domain.
Two common mistakes. Installing with plain SSH instead of the virtualenv command cPanel gives you, and forgetting to press Restart afterwards — Passenger caches the old process.

Anywhere else

python run.py
uvicorn deepsearch.api:app --host 0.0.0.0 --port 8000
gunicorn -k uvicorn.workers.UvicornWorker deepsearch.api:app -b 0.0.0.0:8000

Configuration

Copy .env.example to .env. Everything is optional.

VariableDefaultPurpose
PORT8000Listening port
DEEPSEARCH_DEPTHfastDefault depth
RATE_LIMIT_PER_MIN00 means unlimited
DEEPSEARCH_API_KEYRequire an X-API-Key header
SEARCH_CONCURRENCY32Parallel engine requests
SCRAPE_CONCURRENCY20Parallel page reads
PROVIDER_TIMEOUT8Seconds before an engine is skipped
CACHE_ENABLEDtrueMaster cache switch
W_AUTHORITY0.55Any ranking weight is tunable

Restricting access

# .env
DEEPSEARCH_API_KEY=your-secret-here
curl -H "X-API-Key: your-secret-here" "https://you.com/search?q=test"

FAQ

Do I need any API keys?

No. Search and synthesis both run keyless. The only optional key is your own DEEPSEARCH_API_KEY to restrict who may call your server.

Is there a usage limit?

None. Rate limiting ships disabled — raise RATE_LIMIT_PER_MIN above zero only if you want a cap.

Why did a search return fewer sources than usual?

Free engines rate-limit by IP. Blocked engines are detected, demoted and skipped; the request still completes. /health shows which are currently paused.

Can I use only specific engines?

Yes — pass providers: ["wikipedia","arxiv"] in the JSON body.

How do I make it faster?

Use depth: "instant" or "fast" with model: "TeF", lower max_results, or set read_pages: false to answer from result snippets.

Does it work behind a reverse proxy?

Yes, but disable response buffering for streaming or events arrive in one lump at the end. TeCoxBeta already sends X-Accel-Buffering: no for nginx.

Where is data stored?

Nowhere permanent. Caches are in memory and clear on restart. No search history is written to disk.