Deployment
Self-hosting
For a lot of the companies this is built for, “the context layer holds a condensed copy of our systems of record” is a sentence that ends the conversation unless it runs on their own hardware. So it does, with no plan limits and no feature gating.
Run it
git clone https://github.com/maxbeech/contextely cd contextely export OPENROUTER_API_KEY=sk-or-... export CONTEXTELY_SELF_HOSTED=1 export CONTEXTELY_ENCRYPTION_KEY=$(openssl rand -base64 32) docker compose up --build # http://localhost:3000
Compose brings up Postgres 17 alongside the app. Apply the schema once with npm run db:push pointed at that database.
Point the tools at it
Nothing in the client surface is pinned to our hosted deployment. An MCP client takes the URL in its config, the REST API is wherever you put it, and the CLI is told once and stays told.
# Your deployment serves its own copy of the CLI. curl -fsSL https://contextely.internal/cli.mjs -o contextely && chmod +x contextely ./contextely config set-url https://contextely.internal ./contextely config set-key ctx_sk_... ./contextely search "acme renewal" # or per call, or from the environment CONTEXTELY_URL=https://contextely.internal ./contextely usage
What you must supply
DATABASE_URL
Any Postgres 14+. Compose provides one; point it at your own if you prefer. Server-side only, so there is no browser-reachable database.
OPENROUTER_API_KEY
Condensation is the one genuine LLM dependency and it has no fallback: without a key, ingest and refresh fail loudly rather than writing a memory object some heuristic invented. Set OPENROUTER_MODEL to route it wherever you like.
CONTEXTELY_SELF_HOSTED
Set it to 1. This is what removes the plan limits, and it is read explicitly rather than guessed from absent Stripe keys, because a flag that decides whether limits apply at all should never be inferred. Without it every workspace on your own hardware resolves to the Free plan: one source, three members, five hundred retrievals a month. One number stays finite, deliberately: 50,000 memory objects, which bounds the candidate set a retrieval scans rather than licensing anything. It is a scan bound, and an unbounded value there would read your whole store into memory on every query.
CONTEXTELY_ENCRYPTION_KEY
A source's connection string or bearer token has to be replayed on every refresh, so it is encrypted rather than hashed, and this is the key. Generate one with openssl rand -base64 32. Keep it somewhere other than wherever your database backups go, because storing both together is the same as storing neither. If you lose it, every stored source configuration becomes unreadable and has to be entered again, which is exactly what makes the encryption worth anything. Rotate by moving the old value to CONTEXTELY_ENCRYPTION_KEY_PREVIOUS, deploying, then running scripts/encrypt-existing-secrets.mjs --rewrap.
What is optional, and what you lose without it
NEON_AUTH_BASE_URL, NEON_AUTH_COOKIE_SECRET
The hosted dashboard signs people in with Neon's Managed Better Auth. Self-hosting against your own Postgres leaves these unset, and the dashboard then reports itself unconfigured and fails every session check closed, so it will not let anyone in rather than letting everyone in. The REST API and the MCP server authenticate with API keys and are entirely unaffected, which for an agent-facing deployment is usually all you need. Point these at a Neon project if you want the dashboard as well.
SENTRY_DSN
Unset means no error reporting leaves your network. Nothing else changes.
STRIPE_*
Irrelevant when self-hosting. Billing is disabled and there are no plan limits, because the quota checks read the plan config, and a self-hosted deployment is not on a metered plan.
What leaves your network
Exactly one thing: the content of a record being condensed, sent to whichever model you route OPENROUTER_MODEL at. Retrieval, scoring, entitlement and the freshness bookkeeping are all local and involve no outbound call at all. Re-fetches go to your own systems of record.
There is no telemetry, no licence check and no phone-home. If the machine has no internet access beyond your model endpoint, Contextely still works.
Your own use, and everyone else's
Self-hosting is free for your own company, with no limits and no licence check. That covers running Contextely for your own staff, your own agents and your own internal tools, including a deployment you operate for a subsidiary you own. It stops at resale. If you are putting Contextely inside a product you sell, running it on behalf of your clients, or presenting it to anyone under another name, that is a partner arrangement rather than internal use, and it needs a signed agreement.
Nothing in this codebase checks. The licence is a promise rather than a lock, and we would rather it stayed that way. The practical reason to take the agreement is that it is also how you get the provisioning API, pooled billing across your clients and somebody to call: see the white-label page, or email hello@contextely.com.