Vectorless
Self-hosting

Self-hosting

Run the Vectorless engine yourself with one docker compose command. Same ingest, retrieval, answers and line-level pincites as the hosted service, as an HTTP API with your own model keys.

Updated 2026

The engine's selfhost/ folder runs the server the hosted service ran, with Postgres beside it. You get the same pipeline: the contents found and placed by Jev, judgewalk retrieval, answers, line-level pincites, page images and live ingest progress. It is an HTTP API protected by one bearer token. You call it with curl, the SDKs or the MCP server. There is no web dashboard: the hosted dashboard and control plane are not part of the open source release. Nothing else to provision: no vector database, no object store, no queue service.

The compose file and its full reference live in the selfhost/ folder of the engine.

Quickstart

Get the engine

git clone https://github.com/hallelx2/vectorless-engine.git
cd vectorless-engine/selfhost
cp .env.example .env

Set a token and your model keys

In .env, set VECTORLESS_API_KEY to a long random string (for example openssl rand -hex 32), one answer-model key, and VECTORLESS_TYPESAFE_API_KEY for Jev. Compose refuses to start without the token.

VECTORLESS_API_KEY=<openssl rand -hex 32>
VECTORLESS_LLM_PROVIDER=anthropic
VECTORLESS_ANTHROPIC_API_KEY=<your key>
VECTORLESS_TYPESAFE_API_KEY=<your TypeSafe key>

Start it

docker compose up -d
docker compose ps        # the engine is ready when it reports (healthy)

The API listens on http://localhost:8080, bound to this machine only.

Ingest a document and ask it something

K=<your VECTORLESS_API_KEY>
curl -s -H "Authorization: Bearer $K" -F file=@report.pdf http://localhost:8080/v1/documents
# {"document_id":"doc_…","status":"pending"}

curl -s -H "Authorization: Bearer $K" http://localhost:8080/v1/documents/doc_…
# poll until "status":"ready"; "progress" lists each ingest stage

curl -s -H "Authorization: Bearer $K" -H 'Content-Type: application/json' \
  -d '{"document_id":"doc_…","query":"What was capital expenditure in 2018?"}' \
  http://localhost:8080/v1/answer

On 13 October 2026 this setup ran the 3M 2018 10-K (160 pages) with GLM-4.5-Air writing answers. The filing was ready 10 seconds after upload. The capital expenditure question was answered in 6.1 seconds, with pincites at line precision on the cash-flow statement and the segment table.

What runs

ServiceImageRole
engineghcr.io/hallelx2/vectorless-engineIngest, retrieval, answers, pincites, page images. The job queue runs inside Postgres.
postgrespostgres:16-alpineDocuments, structure, layout and the job queue. Not published to the host.

Uploaded files live in the documents volume and everything else in pgdata.

Reading the answer

POST /v1/answer returns the answer with [n] markers, the evidence pages, and a pincites list. Each pincite has a page, a precision (line or page), the quote taken word for word from the page, and regions: rectangles in 0–1 page coordinates. To show a citation, draw its regions over GET /v1/documents/{id}/pages/{n}/image. GET /v1/documents/{id}/pages gives each page's size.

The engine is single-tenant here. Behind a control plane, each request names its tenant in X-Vectorless-Org. The self-host config sets auth.default_org instead, so requests need only the bearer token.

Model keys

VariableWhat it does
VECTORLESS_LLM_PROVIDERanthropic, openai or gemini: the model that writes answers.
VECTORLESS_ANTHROPIC_API_KEY, _BASE_URL, _MODELAnthropic, or an Anthropic-compatible gateway. For GLM on z.ai the base URL is https://api.z.ai/api/anthropic/v1, /v1 included.
VECTORLESS_OPENAI_API_KEY, _BASE_URL, _MODELOpenAI, or any OpenAI-compatible endpoint.
VECTORLESS_GEMINI_API_KEY, _MODELGemini.
VECTORLESS_ANSWER_MODELOptional: a different model for answers only.

Callers can also send their own answer-model key per request with X-LLM-Api-Key (plus optional X-LLM-Provider, X-LLM-Base-Url and X-LLM-Model). Nothing about it is logged or stored.

Use a non-reasoning model for answers

The answer budget is 1,200 tokens. A reasoning model such as GLM-4.6 can spend it all thinking and return no text. The engine then fails the request with "the answer model returned no text", and the server log says why. GLM-4.5-Air answered the 3M question in about 3 seconds. GLM-4.6 took 37 seconds and returned nothing.

Every variable has a VECTORLESS_ prefix on purpose. Docker Compose lets the shell override .env, and a shell set up for another tool often exports ANTHROPIC_BASE_URL or OPENAI_API_KEY, which would otherwise win silently.

The structure model

Line-level citations need it

TypeSafe's Jev is a System One model: it makes fast, structured decisions and writes no prose. It finds the contents page, places every section on its pages, ranks sections and pages for a question, and picks the exact line each citation points to. Get a key from typesafe.ai. It is a hosted API, so page text is sent to TypeSafe when the key is set.

With a TypeSafe keyWithout
IngestA few batched calls to read structureOne generative call per page: minutes slower on long filings
RetrievalRanks sections and pages in one or two callsYour generative model walks the pages, up to eight hops
CitationsLine-level, quotes chosen by JevQuotes chosen by word overlap

If TypeSafe refuses a request (no credit, a revoked key, an outage), the engine takes the generative path for that request instead of failing it.

Configuration

VariableDefault
VECTORLESS_PORT8080Host port.
VECTORLESS_BIND127.0.0.10.0.0.0 serves beyond this machine. Put TLS in front.
VECTORLESS_VERSIONlatestOr a 12-character commit tag, to pin one build.
VECTORLESS_POSTGRES_PASSWORDvectorlessPostgres is not published to the host.
VECTORLESS_LOG_LEVELinfodebug logs each navigation step.

Everything else is in selfhost/engine.yaml; the engine's config.server.example.yaml documents every key.

TLS with Caddy

Keep the engine on loopback and let Caddy terminate TLS:

vectorless.example.com {
	encode zstd gzip
	request_body {
		max_size 64MB
	}
	reverse_proxy 127.0.0.1:8080 {
		flush_interval -1
		transport http {
			read_timeout 10m
			write_timeout 10m
		}
	}
}

flush_interval -1 keeps streamed answers (/v1/query/stream, "stream": true on /v1/answer) flowing as they are written.

Backups

docker compose stop engine
docker compose exec postgres pg_dump -U vectorless -Fc engine > engine.dump
docker run --rm -v "$(basename "$PWD")_documents:/data" -v "$PWD:/out" alpine tar czf /out/documents.tgz -C /data .
docker compose start engine

Upgrading

docker compose pull
docker compose up -d

Migrations run when the server starts.

Building from source

git clone https://github.com/hallelx2/vectorless-engine.git
cd vectorless-engine
docker build -f Dockerfile.server -t vectorless-engine:local .
cd selfhost
VECTORLESS_IMAGE=vectorless-engine VECTORLESS_VERSION=local docker compose up -d

On this page