File: README.md
🎁 New
- Meet 🌶️ Pipali - our open-source AI coworker that runs on your computer.
- Read about Khoj's excellent performance on modern retrieval and reasoning benchmarks.
Overview
Khoj is a personal AI app to extend your capabilities. It smoothly scales up from an on-device personal AI to a cloud-scale enterprise AI.
- Chat with any local or online LLM (e.g llama3, qwen, gemma, mistral, gpt, claude, gemini, deepseek).
- Get answers from the internet and your docs (including image, pdf, markdown, org-mode, word, notion files).
- Access it from your Browser, Obsidian, Emacs, Desktop, Phone or Whatsapp.
- Create agents with custom knowledge, persona, chat model and tools to take on any role.
- Automate away repetitive research. Get personal newsletters and smart notifications delivered to your inbox.
- Find relevant docs quickly and easily using our advanced semantic search.
- Generate images, talk out loud, play your messages.
- Khoj is open-source, self-hostable. Always.
- Run it privately on your computer or try it on our cloud app.
See it in action
Go to https://app.khoj.dev to see Khoj live.
Full feature list
You can see the full feature list here.
Self-Host
To get started with self-hosting Khoj, read the docs.
Enterprise
Khoj is available as a cloud service, on-premises, or as a hybrid solution. To learn more about Khoj Enterprise, visit our website.
Frequently Asked Questions (FAQ)
Q: Can I use Khoj without self-hosting?
Yes! You can use Khoj right away at https://app.khoj.dev — no setup required.
Q: What kinds of documents can Khoj read?
Khoj supports a wide variety: PDFs, Markdown, Notion, Word docs, org-mode files, and more.
Q: How can I make my own agent?
Check out this blog post for a step-by-step guide to custom agents.
For more questions, head over to our Discord!
Contributors
Cheers to our awesome contributors! 🎉
Made with contrib.rocks.
Interested in Contributing?
Khoj is open source. It is sustained by the community and we’d love for you to join it! Whether you’re a coder, designer, writer, or enthusiast, there’s a place for you.
Why Contribute?
- Make an Impact: Help build, test and improve a tool used by thousands to boost productivity.
- Learn & Grow: Work on cutting-edge AI, LLMs, and semantic search technologies.
You can help us build new features, improve the project documentation, report issues and fix bugs. If you're a developer, please see our Contributing Guidelines and check out good first issues to work on.
File: docker-compose.yml
services:
database:
image: docker.io/pgvector/pgvector:pg15
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
volumes:
- khoj_db:/var/lib/postgresql/data/
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 30s
timeout: 10s
retries: 5
sandbox:
image: ghcr.io/khoj-ai/terrarium:latest
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 2
search:
image: docker.io/searxng/searxng:latest
volumes:
- khoj_search:/etc/searxng
environment:
- SEARXNG_BASE_URL=http://localhost:8080/
Creates Computer for Khoj to use.
Set KHOJ_OPERATOR_ENABLED=True in the server service environment variable to enable.
computer:
container_name: khoj-computer
image: ghcr.io/khoj-ai/khoj-computer:latest
# build:
# context: .
# dockerfile: computer.Dockerfile
ports:
- "5900:5900"
volumes:
- khoj_computer:/home/operator
server:
depends_on:
database:
condition: service_healthy
# Use the following line to use the latest version of khoj. Otherwise, it will build from source. Set this to ghcr.io/khoj-ai/khoj-cloud:latest if you want to use the prod image.
image: ghcr.io/khoj-ai/khoj:latest
# Uncomment the following line to build from source. This will take a few minutes. Comment the next two lines out if you want to use the official image.
# build:
# context: .
ports:
# If changing the local port (left hand side), no other changes required.
# If changing the remote port (right hand side),
# change the port in the args in the build section,
# as well as the port in the command section to match
- "42110:42110"
extra_hosts:
- "host.docker.internal:host-gateway"
working_dir: /app
volumes:
- khoj_config:/root/.khoj/
- khoj_models:/root/.cache/torch/sentence_transformers
- khoj_models:/root/.cache/huggingface
# uncomment line below to mount docker socket to allow khoj to use its computer.
# - /var/run/docker.sock:/var/run/docker.sock
# Use 0.0.0.0 to explicitly set the host ip for the service on the container. https://pythonspeed.com/articles/docker-connection-refused/
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_HOST=database
- POSTGRES_PORT=5432
- KHOJ_DJANGO_SECRET_KEY=secret
- KHOJ_DEBUG=False
- KHOJ_ADMIN_EMAIL=[email protected]
- KHOJ_ADMIN_PASSWORD=password
# Default URL of Terrarium, the default Python sandbox used by Khoj to run code. Its container is specified above
- KHOJ_TERRARIUM_URL=http://sandbox:8080
# Uncomment line below to have Khoj run code in remote E2B code sandbox instead of the self-hosted Terrarium sandbox above. Get your E2B API key from https://e2b.dev/.
# - E2B_API_KEY=your_e2b_api_key
# Default URL of SearxNG, the default web search engine used by Khoj. Its container is specified above
- KHOJ_SEARXNG_URL=http://search:8080
# Uncomment line below to use with Ollama running on your local machine at localhost:11434.
# Change URL to use with other OpenAI API compatible providers like VLLM, LMStudio, DeepInfra, DeepSeek etc.
# - OPENAI_BASE_URL=http://host.docker.internal:11434/v1/
# - KHOJ_DEFAULT_CHAT_MODEL=qwen3
#
# Uncomment appropriate lines below to use chat models by OpenAI, Anthropic, Google.
# Ensure you set your provider specific API keys.
# ---
# - OPENAI_API_KEY=your_openai_api_key
# - GEMINI_API_KEY=your_gemini_api_key
# - ANTHROPIC_API_KEY=your_anthropic_api_key
#
# Uncomment line below to enable Khoj to use its computer.
# - KHOJ_OPERATOR_ENABLED=True
# Uncomment appropriate lines below to enable web results with Khoj
# Ensure you set your provider specific API keys.
# ---
# Paid, Fast API. Only does web search. Get API key from https://serper.dev/
# - SERPER_DEV_API_KEY=your_serper_dev_api_key
# Paid, Higher Read Success API. Only does webpage read. Get API key from https://olostep.com/
# - OLOSTEP_API_KEY=your_olostep_api_key
# Paid, Open API. Does both web search and webpage read. Get API key from https://firecrawl.dev/
# - FIRECRAWL_API_KEY=your_firecrawl_api_key
# Paid, Fast API. Does both web search and webpage read. Get API key from https://exa.ai/
# - EXA_API_KEY=your_exa_api_key
#
# Uncomment the necessary lines below to make your instance publicly accessible.
# Proceed with caution, especially if you are using anonymous mode.
# ---
# - KHOJ_NO_HTTPS=True
# Replace the KHOJ_DOMAIN with the server's externally accessible domain or I.P address from a remote machie (no http/https prefix).
# Ensure this is set correctly to avoid CSRF trusted origin or unset cookie issue when trying to access the admin panel.
# - KHOJ_DOMAIN=192.168.0.104
# - KHOJ_DOMAIN=khoj.example.com
# Replace the KHOJ_ALLOWED_DOMAIN with the server's internally accessible domain or I.P address on the host machine (no http/https prefix).
# Only set if using a load balancer/reverse_proxy in front of your Khoj server. If unset, it defaults to KHOJ_DOMAIN.
# For example, if the load balancer service is added to the khoj docker network, set KHOJ_ALLOWED_DOMAIN to khoj's docker service name: `server'.
# - KHOJ_ALLOWED_DOMAIN=server
# - KHOJ_ALLOWED_DOMAIN=127.0.0.1
# Uncomment the line below to disable telemetry.
# Telemetry helps us prioritize feature development and understand how people are using Khoj
# Read more at https://docs.khoj.dev/miscellaneous/telemetry
# - KHOJ_TELEMETRY_DISABLE=True
# Comment out this line when you're using the official ghcr.io/khoj-ai/khoj-cloud:latest prod image.
command: --host="0.0.0.0" --port=42110 -vv --anonymous-mode --non-interactive
volumes:
khoj_config:
khoj_db:
khoj_models:
khoj_search:
khoj_computer:
File: manifest.json
{
"id": "khoj",
"name": "Khoj",
"version": "2.0.0-beta.28",
"minAppVersion": "0.15.0",
"description": "Your Second Brain",
"author": "Khoj Inc.",
"authorUrl": "https://github.com/khoj-ai",
"isDesktopOnly": false
}
File: versions.json
{
"0.2.1": "0.15.0",
"0.2.5": "0.15.0",
"0.2.6": "0.15.0",
"0.3.0": "0.15.0",
"0.4.0": "0.15.0",
"0.5.0": "0.15.0",
"0.6.0": "0.15.0",
"0.6.1": "0.15.0",
"0.6.2": "0.15.0",
"0.7.0": "0.15.0",
"0.7.1": "0.15.0",
"0.8.0": "0.15.0",
"0.8.1": "0.15.0",
"0.8.2": "0.15.0",
"0.9.0": "0.15.0",
"0.10.0": "0.15.0",
"0.10.1": "0.15.0",
"0.11.0": "0.15.0",
"0.11.1": "0.15.0",
"0.11.2": "0.15.0",
"0.11.3": "0.15.0",
"0.11.4": "0.15.0",
"0.12.0": "0.15.0",
"0.12.1": "0.15.0",
"0.12.2": "0.15.0",
"0.12.3": "0.15.0",
"0.13.0": "0.15.0",
"0.14.0": "0.15.0",
"1.0.0": "0.15.0",
"1.0.1": "0.15.0",
"1.1.0": "0.15.0",
"1.2.0": "0.15.0",
"1.2.1": "0.15.0",
"1.3.0": "0.15.0",
"1.4.0": "0.15.0",
"1.5.0": "0.15.0",
"1.5.1": "0.15.0",
"1.6.0": "0.15.0",
"1.6.1": "0.15.0",
"1.6.2": "0.15.0",
"1.7.0": "0.15.0",
"1.8.0": "0.15.0",
"1.9.0": "0.15.0",
"1.10.0": "0.15.0",
"1.10.1": "0.15.0",
"1.10.2": "0.15.0",
"1.11.0": "0.15.0",
"1.11.1": "0.15.0",
"1.11.2": "0.15.0",
"1.12.0": "0.15.0",
"1.12.1": "0.15.0",
"1.13.0": "0.15.0",
"1.14.0": "0.15.0",
"1.15.0": "0.15.0",
"1.16.0": "0.15.0",
"1.17.0": "0.15.0",
"1.20.0": "0.15.0",
"1.20.1": "0.15.0",
"1.20.2": "0.15.0",
"1.20.3": "0.15.0",
"1.20.4": "0.15.0",
"1.21.0": "0.15.0",
"1.21.1": "0.15.0",
"1.21.2": "0.15.0",
"1.21.3": "0.15.0",
"1.21.4": "0.15.0",
"1.21.5": "0.15.0",
"1.21.6": "0.15.0",
"1.22.0": "0.15.0",
"1.22.1": "0.15.0",
"1.22.2": "0.15.0",
"1.22.3": "0.15.0",
"1.23.0": "0.15.0",
"1.23.1": "0.15.0",
"1.23.2": "0.15.0",
"1.23.3": "0.15.0",
"1.24.0": "0.15.0",
"1.24.1": "0.15.0",
"1.25.0": "0.15.0",
"1.26.0": "0.15.0",
"1.26.1": "0.15.0",
"1.26.2": "0.15.0",
"1.26.3": "0.15.0",
"1.26.4": "0.15.0",
"1.27.0": "0.15.0",
"1.27.1": "0.15.0",
"1.28.0": "0.15.0",
"1.28.1": "0.15.0",
"1.28.2": "0.15.0",
"1.28.3": "0.15.0",
"1.29.0": "0.15.0",
"1.29.1": "0.15.0",
"1.30.0": "0.15.0",
"1.30.1": "0.15.0",
"1.30.2": "0.15.0",
"1.30.3": "0.15.0",
"1.30.4": "0.15.0",
"1.30.5": "0.15.0",
"1.30.6": "0.15.0",
"1.30.7": "0.15.0",
"1.30.8": "0.15.0",
"1.30.9": "0.15.0",
"1.30.10": "0.15.0",
"1.31.0": "0.15.0",
"1.32.0": "0.15.0",
"1.32.1": "0.15.0",
"1.32.2": "0.15.0",
"1.33.0": "0.15.0",
"1.33.1": "0.15.0",
"1.33.2": "0.15.0",
"1.34.0": "0.15.0",
"1.35.0": "0.15.0",
"1.35.1": "0.15.0",
"1.35.2": "0.15.0",
"1.35.3": "0.15.0",
"1.36.0": "0.15.0",
"1.36.1": "0.15.0",
"1.36.2": "0.15.0",
"1.36.3": "0.15.0",
"1.36.4": "0.15.0",
"1.36.5": "0.15.0",
"1.36.6": "0.15.0",
"1.37.0": "0.15.0",
"1.37.1": "0.15.0",
"1.37.2": "0.15.0",
"1.38.0": "0.15.0",
"1.39.0": "0.15.0",
"1.40.0": "0.15.0",
"1.41.0": "0.15.0",
"1.42.0": "0.15.0",
"1.42.1": "0.15.0",
"1.42.2": "0.15.0",
"1.42.3": "0.15.0",
"1.42.4": "0.15.0",
"1.42.5": "0.15.0",
"1.42.6": "0.15.0",
"1.42.7": "0.15.0",
"1.42.8": "0.15.0",
"2.0.0-beta.1": "0.15.0",
"2.0.0-beta.2": "0.15.0",
"2.0.0-beta.3": "0.15.0",
"2.0.0-beta.4": "0.15.0",
"2.0.0-beta.5": "0.15.0",
"2.0.0-beta.6": "0.15.0",
"2.0.0-beta.7": "0.15.0",
"2.0.0-beta.8": "0.15.0",
"2.0.0-beta.9": "0.15.0",
"2.0.0-beta.10": "0.15.0",
"2.0.0-beta.11": "0.15.0",
"2.0.0-beta.12": "0.15.0",
"2.0.0-beta.13": "0.15.0",
"2.0.0-beta.14": "0.15.0",
"2.0.0-beta.15": "0.15.0",
"2.0.0-beta.16": "0.15.0",
"2.0.0-beta.17": "0.15.0",
"2.0.0-beta.18": "0.15.0",
"2.0.0-beta.19": "0.15.0",
"2.0.0-beta.20": "0.15.0",
"2.0.0-beta.21": "0.15.0",
"2.0.0-beta.22": "0.15.0",
"2.0.0-beta.23": "0.15.0",
"2.0.0-beta.24": "0.15.0",
"2.0.0-beta.25": "0.15.0",
"2.0.0-beta.26": "0.15.0",
"2.0.0-beta.27": "0.15.0",
"2.0.0-beta.28": "0.15.0"
}
File: .pre-commit-config.yaml
repos:
repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.3
hooks:- id: ruff-check
args: [ --fix ]
files: .py$ - id: ruff-format
files: .py$
- id: ruff-check
repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:- id: end-of-file-fixer
- id: trailing-whitespace
Exclude elisp files to not clear page breaks
exclude: .el$ - id: check-json
exclude: (devcontainer.json|launch.json|settings.json)$ - id: check-toml
- id: check-yaml
repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.0.0
hooks:- id: mypy
stages: [pre-push, manual]
pass_filenames: false
args:- --config-file=pyproject.toml
- id: mypy
File: documentation/README.md
Website
This website is built using Docusaurus, a modern static website generator.
Installation
$ yarnLocal Development
$ yarn startThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
Build
$ yarn buildThis command generates static content into the build directory and can be served using any static contents hosting service.
Deployment
Using SSH:
$ USE_SSH=true yarn deployNot using SSH:
$ GIT_USER=<Your GitHub username> yarn deployIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the gh-pages branch.
File: documentation/package.json
{
"name": "documentation",
"version": "0.0.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "^3.9.2",
"@docusaurus/plugin-sitemap": "^3.9.2",
"@docusaurus/preset-classic": "^3.9.2",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"webpack-dev-server": "^5.2.4"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.9.2",
"@docusaurus/types": "^3.9.2"
},
"browserslist": {
"production": [
">0.5%",
"not dead",
"not op_mini all"
],
"development": [
"last 3 chrome version",
"last 3 firefox version",
"last 5 safari version"
]
},
"engines": {
"node": ">=18.0"
},
"resolutions": {
"picomatch": ">=2.3.2",
"serialize-javascript": "^7.0.5",
"webpack-dev-server": "^5.2.4"
}
}
File: documentation/docs/advanced/_category_.json
{
"label": "Advanced Self Hosting",
"position": 6,
"link": {
"type": "generated-index",
"description": "Advanced setup for Self Hosting Khoj server"
}
}
File: documentation/docs/advanced/admin.md
Admin Panel
Describes the Khoj settings configurable via the admin panel
By default, your admin panel is available at http://localhost:42110/server/admin/. You can access the admin panel by logging in with your admin credentials (this would be your KHOJ_ADMIN_EMAIL and KHOJ_ADMIN_PASSWORD). The admin panel allows you to configure various settings for your Khoj server.
App Settings
Agents
Add all the agents you want to use for your different use-cases like Writer, Researcher, Therapist etc.
Personality: This is a prompt to tell the chat model how to tune the personality of the agent.Chat model: The chat model to use for the agent.Name: The name of the agent. This field helps give the agent a unique identity across the app.Avatar: Url to the agents profile picture. It helps give the agent a unique visual identity across the app.Style color,Style icon: These fields help give the agent a unique, visually identifiable identity across the app.Slug: This is the agent name to use in urls.Public: Check this if the agent is expected to be visible to all users on this Khoj server.Managed by admin: Check this if the agent is managed by admin, not by any user.Creator: The user who created the agent.Tools: The list of tools available to this agent. Tools include notes, image, online. This field is not currently configurable and only supports all tools (i.e["*"])
Chat Model Options
Add all the chat models you want to try, use and switch between for your different use-cases. For each chat model you add:
Chat model: The name of an OpenAI, Anthropic, Gemini or Offline chat model.Model type: The chat model provider likeOpenAI,Google.Vision enabled: Set totrueif your model supports vision. This is currently only supported for vision capable OpenAI models likegpt-4oMax prompt size,Subscribed max prompt size: These are optional fields. They are used to truncate the context to the maximum context size that can be passed to the model. This can help with accuracy and cost-saving.Tokenizer: This is an optional field. It is used to accurately count tokens and truncate context passed to the chat model to stay within the models max prompt size.
Server Chat Settings
The server chat settings are used as:
- The default chat models for subscribed (
Advancedfield) and unsubscribed (Defaultfield) users. - The chat model for all intermediate steps like intent detection, web search etc. during chat response generation.
If a server chat setting is not added the first ChatModelOption in your config is used as the default chat model.
To add a server chat setting:
- Set your preferred default chat models in the
Defaultfields of your ServerChatSettings - The
Advancedfield doesn't need to be set when self-hosting. When unset, theDefaultchat model is used for all users and the intermediate steps.
AI Model API
These settings configure APIs to interact with AI models.
For each AI Model API you add:
Api key: Set to your OpenAI, Anthropic or Gemini API keys.Name: Give the configuration any friendly name likeOpenAI,Gemini,Anthropic.Api base url: Set the API base URL. This is only relevant to set if you're using another OpenAI-compatible proxy server like Ollama or LMStudio.
Search Model Configs
Search models are used to generate vector embeddings of your documents for natural language search and chat. You can choose any embeddings models on HuggingFace to create vector embeddings of your documents for natural language search and chat.
Text to Image Model Options
Add text to image generation models with these settings. Khoj currently supports text to image models available via OpenAI, Google or Replicate API
api-key: Set to your OpenAI, Google AI or Replicate API keymodel: Set the model name available over the selected model providermodel-type: Set to the appropriate model provideropenai-config: For image generation models available via OpenAI (compatible) API you can set the appropriate OpenAI Processor Conversation Settings instead of specifying theapi-keyfield above
Speech to Text Model Options
Add speech to text models with these settings. Khoj currently only supports whisper speech to text model via OpenAI API or Offline
Voice Model Options
Add text to speech models with these settings. Khoj currently supports models from ElevenLabs.
Reflective Questions
This is a static list of starter question suggestions for each user. It is not currently used in any client app. It used to be shown on the web app home page. We may turn it into a dynamic list of starter questions personalized to each users, say based on their recent conversations or synced knowledge base.
User Data
- Users, Entrys, Conversations, Subscriptions, Github configs, Notion configs, User search configs, User conversation configs, User voice configs
Miscellaneous Data
Process Locks: Persistent Locks for Automations
Client Applications:
Client applications allow you to setup third party applications that can query your Khoj server using a client application ID + secret. The secret would go in a bearer token.
File: documentation/docs/advanced/authentication.mdx
Authenticate (Multi-User Setup)
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';By default, most of the instructions for self-hosting Khoj assume a single user, and so the default configuration is to run in anonymous mode. However, if you want to enable authentication, you can do so either with with Magic Links or Google OAuth as shown below. This can be helpful to make Khoj securely accessible to you and your team.
:::tip[Note]
Remove the --anonymous-mode flag from your khoj start up command or docker-compose file to enable authentication.
:::
Using Magic Links
The most secure way to do this is to integrate with Resend.
- Setup your account at https://resend.com
- Set an environment variable for
RESEND_API_KEY. You can get your API key here. - Set an environment variable for
RESEND_EMAIL. This is the email address that will show up in yourfromfield when sending magic links.
This will allow you to automatically send sign-in links to users who want to log in.
It's still possible to use the magic links feature without Resend, but you'll need to manually send the magic links to users who want to log in.
Manually sending magic links
The user will have to enter their email address in the login popup shown at http://localhost:42110/?v=app.
They'll click
Get Login Link. Without the Resend API key, this will just create an unverified account for them in the backendYou can get their magic link using the admin panel
Go to the admin panel. You'll see a list of users. Search for the user you want to send a magic link to. Tick the checkbox next to their row, and use the action drop down at the top to 'Get email login URL'. This will generate a magic link that you can send to the user, which will appear at the top of the admin interface.
Get email login URL Retrieved login URL Send the magic link to the user. They can click on it to log in.
Once they click on the link, they'll automatically be logged in. They'll have to repeat this process for every new device they want to log in from, but they shouldn't have to repeat it on the same device.
A given magic link can only be used once. If the user tries to use it again, they'll be redirected to the login page to get a new magic link.
Using Google OAuth
For this method, you'll need to use the prod version of the Khoj package. You can install it as below:
To set up your self-hosted Khoj with Google Auth, you need to create a project in the Google Cloud Console and enable the Google Auth API.
To implement this, you'll need to:
Create authorization credentials for your application.
Open your Google cloud console and create a configuration like below for the relevant
OAuth 2.0 Client IDsproject:Configure these environment variables:
GOOGLE_CLIENT_SECRET, andGOOGLE_CLIENT_ID. You can find these values in the Google cloud console, in the same place where you configured the authorized origins and redirect URIs.
That's it! That should be all you have to do. Now, when you reload Khoj without --anonymous-mode, you should be able to use your Google account to sign in.
File: documentation/docs/advanced/gcp-vertex.md
Google Vertex AI
:::info
This is only helpful for self-hosted users. If you're using Khoj Cloud, you can directly use any of the pre-configured AI models.
:::
Khoj can use Google's Gemini and Anthropic's Claude family of AI models from Vertex AI on Google Cloud. Explore Anthropic and Gemini AI models available on Vertex AI's Model Garden.
Setup
- Follow these instructions to use models on GCP Vertex AI.
- Create Service Account credentials.
- Download the credentials keyfile in json format.
- Base64 encode the credentials json keyfile. For example by running the following command from your terminal:
base64 -i <service_account_credentials_keyfile.json>
- Create a new API Model API on your Khoj admin panel.
- Name:
Google Vertex(or whatever friendly name you prefer). - Api Key:
base64 encoded json keyfilefrom step 2. - Api Base Url:
https://{MODEL_GCP_REGION}-aiplatform.googleapis.com/v1/projects/{YOUR_GCP_PROJECT_ID}- MODEL_GCP_REGION: A region the AI model is available in. For example
us-east5works for Claude. - YOUR_GCP_PROJECT_ID: Get your project id from the Google cloud dashboard
- MODEL_GCP_REGION: A region the AI model is available in. For example
- Name:
- Create a new Chat Model on your Khoj admin panel.
- Name:
claude-3-7-sonnet@20250219. Any Claude or Gemini model on Vertex's Model Garden should work. - Model Type:
AnthropicorGoogle - Ai Model API: the Google Vertex Ai Model API you created in step 3
- Max prompt size:
60000(replace with the max prompt size of your model) - Tokenizer: Do not set
- Name:
- Select the chat model on your settings page and start a conversation.
Troubleshooting & gcp AI Tips
Permission Denied?
Ensure your service account has theVertex AI Userrole and that the API is enabled in your GCP project.Region Errors?
Double-check that the model you're trying to use is supported in your selected region. Some Claude or Gemini models are restricted to specific zones likeus-east5orus-central1.Prompt Size Limitations
The "Max prompt size" should align with the limits defined in the model documentation. Exceeding it can silently fail or truncate inputs.Testing the API Key
Before adding it to Khoj, you can verify that your key works by making a simple curl request to Vertex AI. This helps debug auth issues early.Use Environment Variables
For better security, consider using environment variables to manage sensitive keys and inject them at runtime during base64 encoding.
If you encounter any issues, the Khoj Discord is a great place to ask for help!
File: documentation/docs/advanced/litellm.md
LiteLLM
:::info
This is only helpful for self-hosted users. If you're using Khoj Cloud, you're limited to our first-party models.
:::
:::info
Khoj natively supports local LLMs available on HuggingFace in GGUF format. Using an OpenAI API proxy with Khoj maybe useful for ease of setup, trying new models or using commercial LLMs via API.
:::
LiteLLM exposes an OpenAI compatible API that proxies requests to other LLM API services. This provides a standardized API to interact with both open-source and commercial LLMs.
Using LiteLLM with Khoj makes it possible to turn any LLM behind an API into your personal AI agent.
Setup
- Install LiteLLMbash
pip install litellm[proxy] - Start LiteLLM and use Mistral tiny via Mistral APItext
export MISTRAL_API_KEY=<MISTRAL_API_KEY> litellm --model mistral/mistral-tiny --drop_params - Create a new API Model API on your Khoj admin panel
- Name:
litellm - Api Key:
any string - Api Base Url: ``
- Name:
- Create a new Chat Model on your Khoj admin panel.
- Name:
llama3.1(replace with the name of your local model) - Model Type:
Openai - Ai Model Api: the litellm Ai Model API you created in step 3
- Max prompt size:
20000(replace with the max prompt size of your model) - Tokenizer: Do not set for OpenAI, Mistral, Llama3 based models
- Name:
- Go to your config and select the model you just created in the chat model dropdown.
File: documentation/docs/advanced/lmstudio.md
LM Studio
:::warning[Unsupported]
Khoj does not work with LM Studio anymore. Khoj leverages json mode extensively but LMStudio's API seems to have dropped support for json mode. 1, 2
:::
:::info
This is only helpful for self-hosted users. If you're using Khoj Cloud, you're limited to our first-party models.
:::
:::info
Khoj natively supports local LLMs available on HuggingFace in GGUF format. Using an OpenAI API proxy with Khoj maybe useful for ease of setup, trying new models or using commercial LLMs via API.
:::
LM Studio is a desktop app to chat with open-source LLMs on your local machine. LM Studio provides a neat interface for folks comfortable with a GUI.
LM Studio can expose an OpenAI API compatible server. This makes it possible to turn chat models from LM Studio into your personal AI agents with Khoj.
Setup
- Install LM Studio and download your preferred Chat Model
- Go to the Server Tab on LM Studio, Select your preferred Chat Model and Click the green Start Server button
- Create a new AI Model API on your Khoj admin panel
- Name:
lmstudio - Api Key:
any string - Api Base Url:
http://localhost:1234/v1/(default for LMStudio)
- Name:
- Create a new Chat Model on your Khoj admin panel.
- Name:
llama3.1(replace with the name of your local model) - Model Type:
Openai - Ai Model Api: the lmstudio Ai Model Api you created in step 3
- Max prompt size:
20000(replace with the max prompt size of your model) - Tokenizer: Do not set for OpenAI, mistral, llama3 based models
- Name:
- Go to your config and select the model you just created in the chat model dropdown.
File: documentation/docs/advanced/ollama.mdx
Ollama
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';:::info
This is only helpful for self-hosted users. If you're using Khoj Cloud, you can use our first-party supported models.
:::
:::info
Khoj can directly run local LLMs available on HuggingFace in GGUF format. The integration with Ollama is useful to run Khoj on Docker and have the chat models use your GPU or to try new models via CLI.
:::
Ollama allows you to run many popular open-source LLMs locally from your terminal.
For folks comfortable with the terminal, Ollama's terminal based flows can ease setup and management of chat models.
Ollama exposes a local OpenAI API compatible server. This makes it possible to use chat models from Ollama with Khoj.
Setup
:::info
Restart your Khoj server after first run or update to the settings below to ensure all settings are applied correctly.
:::
<TabItem value="pip" label="Pip">
1. Setup Ollama: https://ollama.com/
2. Download your preferred chat model with Ollama. For example,
```bash
ollama pull llama3.1
```
3. Set `OPENAI_BASE_URL` environment variable to `http://localhost:11434/v1/` in your shell before starting Khoj for the first time
```bash
export OPENAI_BASE_URL="http://localhost:11434/v1/"
khoj --anonymous-mode
```
</TabItem> If you want to add additional models running on Ollama, repeat step 4 for each model.
That's it! You should now be able to chat with your Ollama model from Khoj.
File: documentation/docs/advanced/remote.md
Remote Access
By default self-hosted Khoj is only accessible on the machine it is running. To securely access it from a remote machine:
- Set the
KHOJ_DOMAINenvironment variable to your remotely accessible ip or domain via shell or docker-compose.yml.
Examples:KHOJ_DOMAIN=my.khoj-domain.com,KHOJ_DOMAIN=192.168.0.4. - Ensure the Khoj Admin password and
KHOJ_DJANGO_SECRET_KEYenvironment variable are securely set. - Setup Authentication.
- Open access to the Khoj port (default: 42110) from your OS and Network firewall.
:::warning[Use HTTPS certificate]
To expose Khoj on a custom domain over the public internet, use of an SSL certificate is strongly recommended. You can use Let's Encrypt to get a free SSL certificate for your domain.
To disable HTTPS, set the KHOJ_NO_HTTPS environment variable to True. This can be useful if Khoj is only accessible behind a secure, private network.
:::
:::info[Try Tailscale]
You can use Tailscale for easy, secure access to your self-hosted Khoj over the network.
- Set
KHOJ_DOMAINto your machines tailscale ip or fqdn on tailnet. E.gKHOJ_DOMAIN=100.4.2.0orKHOJ_DOMAIN=khoj.tailfe8c.ts.net - Access Khoj by opening
http://tailscale-ip-of-server:42110orhttp://fqdn-of-server:42110from any device on your tailscale network
:::
File: documentation/docs/advanced/support-multilingual-docs.md
Support Multilingual Docs
Khoj uses an embedding model to understand documents. Multilingual embedding models improve the search quality for documents not in English. This affects both search and chat with docs experiences across Khoj.
To improve search and chat quality for non-english documents you can use a multilingual model.
For example, the paraphrase-multilingual-MiniLM-L12-v2 supports 50+ languages, has decent search quality and speed for a consumer machine.
To use it:
- Open the search config on your server's admin settings page. Either create a new search model, if none exists, or update the existing one. For example,
- Set the
bi_encoderfield tosentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 - Set the
cross_encoderfield tomixedbread-ai/mxbai-rerank-xsmall-v1
- Set the
- Regenerate your content index from all the relevant clients. This step is very important, as you'll need to re-encode all your content with the new model.
:::info[Note]
Modern search/embedding model like mixedbread-ai/mxbai-embed-large-v1 expect a prefix to the query (or docs) string to improve encoding. Update the bi_encoder_query_encode_config field of your embedding model with {prompt: } to improve the search quality of these models.
E.g. {prompt: "Represent this query for searching documents"}. You can pass any valid JSON object that the SentenceTransformer encode function accepts
:::
File: documentation/docs/advanced/tailscale.md
Tailscale
:::info
This is only helpful for secure cross-device access to self-hosted Khoj. You do not need this if you're using Khoj Cloud.
:::
Tailscale simplifies creating a private VPN using Wireguard and OAuth. So you can host and access services on your devices from anywhere.
The instructions below are one way to simply and securely access your self-hosted Khoj from your phone, laptop etc.
Minimal Setup
- Setup khoj on your preferred machine following the standard steps
- Sign-up to Tailscale and install the app on machines you want to access Khoj from. This usually includes your khoj server, your phone, laptop. Note the tailscale i.p of your khoj server.
- Start khoj on your server by including the flag
--host <your_server_tailscale_ip> - Open
http://<your_server_tailscale_ip>:42110to access khoj from any device on your tailscale network!
HTTPS Certificate
:::info
Tailscale uses Wireguard to encrypt and route traffic between your machines. So HTTPS isn't required with Tailscale for secure access. HTTPS with Tailscale is only useful for browsers to not complain about security and block certain features like clipboard access unless HTTPS is enabled.
:::
- Enable MagicDNS and HTTPS toggle on your tailscale admin console DNS page. Note your unique tailscale domain name (usually ends with .ts.net)
- Create an https certificate for your Khoj server by running the following command:bash
# Assuming the server is named, `server` and your tailnet is `black-forest.ts.net` # Note path of the .crt and .key files generated tailscale cert server.black-forest.ts.net - Start khoj to be served via https on standard portbash
sudo KHOJ_DOMAIN=server.black-forest.ts.net \ khoj \ --sslcert /path/to/your/tailscale.crt \ --sslkey path/to/your/tailscale.key \ --host=server.black-forest.ts.net \ --port 443 - You should now be able to access khoj on
https://server.black-forest.ts.netfrom any device on your private tailscale network!
File: documentation/docs/advanced/use-openai-proxy.md
sidebar_position: 1
Use OpenAI Proxy
:::info
This is only helpful for self-hosted users. If you're using Khoj Cloud, you're limited to our first-party models.
:::
:::info
Khoj natively supports local LLMs available on HuggingFace in GGUF format. Using an OpenAI API proxy with Khoj maybe useful for ease of setup, trying new models or using commercial LLMs via API.
:::
Khoj can use any OpenAI API compatible server including local providers like Ollama, LMStudio and LiteLLM and commercial providers like HuggingFace, OpenRouter etc.
Configuring this allows you to use non-standard, open or commercial, local or hosted LLM models for Khoj.
Combine them with Khoj can turn your favorite LLM into an AI agent. Allowing you to chat with your docs, find answers from the internet, build custom agents and run automations.
For specific integrations, see our Ollama, LMStudio and LiteLLM setup docs. For general instructions to setup Khoj with an OpenAI API proxy see below.
General Setup
- Start your preferred OpenAI API compatible app locally or get API keys from commercial AI model providers.
- Create a new API Model API on your Khoj admin panel
- Name:
any name - Api Key:
any string - Api Base Url: The URL of your Openai Compatible API
- Name:
- Create a new Chat Model on your Khoj admin panel.
- Name:
llama3(replace with the name of your local model) - Model Type:
Openai - Ai Model Api: The AI Model API you created in step 2
- Max prompt size:
2000(replace with the max prompt size of your model) - Tokenizer: Do not set for OpenAI, mistral, llama3 based models
- Name:
- Go to your config and select the model you just created in the chat model dropdown.
File: documentation/docs/clients/_category_.json
{
"label": "Clients",
"position": 4,
"link": {
"type": "generated-index",
"description": "Different ways for indexing data with the Khoj backend. To see online data sources, go to https://docs.khoj.dev/category/data-sources"
}
}
File: documentation/docs/clients/desktop.md
sidebar_position: 1
Desktop
Upload your knowledge base to Khoj and chat with your whole corpus
Companion App
Share your files, folders with Khoj using the app.
Khoj will keep these files in sync to provide contextual responses when you search or chat.
Setup
:::info[Self Hosting]
If you are self-hosting the Khoj server, update the Settings page on the Khoj Desktop app to:
- Set the
Khoj URLfield to your Khoj server URL. By default, usehttp://127.0.0.1:42110. - Do not set the
Khoj API Keyfield if your Khoj server runs in anonymous mode. For example,khoj --anonymous-mode
:::
- Install the Khoj Desktop app for your OS
- Generate an API key on the Khoj Web App
- Set your Khoj API Key on the Settings page of the Khoj Desktop app
- [Optional] Add any files, folders you'd like Khoj to be aware of on the Settings page and Click Save.
These files and folders will be automatically kept in sync for you
Main App
You can also install the Khoj application on your desktop as a progressive web app.
- Open the Khoj Web App in Chrome.
- Click on the install button in the address bar to install the app. You must be logged into your Chrome browser for this to work.
Alternatively, you can also install using this route:
- Open the three-dot menu in the top right corner of the browser.
- Go to 'Cast, Save, and Share' option.
- Click on the "Open in Khoj" option.
File: documentation/docs/clients/emacs.md
sidebar_position: 2
Emacs
Query your Second Brain from Emacs
Features
- Chat
- Faster answers: Find answers quickly, from your private notes or the public internet
- Assisted creativity: Smoothly weave across retrieving answers and generating content
- Iterative discovery: Iteratively explore and re-discover your notes
- Search
- Natural: Advanced natural language understanding using Transformer based ML Models
- Incremental: Incremental search for a fast, search-as-you-type experience
Interface
| Search | Chat |
|---|---|
Setup
:::info[Self Hosting]
If you are self-hosting the Khoj server modify the install steps below:
- Set
khoj-server-urlto your Khoj server URL. By default, usehttp://127.0.0.1:42110. - Do not set
khoj-api-keyif your Khoj server runs in anonymous mode. For example,khoj --anonymous-mode
:::
- Generate an API key on the Khoj Web App
- Add below snippet to your Emacs config file, usually at
~/.emacs.d/init.el
**Direct Install**
Khoj will index your org-agenda files, by default
;; Install Khoj.el
M-x package-install khoj
; Set your Khoj API key
(setq khoj-api-key "YOUR_KHOJ_CLOUD_API_KEY")
(setq khoj-server-url "https://app.khoj.dev")**Minimal Install**
Khoj will index your org-agenda files, by default
;; Install Khoj client from MELPA Stable
(use-package khoj
:ensure t
:pin melpa-stable
:bind ("C-c s" . 'khoj)
:config (setq khoj-api-key "YOUR_KHOJ_CLOUD_API_KEY"
khoj-server-url "https://app.khoj.dev"))**Standard Install**
Configures the specified org files, directories to be indexed by Khoj
;; Install Khoj client from MELPA Stable
(use-package khoj
:ensure t
:pin melpa-stable
:bind ("C-c s" . 'khoj)
:config (setq khoj-api-key "YOUR_KHOJ_CLOUD_API_KEY"
khoj-server-url "https://app.khoj.dev"
khoj-index-directories '("~/docs/org-roam" "~/docs/notes")
khoj-index-files '("~/docs/todo.org" "~/docs/work.org")))**Straight.el**
Configures the specified org files, directories to be indexed by Khoj
;; Install Khoj client using Straight.el
(use-package khoj
:after org
:straight (khoj :type git :host github :repo "khoj-ai/khoj" :files (:defaults "src/interface/emacs/khoj.el"))
:bind ("C-c s" . 'khoj)
:config (setq khoj-api-key "YOUR_KHOJ_CLOUD_API_KEY"
khoj-server-url "https://app.khoj.dev"
khoj-org-directories '("~/docs/org-roam" "~/docs/notes")
khoj-org-files '("~/docs/todo.org" "~/docs/work.org")))Use
Search
See Khoj Search for details
- Hit
C-c s s(orM-x khoj RET s) to open khoj search - Enter your query in natural language
E.g. "What is the meaning of life?", "My life goals for 2023"
Chat
See Khoj Chat for details
- Hit
C-c s c(orM-x khoj RET c) to open khoj chat - Ask questions in a natural, conversational style
E.g. "When did I file my taxes last year?"
Find Similar Entries
This feature finds entries similar to the one you are currently on.
- Move cursor to the org-mode entry, markdown section or text paragraph you want to find similar entries for
- Hit
C-c s f(orM-x khoj RET f) to find similar entries
Advanced Usage
Add query filters during search to narrow down results further
e.g.What is the meaning of life? -"god" +"none" dt>"last week"Use
C-c C-o 2to open the current result at cursor in its source org file- This calls
M-x org-open-at-pointon the current entry and opens the second link in the entry. - The second link is the entries org-id, if set, or the heading text.
The first link is the line number of the entry in the source file. This link is less robust to file changes. - Note: If you have speed keys enabled,
o 2will also work
- This calls
Khoj Menu
Hit C-c s (or M-x khoj) to open the khoj menu above. Then:
- Hit
tuntil you preferred content type is selected in the khoj menuContent Typespecifies the content to performSearch,UpdateorFind Similaractions on - Hit
ntwice and then enter number of results you want to seeResults Countis used by theSearchandFind Similaractions - Hit
-f utoforceupdate the khoj content index
TheForce Updateswitch is only used by theUpdateaction
Upgrade
Use your Emacs package manager to upgrade khoj.el
**With MELPA**
- Run
M-x package-refresh-content - Run
M-x package-reinstall khoj
**With Straight.el**
- Run
M-x straight-pull-package khoj
File: documentation/docs/clients/obsidian.md
sidebar_position: 3
Obsidian
Query your Second Brain from Obsidian
Features
- Chat
- Faster answers: Find answers quickly, from your private notes or the public internet
- Assisted creativity: Smoothly weave across retrieving answers and generating content
- Iterative discovery: Iteratively explore and re-discover your notes
- Search
- Natural: Advanced natural language understanding using Transformer based ML Models
- Incremental: Incremental search for a fast, search-as-you-type experience
- Similar
- Discover: Find similar notes to the current one
Setup
:::info[Self Hosting]
If you are self-hosting the Khoj server, update the Khoj Obsidian plugin settings step below:
- Set the
Khoj URLfield to your Khoj server URL. By default, usehttp://127.0.0.1:42110. - Do not set the
Khoj API Keyfield if your Khoj server runs in anonymous mode. For example,khoj --anonymous-mode
:::
- Open Khoj from the Community plugins tab in Obsidian settings panel
- Click Install, then Enable on the Khoj plugin page in Obsidian
- Generate an API key on the Khoj Web App
- Set your Khoj API Key in the Khoj plugin settings on Obsidian
- (Optional) Click
Force Syncin the Khoj plugin settings on Obsidian to immediately sync your Obsidian vault.
By default, your Obsidian vault is automatically synced periodically.
See the official Obsidian Plugin Docs for more details on installing Obsidian plugins.
Use
Chat
Click the Khoj chat icon 💬 on the Ribbon or run Khoj: Chat from the Command Palette and ask questions in a natural, conversational style.
E.g. "When did I file my taxes last year?"
See Khoj Chat for more details
Find Similar Notes
To see other notes similar to the current one, run Khoj: Find Similar Notes from the Command Palette
Search
Run Khoj: Search from the Command Palette
See Khoj Search for more details. Use query filters to limit entries to search
Upgrade
- Open Community plugins tab in Obsidian settings
- Click the Check for updates button
- Click the Update button next to Khoj, if available
Troubleshooting
- Open the Khoj plugin settings pane, to configure Khoj
- Toggle Enable/Disable Khoj, if setting changes have not applied
- Click Update button to force index to refresh, if results are failing or stale
File: documentation/docs/clients/web.md
sidebar_position: 4
Web
Query your Second Brain from your Web Browser
Without any desktop clients, you can start chatting with Khoj on the web. Bear in mind you do need one of the desktop clients in order to share and sync your data with Khoj.
Go see it here --> Khoj Cloud.
Features
- Chat
- Faster answers: Find answers quickly, from your private notes or the public internet
- Assisted creativity: Smoothly weave across retrieving answers and generating content
- Iterative discovery: Iteratively explore and re-discover your notes
- Search
- Natural: Advanced natural language understanding using Transformer based ML Models
- Incremental: Incremental search for a fast, search-as-you-type experience
Setup
No setup required. The Khoj web app is the default Khoj client. You can access it from any web browser. Try it on Khoj Cloud
Upload Documents
You can upload documents to Khoj from the web interface, one at a time. This is useful for uploading documents from your phone or tablet. To upload a document:
- You can drag and drop the document into the chat window.
- Or click the paperclip icon in the chat window and select the document from your file system.
Install on Phone
You can optionally install Khoj as a Progressive Web App (PWA). This makes it quick and easy to access Khoj on your phone.
- Login to Khoj Cloud or your self-hosted Khoj server from the web browser (prefer Chrome/Edge) on your phone
- Open the 3 dot menu on the browser and click the "Add to Home screen" option
- Click "Install" on the next screen to add the Khoj icon to your phone Home screen
Process via Screenshots
| Step 1 | Step 2 | Step 3 |
|---|---|---|
File: documentation/docs/clients/whatsapp.md
sidebar_position: 5
Query your Second Brain from WhatsApp
Text +1 (848) 800 4242 or scan the QR code below on your phone to chat with Khoj on WhatsApp.
Without any desktop clients, you can start chatting with Khoj on WhatsApp. Bear in mind you do need one of the desktop clients in order to share and sync your data with Khoj. The WhatsApp AI bot will work right away for answering generic queries and using Khoj in default mode.
In order to use Khoj on WhatsApp with your own data, you need to setup a Khoj Cloud account and connect your WhatsApp account to it. This is a one time setup and you can do it from the Khoj Cloud config page.
If you hit usage limits for the WhatsApp bot, upgrade to a paid plan on Khoj Cloud.
Features
- Slash Commands: Use slash commands to quickly access Khoj features
/online: Get responses from Khoj powered by online search./dream: Generate an image in response to your prompt./notes: Explicitly force Khoj to retrieve context from your notes. Note: You'll need to connect your WhatsApp account to a Khoj Cloud account for this to work.
We have more commands under development, including /share to uploading documents directly to your Khoj account from WhatsApp, and /speak in order to get a speech response from Khoj. Feel free to raise an issue if you have any suggestions for new commands.
Source Code
You can find all of the code for the WhatsApp bot in the flint repository. As all of our code, it is open source and you can contribute to it.
File: documentation/docs/contributing/_category_.json
{
"label": "Contributing",
"position": 2,
"link": {
"type": "generated-index",
"description": "Development Setup"
}
}
File: documentation/docs/contributing/development.mdx
sidebar_position: 0
Development
Welcome to the development docs of Khoj! Thanks for your interest in being a contributor ❤️. Open source contributors are a cornerstone of the Khoj community. We welcome all contributions, big or small.
To get started with contributing, check out the official GitHub docs on contributing to an open-source project.
Join the Discord server and click the ✅ for the question "Are you interested in becoming a contributor?" in the #welcome-and-rules channel. This will give you access to the #contributors channel where you can ask questions and get help from other contributors.
If you're looking for a place to get started, check out the list of Github Issues with the tag good first issue to find issues that are good for first-time contributors.
Local Server Installation
Using Pip
1. Khoj Installation
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';Create, Activate Virtual Environment
python3 -m venv .venv && source .venv/bin/activate
For MacOS or zsh users run this
uv sync --all-extras
</TabItem> <TabItem value="windows" label="Windows"> shell
Get Khoj Code
git clone https://github.com/khoj-ai/khoj && cd khoj
Create, Activate Virtual Environment
python3 -m venv .venv && .venv\Scripts\activate
Install Khoj for Development
uv sync --all-extras
</TabItem> <TabItem value="linux" label="Linux"> shell
# Get Khoj Code
git clone https://github.com/khoj-ai/khoj && cd khoj
Create, Activate Virtual Environment
python3 -m venv .venv && source .venv/bin/activate
Install Khoj for Development
uv sync --all-extras
```
2. Postgres Installation & Setup
Khoj uses the pgvector package to store embeddings of your index in a Postgres database. To use this, you need to have Postgres installed.
Create the Khoj database
Make sure to update your environment variables to match your Postgres configuration if you're using a different name. The default values should work for most people. When prompted for a password, you can use the default password postgres, or configure it to your preference. Make sure to set the environment variable POSTGRES_PASSWORD to the same value as the password you set here.
3. Build the front-end assets
cd src/interface/web/
bun install
bun exportYou can optionally use bun dev to start a development server for the front-end which will be available at http://localhost:3000. This is especially useful if you're making changes to the front-end code, but not necessary for running Khoj. Note that streaming does not work on the dev server due to how it is handled with SSR in Next.js.
Always run bun export to test your front-end changes on http://localhost:42110 before creating a PR.
4. Run
- Start Khojbash
khoj -vv - Configure Khoj
- Via the Desktop application: Add files, directories to index using the settings page of your desktop application. Click "Save" to immediately trigger indexing.
Note: Wait after configuration for khoj to Load ML model, generate embeddings and expose API to query notes, images, documents etc specified in config YAML
Windows Installation Notes
- Command
khojNot Recognized- Try reactivating the virtual environment and rerunning the
khojcommand. - If it still doesn't work repeat the installation process.
- Try reactivating the virtual environment and rerunning the
- Python Package Missing
- Use
uv add xxxand try running thekhojcommand.
- Use
- Command
createdbNot Recognized- make sure path to postgres binaries is included in environment variables. It usually looks something like
textC:\Program Files\PostgreSQL\16\bin - Connection Refused on port xxxx
- Locate the
pg_hba.conffile in the location where postgres was installed. - Edit the file to have trust as the method for user postgres, local, and host connections.
- Below is an example:
- Locate the
host all postgres 127.0.0.1/32 trust
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust- Errors with installing pgvector
- Reinstall Visual Studio 2022 Build Tools with:
- desktop development with c++ selected in workloads
- MSVC (C++ Build Tools), Windows 10/11 SDK, and C++/CLI support for build tools selected in individual components.
- Open the x64 Native Tools Command Prompt as an Administrator
- Follow the pgvector windows installation instructions in this command prompt.
- Reinstall Visual Studio 2022 Build Tools with:
Using Docker
Make sure you install the latest version of Docker and Docker Compose.
1. Clone
git clone https://github.com/khoj-ai/khoj && cd khoj2. Configure
- Update docker-compose.yml to use relevant environment variables.
- Comment out the
imageline and uncomment thebuildline in theserverservice
3. Run
This will start the Khoj server, and the database.
docker-compose up -d4. Upgrade
If you've made changes to the codebase, you'll need to rebuild the Docker image before running the container again.
docker-compose build --no-cacheUpdate clients
In whichever clients you're using for testing, you'll need to update the server URL to point to your local server. By default, the local server URL should be http://127.0.0.1:42110.
Validate
Before Making Changes
- Install Khoj. Setup Git Hooks for Validationshell
./scripts/dev_setup.sh- Installs the khoj server and web app by default. Use the
--fullflag to install the Khoj Desktop and Obsidian client apps as well. - Git hooks format code, check types automatically on every commit and push respectively.
- Note 1: If pre-commit didn't already get installed, install it via
pip install pre-commit - Note 2: To run the pre-commit changes manually, use
pre-commit run --hook-stage manual --allbefore creating PR
- Installs the khoj server and web app by default. Use the
Before Creating PR
:::tip[Note]
You should be in an active virtual environment for Khoj in order to run the unit tests and linter. The dev_setup.sh script will automatically create and activate it for you.
:::
- Ensure that you have a Github Issue that can be linked to the PR. If not, create one. Make sure you've tagged one of the maintainers to the issue. This will ensure that the maintainers are notified of the PR and can review it. It's best to discuss the code design on an existing issue or Discord thread before creating a PR. This helps get your PR merged faster.
- Run unit tests.shell
pytest - Run the linter.shell
mypy - Think about how to add unit tests to verify the functionality you're adding in the PR. If you're not sure how to do this, ask for help in the Github issue or on Discord's
#contributorschannel.
After Creating PR
- Automated validation workflows should run for every PR. Tag one of the maintainers in the PR to trigger it.
Obsidian Plugin Development
Plugin development setup
The core code for the Obsidian plugin is under src/interface/obsidian. The file main.ts is a good place to start.
- In your CLI, go to the directory
src/interface/obsidianin the Khoj repository. - Run
yarn installto install the dependencies. - Run
yarn devto start the development server. This will continually rebuild the plugin as you make changes to the code.- Your code changes will be outputted to a file called
main.jsin theobsidiandirectory.
- Your code changes will be outputted to a file called
Loading your development plugin in Obsidian
- Make sure you have the Khoj plugin installed in Obsidian. See the plugin page.
- Open Obsidian and go to your settings (gear icon in the bottom left corner)
- Click on 'Community Plugins' in the left panel
- Next to the 'Installed Plugins' heading, click on the folder icon to open the folder with the plugin's source code.
- Open the
khojfolder in the file explorer that opens. You'll see a file calledmain.jsin this folder. To test your changes, replace this file with themain.jsfile that was generated by the development server in the previous section.
Create Khoj Release (Only for Maintainers)
Follow the steps below to release Khoj. This will create a stable release of Khoj on Pypi, Melpa and Obsidian. It will also create desktop apps of Khoj and attach them to the latest release.
- Create and tag release commit by running the bump_version script. The release commit sets version number in required metadata files.
./scripts/bump_version.sh -c "<release_version>"- Push commit and then the tag to trigger the release workflow to create Release with auto generated release notes.
git push origin master # push release commit to khoj repository
git push origin <release_version> # push release tag to khoj repository- [Optional] Update the Release Notes to highlight new features, fixes and updates
Architecture
Visualize Codebase
Visualize Khoj Obsidian Plugin Codebase
File: documentation/docs/data-sources/_category_.json
{
"label": "Data Sources",
"position": 5,
"link": {
"type": "generated-index",
"description": "Online data sources for indexing via Khoj"
}
}
File: documentation/docs/data-sources/github_integration.md
Github integration
:::warning[Unmaintained]
The Github integration is not maintained. We are considering deprecating it. It doesn't seem used by many folks and its cumbersome for us to maintain.
:::
The Github integration allows you to index as many repositories as you want. It's currently default configured to index all Markdown/Org/Text files in each repository. For large repositories, this takes a fairly long time, but it works well for smaller projects.
Configure your settings
- Go to https://app.khoj.dev/settings and enter in settings for the data sources you want to index. You'll have to specify the file paths.
Use the Github plugin
- Generate a classic PAT (personal access token) from Github with
repoandadmin:orgscopes at least. - Navigate to https://app.khoj.dev/settings#github to configure your Github settings. Enter in your PAT, along with details for each repository you want to index.
- Click
Save. Go back to the settings page and clickConfigure. - Go to https://app.khoj.dev/ and start searching!
File: documentation/docs/data-sources/notion_integration.md
Notion Integration
The Notion integration allows you to search/chat with your Notion workspaces. Notion is a platform people use for taking notes, especially for collaboration.
Go to https://app.khoj.dev/settings to connect your Notion workspace(s) to Khoj.
Self-Hosted Setup
Go to https://www.notion.so/my-integrations and create a new integration called Khoj to get an API key.
Share all the workspaces that you want to integrate with the Khoj integration you just made in the previous step
In the first step, you generated an API key. Use the newly generated API Key in your Khoj settings, by default at http://localhost:42110/settings#notion. Click
Save.Click
Configurein http://localhost:42110/settings to index your Notion workspace(s).
That's it! You should be ready to start searching and chatting. Make sure you've configured your chat settings.
File: documentation/docs/data-sources/share_your_data.md
sidebar_position: 0
keywords: ["upload data", "upload files", "share data", "share files", "pdf ai", "ai for pdf", "ai for documents", "ai for files", "local ai pdf", "local ai documents", "local ai files"]
Upload your data
There are several ways you can get started with sharing your data with the Khoj AI.
- Drag and drop your documents via the web UI. This is best if you have a one-off document you need to interact with.
- You can use the search page to upload documents that become indexed & searchable by your second brain. Click on "Add Documents" to get started.
- Use the desktop app to upload and sync your documents. This is best if you have a lot of documents on your computer or you need the docs to stay in sync.
- Setup the sync options for either Obsidian or Emacs to automatically sync your documents with Khoj. This is best if you are already using these tools and want to leverage Khoj's AI capabilities.
- Configure your Notion or Github to sync with Khoj. By providing your credentials, you can keep the data synced in the background.
File: documentation/docs/features/_category_.json
{
"label": "Features",
"position": 3,
"link": {
"type": "generated-index",
"description": "Features supported by Khoj"
}
}
File: documentation/docs/features/agents.md
sidebar_position: 4
Agents
You can use agents to setup custom system prompts with Khoj. The server host can setup their own agents, which are accessible to all users. You can see ours at https://app.khoj.dev/agents.
Creating an Agent (Self-Hosted)
Go to server/admin/database/agent on your server and click Add Agent to create a new one. You have to set it to public in order for it to be accessible to all the users on your server. To limit access to a specific user, do not set the public flag and add the user in the Creator field.
Set your custom prompt in the personality field.
File: documentation/docs/features/all-features.md
sidebar_position: 1
Overview
Khoj supports a variety of features, including search and chat with a wide range of data sources and interfaces.
[Search](/features/search)
- Local: Your personal data stays local. All search and indexing is done on your machine when you self-host
- Incremental: Incremental search for a fast, search-as-you-type experience
[Chat](/features/chat)
- Faster answers: Find answers faster, smoother than search. No need to manually scan through your notes to find answers.
- Iterative discovery: Iteratively explore and (re-)discover your notes
- Assisted creativity: Smoothly weave across answers retrieval and content generation
- Works online or offline: Chat using online or offline AI chat models
General
- Cloud or Self-Host: Use cloud to use Khoj anytime from anywhere or self-host for privacy
- Natural: Advanced natural language understanding using Transformer based ML Models
- Pluggable: Modular architecture makes it easy to plug in new data sources, frontends and ML models
- Multiple Sources: Index your Org-mode, Markdown, PDF, plaintext files, Github repos and Notion pages
- Multiple Interfaces: Interact from your Web Browser, Emacs, Obsidian, Desktop app or even Whatsapp
Supported Interfaces
Khoj is available as a Desktop app, Emacs package, Obsidian plugin, Web app and a Whatsapp AI.
Supported Data Sources
Khoj can understand your word, PDF, org-mode, markdown, plaintext files, and Notion pages.
File: documentation/docs/features/automations.md
Automations
Automations are a powerful feature within Khoj to schedule repeated jobs for Khoj to do on your behalf. Automations allow you run your query automatically at a scheduled time and frequency. Khoj will send its research to you as an email.
You can ask Khoj to create custom newsletters, summarize news, notify you of world events etc.
Khoj uses your local time zone for scheduling. You can configure, share and delete your automations from the automations page.
:::info[Self Hosting]
Self hosting users need to setup Resend and Authentication setup to have Khoj send automation emails.
:::
| Create Automation | Receive Automation Email |
|---|---|
File: documentation/docs/features/chat.md
sidebar_position: 2
Chat
You can configure Khoj to chat with you about anything. When relevant, it'll use any notes or documents you shared with it to respond. It acts as an excellent research assistant, search engine, or personal tutor.
Overview
- Creates a personal assistant for you to inquire and engage with your notes or online information as needed
- You can choose to use Online or Offline Chat depending on your requirements
- Supports multi-turn conversations with the relevant notes for context
- Shows reference notes used to generate a response
Setup (Self-Hosting)
See the setup guide to configure your chat models.
Use
- Open Khoj Chat
- On Web: Open /chat in your web browser
- On Obsidian: Search for Khoj: Chat in the Command Palette
- On Emacs: Run
M-x khoj
- Enter your queries to chat with Khoj. Use slash commands and query filters to change what Khoj uses to respond
Details
- Your query is used to retrieve the most relevant notes, if any, using Khoj search using RAG.
- These notes, the last few messages and associated metadata is passed to the enabled chat model along with your query to generate a response
Conversation File Filters
You can use conversation file filters to limit the notes used in the chat response. To do so, use the left panel in the web UI. Alternatively, you can also use query filters to limit the notes used in the chat response.
Commands
Slash commands allows you to change what Khoj uses to respond to your query
- /notes: Limit chat to only respond using your notes, not just Khoj's general world knowledge as reference
- /general: Limit chat to only respond using Khoj's general world knowledge, not using your notes as reference
- /default: Allow chat to respond using your notes or it's general knowledge as reference. It's the default behavior when no slash command is used
- /online: Use online information and incorporate it in the prompt to the LLM to send you a response.
- /image: Generate an image in response to your query.
- /help: Use /help to get all available commands and general information about Khoj
- /diagram: Generate a diagram in response to your query. This is built on Excalidraw.
- /code: Generate and run very simple Python code snippets. Refer to Code Execution for details.
- /research: Go deeper in a topic for more accurate, in-depth responses.
File: documentation/docs/features/code_execution.md
Code Execution
Khoj can generate and run simple Python code as well. This is useful if you want to have Khoj do some data analysis, generate plots and reports. LLMs by default aren't skilled at complex quantitative tasks. Code generation & execution can come in handy for such tasks.
Khoj automatically infers when to use the code tool. You can also tell it explicitly to use the code tool or use the /code slash command in your chat.
Setup (Self-Hosting)
Terrarium Sandbox
Use Cohere's Terrarium to host the code sandbox locally on your machine for free.
To run with Docker, use our docker-compose.yml to automatically setup the Terrarium code sandbox, or start it manually like this:
docker pull ghcr.io/khoj-ai/terrarium:latest
docker run -d -p 8080:8080 ghcr.io/khoj-ai/terrarium:latestTo run from source, check these instructions.
Verify
Verify that it's running, by evaluating a simple Python expression:
curl -X POST -H "Content-Type: application/json" \
--url http://localhost:8080 \
--data-raw '{"code": "1 + 1"}' \
--no-bufferE2B Sandbox
E2B allows Khoj to run code on a remote but versatile sandbox with support for more python libraries. This is not free.
To have Khoj use E2B as the code sandbox:
- Generate an API key on their dashboard.
- Set the
E2B_API_KEYenvironment variable to it on the machine running your Khoj server.- When using our docker-compose.yml, uncomment and set the
E2B_API_KEYenv var in thedocker-compose.ymlfile.
- When using our docker-compose.yml, uncomment and set the
- Now restart your Khoj server to switch to using the E2B code sandbox.
File: documentation/docs/features/image_generation.md
Image Generation
You can use Khoj to generate images from text prompts. You can get deeper into the details of our image generation flow in this blog post: https://blog.khoj.dev/posts/how-khoj-generates-images/.
To generate images, you just need to provide a prompt to Khoj in which the image generation is in the instructions. Khoj will automatically detect the image generation intent, augment your generation prompt, and then create the image. Here are some examples:
| Prompt | Image |
|---|---|
| Paint a picture of the plants I got last month, pixar-animation | |
| Create a picture of my dream house, based on my interests |
Setup (Self-Hosting)
You have a couple of image generation options.
Image Generation Models
We support most state of the art image generation models, including Ideogram, Flux, and Stable Diffusion. These will run using Replicate. Here's how to set them up:
- Get a Replicate API key here.
- Create a new Text to Image Model. Set the
typetoReplicate. Use any of the model names you see on this list. We recommend themodel nameblack-forest-labs/flux-1.1-profrom Replicate.
OpenAI
- Get an OpenAI API key.
- Setup your OpenAI API key, if you haven't already. See instructions here
- Create a text to image config at http://localhost:42110/server/admin/database/texttoimagemodelconfig/. Use
model namedall-e-3to use openai for image generation. Make sure to set theAi model apifield to the OpenAI AI model api you setup in step 2.
File: documentation/docs/features/keyboard_shortcuts.md
Keyboard Shortcuts
Oftentimes, having to leave your keyboard to move the mouse can break your flow. We want to make it as easy as possible for AI to flow with you as you are, so we've added some keyboard shortcuts to facilitate that.
Obsidian
Up/Down Arrow Keys (Chat Input)
- Up Arrow Key: Move up in the list of most recent messages in your chat window.
- Down Arrow Key: Move down in the list of most recent messages in your chat window.
You can watch the demo to see how it works on this sample conversation.
Enter (Chat Input)
Press 'Enter' to send the message you've typed in the chat window.
File: documentation/docs/features/khoj_mini.md
Desktop Quick Chat (Khoj Mini)
Once you have the Khoj desktop application installed, you can use the desktop shortcut to quickly pull up a mini chat module for quicker answers. See the desktop setup instructions in the docs for more information.
To use it, you just have to copy the text you want to inject into your query, and then run Ctrl + Shift + K (or Cmd + Shift + K on Mac) to open the mini chat module. The text you copied will be automatically pasted into the chat module, and you can then hit enter to get the answer. You can edit the text before hitting enter if you want to refine your query.
The desktop shortcut is a great way to quickly get answers to your questions without having to switch between windows or tabs. It's especially useful when you're working on a project and need to quickly look up something without losing your focus.
File: documentation/docs/features/online_search.md
Online Search
Khoj will research on the internet to ground its responses, when it determines that it would need fresh information outside its existing knowledge to answer the query. It will always show any online references it used to respond to your requests.
By default, Khoj will try to infer which information sources, it needs to read to answer your question. This can include reading your documents or researching information online. You can also explicitly trigger an online search by adding the /online prefix to your chat query.
Example queries that should trigger an online search:
- What's the latest news about the Israel-Palestine war?
- Where can I find the best pizza in New York City?
- /online Deadline for filing taxes 2024.
- Give me a summary of this article: https://en.wikipedia.org/wiki/Haitian_Revolution
Try it out yourself! https://app.khoj.dev
Self-Hosting
Search
Online search can work even with self-hosting! You have a few options:
- If you're using Docker, online search should work out of the box with searxng using our standard
docker-compose.yml. - To get production-grade, fast online search, set the
SERPER_DEV_API_KEYenvironment variable to your Serper.dev API key. These search results include additional context like answer box, knowledge graph etc. - To use open, self-hostable search provider, set the
FIRECRAWL_API_KEYenvironment variable to your Firecrawl API key. These search results do not scrape social media results. - To use Exa search provider, set the
EXA_API_KEYenvironment variable to your Exa API key.
Webpage Reading
Out of the box, you don't have to do anything to enable webpage reading. Khoj will automatically read webpages by using the requests library. To get faster, more readable webpages for Khoj, you can use the following options:
- For open, self-hostable webpage reader, you can use Firecrawl. Create a new Webscraper. Set your Firecrawl API key to the Api Key field, and set the type to Firecrawl.
- For advanced webpage reading, you can use Olostep. This can read a wider variety of webpages. Create a new Webscraper. Set your Olostep API key to the Api Key field, and set the type to Olostep.
- For fast webpage reading, you can use Exa. Create a new Webscraper. Set your Exa API key to the Api Key field, and set the type to Exa.
File: documentation/docs/features/search.md
sidebar_position: 3
Search
Take advantage of super fast search to find relevant notes and documents from your Second Brain.
Use
- Open Khoj Search
- On Web: Open https://app.khoj.dev/ in your web browser
- On Obsidian: Click the Khoj search icon 🔎 on the Ribbon or Search for Khoj: Search in the Command Palette
- On Emacs: Run
M-x khoj
- Query using natural language to find relevant entries from your knowledge base. Use query filters to limit entries to search
Demo
Implementation Overview
A bi-encoder models is used to create meaning vectors (aka vector embeddings) of your documents and search queries.
- When you sync you documents with Khoj, it uses the bi-encoder model to create and store meaning vectors of (chunks of) your documents
- When you initiate a natural language search the bi-encoder model converts your query into a meaning vector and finds the most relevant document chunks for that query by comparing their meaning vectors.
- The slower but higher-quality cross-encoder model is than used to re-rank these documents for your given query.
Setup (Self-Hosting)
You are not required to configure the search model config when self-hosting. Khoj sets up decent default local search model config for general use.
You may want to configure this if you need better multi-lingual search, want to experiment with different, newer models or the default models do not work for your use-case.
You can use bi-encoder models downloaded locally from Huggingface, served via the HuggingFace Inference API, OpenAI API, Azure OpenAI API or any OpenAI Compatible API like Ollama, LiteLLM etc. Follow the steps below to configure your search model:
- Open the SearchModelConfig page on your Khoj admin panel.
- Hit the Plus button to add a new model config or click the id of an existing model config to edit it.
- Set the
biencoderfield to the name of the bi-encoder model supported locally or via the API you configure. - Set the
Embeddings inference endpoint api keyto your OpenAI API key andEmbeddings inference endpoint typetoOpenAIto use an OpenAI embedding model. - Also set the
Embeddings inference endpointto your Azure OpenAI or OpenAI compatible API URL to use the model via those APIs. - Ensure the search model config you want to use is the only one that has
namefield set todefault[^1]. - Save the search model configs and restart your Khoj server to start using your new, updated search config.
:::info
You will need to re-index all your documents if you want to use a different bi-encoder model.
:::
:::info
You may need to tune the Bi encoder confidence threshold field for each bi-encoder to get appropriate number of documents for chat with your Knowledge base.
Confidence here is a normalized measure of semantic distance between your query and documents. The confidence threshold limits the documents returned to chat that fall within the distance specified in this field. It can take values between 0.0 (exact overlap) and 1.0 (no meaning overlap).
:::
[^1]: Khoj uses the first search model config named default it finds on startup as the search model config for that session
File: documentation/docs/features/share.md
Shareable Chat
You can share any of your conversations by going to the three dot menu on the conversation and selecting 'Share'. This will create a public link that you can share with anyone. The link will open the conversation in the same state it was when you shared it, so your future messages will not be visible to the person you shared it with.
This means you can easily share a conversation with someone to show them how you solved a problem, or to get help with something you're working on.
File: documentation/docs/features/voice-chat.md
Voice
You can talk to Khoj using your voice. Khoj will respond to your queries using the same models as the chat feature. You can use voice chat on the web, Desktop, and Obsidian apps.
Click on the little mic icon to send your voice message to Khoj. It will send back what it heard via text. You can edit the message before sending it, if required. Try it at https://app.khoj.dev/.
Voice Response
If you send a voice message, Khoj will automatically respond back with a voice message.
You can also click on the speaker icon next to any message to hear it out loud. The voice response feature is available only on the web view right now.
Setup (Self-Hosting)
Voice chat will automatically be configured when you initialize the application. The default configuration will run locally. If you want to use the OpenAI whisper API for voice chat, you can set it up by following these steps:
- Setup your OpenAI API key. See instructions here.
- Create a new configuration at http://localhost:42110/server/admin/database/speechtotextmodeloptions/. We recommend the value
whisper-1and model typeOpenai.
If you want to use the Text to Speech feature, you can set it up by following these steps:
- Setup your account on ElevenLabs.io.
- Configure your API key in your environment variables with the key
ELEVEN_LABS_API_KEY. - (Optional) Create a new Voice model option with a specific voice ID from whichever voice you want to use. You can explore the options here.
File: documentation/docs/get-started/_category_.json
{
"label": "Get Started",
"position": 1,
"link": {
"type": "generated-index",
"description": "Learn how to get started with using Khoj"
}
}
File: documentation/docs/get-started/overview.md
sidebar_position: 0 slug: / keywords: ["khoj", "khoj ai", "khoj docs", "khoj documentation", "khoj features", "khoj overview", "khoj quickstart", "khoj chat", "khoj search", "khoj cloud", "khoj self-host", "khoj setup", "open source ai", "local llm", "ai copilot", "second brain", "personal ai", "ai search engine", "research assistant", "open source llm", "self-host llm", "self-host chatgpt", "ai chatbot", "ai assistant", "ai research assistant", "ai search engine", "ai knowledge base", "ai knowledge graph", "ai personal assistant", "ai second brain", "open source ai assistant"]
Overview
Introduction
Welcome to the Khoj Docs! This is the best place to get setup and explore Khoj's features.
- Khoj is an open source, personal AI
- You can chat with it about anything. It'll use files you shared with it to respond, when relevant. It can also access information from the public internet.
- Quickly find relevant notes and documents using natural language
- It understands pdf, plaintext, markdown, org-mode files, and notion pages.
- Access it from your Emacs, Obsidian, the Khoj desktop app, or any web browser
- Use our cloud instance to access your Khoj anytime from anywhere, self-host on consumer hardware for privacy
Quickstart
- Try Khoj Cloud to get started quickly
- Read these instructions to self-host a private instance of Khoj
File: documentation/docs/get-started/privacy-security.md
sidebar_position: 4 slug: /privacy
Privacy
If you're using Khoj to index you personal data, it's almost certain you'll have sensitive and private information you'd like to index.
Khoj is designed to be a personal AI, so one of our cornerstone principles is to make it as privacy-friendly as possible. That's why, you can always choose to run Khoj on your own hardware, and never share your data outside of your device. You can generate your embeddings directly on your machine, and then use an offline chat client so that your data never leaves your machine. You'll find the instructions to self-hosting here.
Here's what to consider if you're using Khoj, whether self-hosted or on our cloud:
- Some of your relevant indexed data may be included as context when you chat with Khoj. This means that it may be sent to OpenAI, if you use one of the OpenAI models.
- We collect completely anonymized usage telemetry and send it to PostHog. This includes data like unique chat requests, unique search requests, unique requests to index data. Usage data is collected to help us understand how people are using Khoj, and to help us prioritize features.
- We do not log your IP address, nor upload any of your personal data to PostHog.
- You can see our telemetry aggregation code here and see our telemetry server here.
- If you're self-hosting, you can opt out of telemetry by following these instructions.
Self-hosting isn't for everyone, so we've still taken steps to make Khoj privacy-friendly, even if you choose to use our cloud offering. Here's what to consider when using Khoj Cloud:
- Your embeddings are generated by an open source model within our own dedicated endpoint hosted on AWS with Huggingface. There's zero persistent memory to the Huggingface Inference endpoints (it's stateless).
- Your embeddings and the associated raw text are stored in a secure Postgres DB in our private AWS cloud. Your data is sharded on a unique user ID. We store the raw text in your files to improve file syncing and provide context when you chat with Khoj.
- When you use the single-sign-on option with Google, we only receive your name, a link to your profile photo, and your email address.
You can see our full privacy policy here.
:::tip[Info]
Your data is yours. We do not sell your data or use it for training models. Khoj is a sustainable, open-source alternative to closed-source, commercial personal AI. We have no interest in selling your data to make a quick buck.
:::
We have lots of ideas of how to make Khoj really robust as a personal AI and cloud offering, but also trust-less and privacy-centric. Please reach out if this is important to you, and you'd like to help us build it.
File: documentation/docs/get-started/setup.mdx
sidebar_position: 1
Self-Host
Learn about how to self-host Khoj on your own machine.
Benefits to self-hosting:
- Privacy: Your data will never have to leave your private network. You can even use Khoj without an internet connection if deployed on your personal computer.
- Customization: You can customize Khoj to your liking, from models, to host URL, to feature enablement.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';Setup Khoj
These are the general setup instructions for self-hosted Khoj.
You can install the Khoj server using either Docker or Pip.
:::info[First Run]
Restart your Khoj server after the first run to ensure all settings are applied correctly.
:::
Prerequisites
Docker
- *Option 1*: Click here to install [Docker Desktop](https://docs.docker.com/desktop/install/mac-install/). Make sure you also install the [Docker Compose](https://docs.docker.com/desktop/install/mac-install/) tool.- *Option 2*: Use [Homebrew](https://brew.sh/) to install Docker and Docker Compose.
```shell
brew install --cask docker
brew install docker-compose
```
<h3>Setup</h3>
1. Download the Khoj docker-compose.yml file [from Github](https://github.com/khoj-ai/khoj/blob/master/docker-compose.yml)
```shell
mkdir ~/.khoj && cd ~/.khoj
wget https://raw.githubusercontent.com/khoj-ai/khoj/master/docker-compose.yml
```
2. Configure the environment variables in the `docker-compose.yml`
- Set `KHOJ_ADMIN_PASSWORD`, `KHOJ_DJANGO_SECRET_KEY` (and optionally the `KHOJ_ADMIN_EMAIL`) to something secure. This allows you to customize Khoj later via the admin panel.
- Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY` to your API key if you want to use OpenAI, Anthropic or Gemini commercial chat models respectively.
- Uncomment `OPENAI_BASE_URL` to use [Ollama](/advanced/ollama?type=first-run&server=docker#setup) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio).
3. Start Khoj by running the following command in the same directory as your docker-compose.yml file.
```shell
cd ~/.khoj
docker-compose up
```
</TabItem>
<TabItem value="windows" label="Windows">
<h3>Prerequisites</h3>
1. Install [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) and restart your machine
```shell
# Run in PowerShell
wsl --install
```
2. Install [Docker Desktop](https://docs.docker.com/desktop/install/windows-install/) with **[WSL2 backend](https://docs.docker.com/desktop/wsl/#turn-on-docker-desktop-wsl-2)** (default)
<h3>Setup</h3>
1. Download the Khoj docker-compose.yml file [from Github](https://github.com/khoj-ai/khoj/blob/master/docker-compose.yml)
```shell
# Windows users should use their WSL2 terminal to run these commands
mkdir ~/.khoj && cd ~/.khoj
wget https://raw.githubusercontent.com/khoj-ai/khoj/master/docker-compose.yml
```
2. Configure the environment variables in the `docker-compose.yml`
- Set `KHOJ_ADMIN_PASSWORD`, `KHOJ_DJANGO_SECRET_KEY` (and optionally the `KHOJ_ADMIN_EMAIL`) to something secure. This allows you to customize Khoj later via the admin panel.
- Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY` to your API key if you want to use OpenAI, Anthropic or Gemini commercial chat models respectively.
- Uncomment `OPENAI_BASE_URL` to use [Ollama](/advanced/ollama) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio).
3. Start Khoj by running the following command in the same directory as your docker-compose.yml file.
```shell
# Windows users should use their WSL2 terminal to run these commands
cd ~/.khoj
docker-compose up
```
</TabItem>
<TabItem value="linux" label="Linux">
<h3>Prerequisites</h3>
Install [Docker Desktop](https://docs.docker.com/desktop/install/linux/).
You can also use your package manager to install Docker Engine & Docker Compose.
<h3>Setup</h3>
1. Download the Khoj docker-compose.yml file [from Github](https://github.com/khoj-ai/khoj/blob/master/docker-compose.yml)
```shell
mkdir ~/.khoj && cd ~/.khoj
wget https://raw.githubusercontent.com/khoj-ai/khoj/master/docker-compose.yml
```
2. Configure the environment variables in the `docker-compose.yml`
- Set `KHOJ_ADMIN_PASSWORD`, `KHOJ_DJANGO_SECRET_KEY` (and optionally the `KHOJ_ADMIN_EMAIL`) to something secure. This allows you to customize Khoj later via the admin panel.
- Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY` to your API key if you want to use OpenAI, Anthropic or Gemini commercial chat models respectively.
- Uncomment `OPENAI_BASE_URL` to use [Ollama](/advanced/ollama) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio).
3. Start Khoj by running the following command in the same directory as your docker-compose.yml file.
```shell
cd ~/.khoj
docker-compose up
```
</TabItem>
</Tabs>:::info[Remote Access]
By default Khoj is only accessible on the machine it is running. To access Khoj from a remote machine see Remote Access Docs.
:::
Your setup is complete once you see 🌖 Khoj is ready to engage in the server logs on your terminal.
1. Install Khoj Server
- Make sure [python](https://realpython.com/installing-python/) and [pip](https://pip.pypa.io/en/stable/installation/) are installed on your machine - Check [llama-cpp-python setup](https://github.com/abetlen/llama-cpp-python?tab=readme-ov-file#supported-backends) if you hit any llama-cpp issues with the installationRun the following command in your terminal to install the Khoj server.
2. Start Khoj Server
Run the following command from your terminal to start the Khoj service.
USE_EMBEDDED_DB="true" khoj --anonymous-mode--anonymous-mode allows access to Khoj without requiring login. This is usually fine for local only, single user setups. If you need authentication follow the authentication setup docs.
First Run
On the first run of the above command, you will be prompted to: 1. Create an admin account with an email and secure password 2. Customize the chat models to enable - Keep your [OpenAI](https://platform.openai.com/api-keys), [Anthropic](https://console.anthropic.com/account/keys), [Gemini](https://aistudio.google.com/app/apikey) API keys and [OpenAI](https://platform.openai.com/docs/models), [Anthropic](https://docs.anthropic.com/en/docs/about-claude/models#model-names), [Gemini](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-models), [Offline](https://huggingface.co/models?pipeline_tag=text-generation&library=gguf) chat model names handy to set any of them up during first run. 3. Your setup is complete once you see `🌖 Khoj is ready to engage` in the server logs on your terminal!:::tip[Auto Start]
To start Khoj automatically in the background use Task scheduler on Windows or Cron on Mac, Linux (e.g. with @reboot khoj)
:::
Use Khoj
You can now open the web app at http://localhost:42110 and start interacting!
Nothing else is necessary, but you can customize your setup further by following the steps below.
Add Chat Models
Login to the Khoj Admin Panel
Go to http://localhost:42110/server/admin and login with the admin credentials you setup during installation.:::info[CSRF Error]
Ensure you are using localhost, not 127.0.0.1, to access the admin panel to avoid the CSRF error.
:::
:::info[CSRF Trusted Origin or Unset Cookie Error]
If using a load balancer/reverse_proxy in front of your Khoj server: Set the environment variable KHOJ_ALLOWED_DOMAIN=your-internal-ip-or-domain to avoid this error.
If unset, it defaults to KHOJ_DOMAIN.
:::
:::info[DISALLOWED HOST or Bad Request (400) Error]
You may hit this if you try access Khoj exposed on a custom domain (e.g. 192.168.12.3 or example.com) or over HTTP.
Set the environment variables KHOJ_DOMAIN=your-external-ip-or-domain and KHOJ_NO_HTTPS=True if required to avoid this error.
:::
:::tip[Note]
Using Safari on Mac? You might not be able to login to the admin panel. Try using Chrome or Firefox instead.
:::
Configure Chat Model
Setup which chat model you'd want to use. Khoj supports local and online chat models.:::info[Ollama Integration]
Using Ollama? See the Ollama Integration section for more custom setup instructions.
:::
Create a new AI Model Api in the server admin settings.
- Add your OpenAI API key
- Give the configuration a friendly name like
OpenAI - (Optional) Set the API base URL. It is only relevant if you're using another OpenAI-compatible proxy server like Ollama or LMStudio.
Create a new chat model
- Set the
chat-modelfield to an OpenAI chat model. Example:gpt-4o. - Make sure to set the
model-typefield toOpenAI. - If your model supports vision, set the
vision enabledfield totrue. This is currently only supported for OpenAI models with vision capabilities. - The
tokenizerandmax-prompt-sizefields are optional. Set them only if you're sure of the tokenizer or token limit for the model you're using. Contact us if you're unsure what to do here.
- Set the
:::tip[System Requirements]
- Minimum 8 GB RAM. Recommend 16Gb VRAM
- Minimum 5 GB of Disk available
- A Nvidia, AMD GPU or a Mac M1+ machine would significantly speed up chat responses
:::
- Install any Openai API compatible local ai model server like llama-cpp-server, Ollama, vLLM etc.
- Add an ai model api on the admin panel
- Set the
api urlfield to the url of your local ai model provider likehttp://localhost:11434/v1/for Ollama
- Set the
- Restart the Khoj server to load models available on your local ai model provider
- If that doesn't work, you'll need to manually add available chat model in the admin panel.
- Set the newly added chat model as your preferred model in your User chat settings
- Start chatting with your local AI!
:::tip[Multiple Chat Models]
Set your preferred default chat model in the Default, Advanced fields of your ServerChatSettings.
Khoj uses these chat model for all intermediate steps like intent detection, web search etc.
:::
:::info[Chat Model Fields]
- The
tokenizerandmax-prompt-sizefields are optional. Set them only if you're sure of the tokenizer or token limit for the model you're using. This improves context stuffing. Contact us if you're unsure what to do here. - Only tick the
vision enabledfield for OpenAI models with vision capabilities like gpt-4o. Vision capabilities in other chat models is not currently utilized.
:::
Sync your Knowledge
- You can chat with your notes and documents using Khoj.
- Khoj can keep your files and folders synced using the Khoj Desktop, Obsidian or Emacs clients.
- Your Notion workspace can be directly synced from the web app.
- You can also just drag and drop specific files you want to chat with on the Web app.
Setup Khoj Clients
The Khoj web app is available by default to chat, search and configure Khoj.
You can also install a Khoj client to easily access it from Obsidian, Emacs, Whatsapp or your OS and keep your documents synced with Khoj.
:::info[Note]
Set the host URL on your clients settings page to your Khoj server URL. By default, use http://127.0.0.1:42110 or http://localhost:42110. Note that localhost may not work in all cases.
:::
Upgrade
Upgrade Server
Upgrade Clients
Uninstall
Uninstall Server
# delete khoj postgres db
dropdb khoj -U postgres
```
</TabItem>
<TabItem value="docker" label="Docker">
Run the command below from the same directory where you have your `docker-compose` file.
This will remove the server containers, networks, images and volumes.
```shell
docker-compose down --volumes
```
</TabItem>Uninstall Clients
Troubleshoot
Dependency conflict when trying to install Khoj python package with pip
- Reason: When conflicting dependency versions are required by Khoj vs other python packages installed on your system
- Fix: Install Khoj in a python virtual environment using venv or pipx to avoid this dependency conflicts
- Process:
- Install pipx
- Use
pipxto install Khoj to avoid dependency conflicts with other python packages.shellpipx install khoj - Now start
khojusing the standard steps described earlier
Install fails while building Tokenizer dependency
- Details:
pip install khojfails while building thetokenizersdependency. Complains about Rust. - Fix: Install Rust to build the tokenizers package. For example on Mac run:shell
brew install rustup rustup-init source ~/.cargo/env - Refer: Issue with Fix for more details
Khoj in Docker errors out with \"Killed\" in error message
- Fix: Increase RAM available to Docker Containers in Docker Settings
- Refer: StackOverflow Solution, Configure Resources on Docker for Mac
File: documentation/docs/miscellaneous/_category_.json
{
"label": "Miscellaneous",
"position": 7,
"link": {
"type": "generated-index",
"description": "Additional resources for learning about Khoj"
}
}
File: documentation/docs/miscellaneous/credits.md
sidebar_position: 4
Credits
Many Open Source projects are used to power Khoj. Here's a few of them:
- Llama.cpp to chat with local LLM
- SentenceTransformer for Text Search
- HuggingFace for hosting open-source chat and search models
- Charles Cave for OrgNode Parser
- Org.js to render Org-mode results on the Web interface
- Markdown-it to render Markdown results on the Web interface
- Katex to render math
File: documentation/docs/miscellaneous/performance.md
sidebar_position: 2
Performance
Here are some top-level performance metrics for Khoj. These are rough estimates and will vary based on your hardware and data.
:::info
These performance metrics were last evaluated in 2022.
:::
Search performance
- Semantic search using the default embeddings model is fairly fast at <100 ms across all content types
- Reranking using the cross-encoder model is slower at <2s on 15 results. Tweak
top_kto tradeoff speed for accuracy of results - Filters in query (e.g. by file, word or date) usually add <20ms to query latency
Indexing performance
- Indexing is more strongly impacted by the size of the source data
- Indexing 100K+ line corpus of notes takes about 10 minutes
- Note: It should only take this long on the first run as the index is incrementally updated
Miscellaneous
- Testing done on a Mac M1 and a >100K line corpus of notes
File: documentation/docs/miscellaneous/query-filters.md
sidebar_position: 3
Query Filters
Use structured query syntax to filter entries from your knowledge based used by search results or chat responses.
- Word Filter: Get entries that include/exclude a specified term
- Entries that contain term_to_include:
+"term_to_include" - Entries that contain term_to_exclude:
-"term_to_exclude"
- Entries that contain term_to_include:
- Date Filter: Get entries containing dates in YYYY-MM-DD format from specified date (range)
- Entries from April 1st 1984:
dt:"1984-04-01" - Entries after March 31st 1984:
dt>="1984-04-01" - Entries before April 2nd 1984 :
dt<="1984-04-01"
- Entries from April 1st 1984:
- File Filter: Get entries from a specified file
- Entries from incoming.org file:
file:"incoming.org"
- Entries from incoming.org file:
- Combined Example
what is the meaning of life? file:"1984.org" dt>="1984-01-01" dt<="1985-01-01" -"big" -"brother"- Adds all filters to the natural language query. It should return entries
- from the file 1984.org
- containing dates from the year 1984
- excluding words "big" and "brother"
- that best match the natural language query "what is the meaning of life?"
File: documentation/docs/miscellaneous/telemetry.md
sidebar_position: 1
Telemetry
We collect some high level, anonymized metadata about usage of self-hosted Khoj. This includes:
- Client (Web, Emacs, Obsidian)
- API usage (Search, Chat)
- Configured content types (Github, Org, etc)
- Request metadata (e.g., host, referrer)
We don't send any personal information or any information from/about your content. We only send the above metadata. This helps us prioritize feature development and understand how people are using Khoj. Don't just take our word for it -- you can see the code here.
Disable Telemetry
If you're self-hosting Khoj, you can opt out of telemetry at any time by setting the KHOJ_TELEMETRY_DISABLE environment variable to True via shell or docker-compose.yml
If you have any questions or concerns, please reach out to us on Discord.
File: src/interface/android/manifest-checksum.txt
6ee1711cf4f745dafc80c1cc13c3025342a0f5da
File: src/interface/android/twa-manifest.json
{
"packageId": "dev.khoj.app",
"host": "app.khoj.dev",
"name": "Khoj AI",
"launcherName": "Khoj",
"display": "standalone",
"themeColor": "#FFFFFF",
"themeColorDark": "#000000",
"navigationColor": "#000000",
"navigationColorDark": "#000000",
"navigationDividerColor": "#000000",
"navigationDividerColorDark": "#000000",
"backgroundColor": "#FFFFFF",
"enableNotifications": true,
"startUrl": "/",
"iconUrl": "https://assets.khoj.dev/khoj_lantern_1200x1200.png",
"splashScreenFadeOutDuration": 300,
"signingKey": {
"path": "android.keystore",
"alias": "android"
},
"appVersionName": "4",
"appVersionCode": 4,
"shortcuts": [],
"generatorApp": "bubblewrap-cli",
"webManifestUrl": "https://app.khoj.dev/static/khoj.webmanifest",
"fallbackType": "customtabs",
"features": {
"locationDelegation": {
"enabled": true
}
},
"alphaDependencies": {
"enabled": false
},
"enableSiteSettingsShortcut": true,
"isChromeOSOnly": false,
"isMetaQuest": false,
"fullScopeUrl": "https://app.khoj.dev/",
"minSdkVersion": 19,
"orientation": "natural",
"fingerprints": [
{
"name": "signing",
"value": "CC:98:4A:0A:F1:CC:84:26:AC:02:86:49:AA:69:64:B9:5E:63:A3:EF:18:56:EA:CA:13:C1:3A:15:CA:49:77:46"
},
{
"name": "upload",
"value": "D4:5A:6F:6C:18:28:D2:1C:78:27:92:C6:AC:DB:4C:12:C4:52:A1:88:9B:A1:F5:67:D1:22:FE:A0:0F:B1:AE:92"
}
],
"additionalTrustedOrigins": [],
"retainedBundles": [],
"appVersion": "4"
}
File: src/interface/android/app/src/main/res/raw/web_app_manifest.json
{"name":"Khoj","short_name":"Khoj","display":"standalone","start_url":"/","description":"The open, personal AI for your digital brain. You can ask Khoj to draft a message, paint your imagination, find information on the internet and even answer questions from your documents.","theme_color":"#ffffff","background_color":"#ffffff","icons":[{"src":"/static/assets/icons/khoj_lantern_128x128.png","sizes":"128x128","type":"image/png"},{"src":"/static/assets/icons/khoj_lantern_256x256.png","sizes":"256x256","type":"image/png"}],"screenshots":[{"src":"/static/assets/samples/phone-remember-plan-sample.png","sizes":"419x900","type":"image/png","form_factor":"narrow","label":"Remember and Plan"},{"src":"/static/assets/samples/phone-browse-draw-sample.png","sizes":"419x900","type":"image/png","form_factor":"narrow","label":"Browse and Draw"},{"src":"/static/assets/samples/desktop-remember-plan-sample.png","sizes":"1260x742","type":"image/png","form_factor":"wide","label":"Remember and Plan"},{"src":"/static/assets/samples/desktop-browse-draw-sample.png","sizes":"1260x742","type":"image/png","form_factor":"wide","label":"Browse and Draw"}]}
File: src/interface/desktop/README.md
Run it locally
Prerequisites
Install the runtime dependencies. This command should install all dev dependencies.
yarn installRun the application
yarn startDeploying the Electron App
Prerequisites
Install the ToDesktop CLI. Full documentation can be found here: https://www.npmjs.com/package/@todesktop/cli
yarn global add @todesktop/cliConfigure the todesktop.json file. Fill in the id based on the application ID.
Build
This will prompt you to login. It triggers builds for all platforms.
todesktop buildIf you get an error saying the command is not found, make sure that your yarn global bin directory is in your PATH environment variable. You can find the location of the global bin directory by running yarn global bin. Add this line to your .bashrc or .zshrc file: export PATH="$PATH:$(yarn global bin)".
File: src/interface/desktop/package.json
{
"name": "Khoj",
"version": "2.0.0-beta.28",
"description": "Your Second Brain",
"author": "Khoj Inc. [email protected]",
"license": "GPL-3.0-or-later",
"homepage": "https://khoj.dev",
"repository": ""https://github.com/khoj-ai/khoj\"",
"productName": "Khoj",
"main": "main.js",
"private": false,
"devDependencies": {
"electron": "39.8.5"
},
"scripts": {
"start": "yarn electron ."
},
"dependencies": {
"@todesktop/runtime": "^2.0.0",
"axios": "^1.16.0",
"cron": "^2.4.3",
"electron-store": "^8.1.0"
},
"resolutions": {
"ajv": "^8.18.0",
"picomatch": ">=2.3.2"
}
}
File: src/interface/desktop/todesktop.json
{
"id": "",
"icon": "./assets/icons/favicon.icns",
"appPath": ".",
"schemaVersion": 1,
"windows": {
"icon": "./assets/icons/favicon-128x128.png"
}
}
File: src/interface/obsidian/README.md
Obsidian Development
You can use the Obsidian Khoj plugin to share your Obsidian knowledge base with your AI assistant. The plugin will index your notes and make them searchable by your AI assistant.
Development
In src/interface/obsidian, run:
yarn install
yarn buildYou'll want to link the built plugin to your Obsidian vault. You can do this by symlinking the built folder to your Obsidian vault's plugins folder. For example:
ln -s /path/to/khoj-assistant/src/interface/obsidian /path/to/obsidian-vault/.obsidian/plugins/obsidian-assistantNow, once you reload your Obsidian, you should see your updated plugin code running.
File: src/interface/obsidian/manifest.json
{
"id": "khoj",
"name": "Khoj",
"version": "2.0.0-beta.28",
"minAppVersion": "0.15.0",
"description": "Your Second Brain",
"author": "Khoj Inc.",
"authorUrl": "https://github.com/khoj-ai",
"isDesktopOnly": false
}
File: src/interface/obsidian/package.json
{
"name": "Khoj",
"version": "2.0.0-beta.28",
"description": "Your Second Brain",
"author": "Debanjum Singh Solanky, Saba Imran [email protected]",
"license": "GPL-3.0-or-later",
"main": "src/main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [
"search",
"chat",
"AI",
"assistant",
"second brain"
],
"devDependencies": {
"@types/dompurify": "3.2.0",
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "7.13.1",
"@typescript-eslint/parser": "7.13.1",
"builtin-modules": "3.3.0",
"esbuild": "0.14.47",
"obsidian": "^1.6.6",
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {
"diff": "^8.0.3",
"isomorphic-dompurify": "^2.25.0"
},
"resolutions": {
"picomatch": ">=2.3.2"
}
}
File: src/interface/obsidian/tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES2018",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7",
"ES2018"
]
},
"include": [
"**/*.ts"
]
}
File: src/interface/obsidian/versions.json
{
"0.2.1": "0.15.0",
"0.2.5": "0.15.0",
"0.2.6": "0.15.0",
"0.3.0": "0.15.0",
"0.4.0": "0.15.0",
"0.5.0": "0.15.0",
"0.6.0": "0.15.0",
"0.6.1": "0.15.0",
"0.6.2": "0.15.0",
"0.7.0": "0.15.0",
"0.7.1": "0.15.0",
"0.8.0": "0.15.0",
"0.8.1": "0.15.0",
"0.8.2": "0.15.0",
"0.9.0": "0.15.0",
"0.10.0": "0.15.0",
"0.10.1": "0.15.0",
"0.11.0": "0.15.0",
"0.11.1": "0.15.0",
"0.11.2": "0.15.0",
"0.11.3": "0.15.0",
"0.11.4": "0.15.0",
"0.12.0": "0.15.0",
"0.12.1": "0.15.0",
"0.12.2": "0.15.0",
"0.12.3": "0.15.0",
"0.13.0": "0.15.0",
"0.14.0": "0.15.0",
"1.0.0": "0.15.0",
"1.0.1": "0.15.0",
"1.1.0": "0.15.0",
"1.2.0": "0.15.0",
"1.2.1": "0.15.0",
"1.3.0": "0.15.0",
"1.4.0": "0.15.0",
"1.5.0": "0.15.0",
"1.5.1": "0.15.0",
"1.6.0": "0.15.0",
"1.6.1": "0.15.0",
"1.6.2": "0.15.0",
"1.7.0": "0.15.0",
"1.8.0": "0.15.0",
"1.9.0": "0.15.0",
"1.10.0": "0.15.0",
"1.10.1": "0.15.0",
"1.10.2": "0.15.0",
"1.11.0": "0.15.0",
"1.11.1": "0.15.0",
"1.11.2": "0.15.0",
"1.12.0": "0.15.0",
"1.12.1": "0.15.0",
"1.13.0": "0.15.0",
"1.14.0": "0.15.0",
"1.15.0": "0.15.0",
"1.16.0": "0.15.0",
"1.17.0": "0.15.0",
"1.20.0": "0.15.0",
"1.20.1": "0.15.0",
"1.20.2": "0.15.0",
"1.20.3": "0.15.0",
"1.20.4": "0.15.0",
"1.21.0": "0.15.0",
"1.21.1": "0.15.0",
"1.21.2": "0.15.0",
"1.21.3": "0.15.0",
"1.21.4": "0.15.0",
"1.21.5": "0.15.0",
"1.21.6": "0.15.0",
"1.22.0": "0.15.0",
"1.22.1": "0.15.0",
"1.22.2": "0.15.0",
"1.22.3": "0.15.0",
"1.23.0": "0.15.0",
"1.23.1": "0.15.0",
"1.23.2": "0.15.0",
"1.23.3": "0.15.0",
"1.24.0": "0.15.0",
"1.24.1": "0.15.0",
"1.25.0": "0.15.0",
"1.26.0": "0.15.0",
"1.26.1": "0.15.0",
"1.26.2": "0.15.0",
"1.26.3": "0.15.0",
"1.26.4": "0.15.0",
"1.27.0": "0.15.0",
"1.27.1": "0.15.0",
"1.28.0": "0.15.0",
"1.28.1": "0.15.0",
"1.28.2": "0.15.0",
"1.28.3": "0.15.0",
"1.29.0": "0.15.0",
"1.29.1": "0.15.0",
"1.30.0": "0.15.0",
"1.30.1": "0.15.0",
"1.30.2": "0.15.0",
"1.30.3": "0.15.0",
"1.30.4": "0.15.0",
"1.30.5": "0.15.0",
"1.30.6": "0.15.0",
"1.30.7": "0.15.0",
"1.30.8": "0.15.0",
"1.30.9": "0.15.0",
"1.30.10": "0.15.0",
"1.31.0": "0.15.0",
"1.32.0": "0.15.0",
"1.32.1": "0.15.0",
"1.32.2": "0.15.0",
"1.33.0": "0.15.0",
"1.33.1": "0.15.0",
"1.33.2": "0.15.0",
"1.34.0": "0.15.0",
"1.35.0": "0.15.0",
"1.35.1": "0.15.0",
"1.35.2": "0.15.0",
"1.35.3": "0.15.0",
"1.36.0": "0.15.0",
"1.36.1": "0.15.0",
"1.36.2": "0.15.0",
"1.36.3": "0.15.0",
"1.36.4": "0.15.0",
"1.36.5": "0.15.0",
"1.36.6": "0.15.0",
"1.37.0": "0.15.0",
"1.37.1": "0.15.0",
"1.37.2": "0.15.0",
"1.38.0": "0.15.0",
"1.39.0": "0.15.0",
"1.40.0": "0.15.0",
"1.41.0": "0.15.0",
"1.42.0": "0.15.0",
"1.42.1": "0.15.0",
"1.42.2": "0.15.0",
"1.42.3": "0.15.0",
"1.42.4": "0.15.0",
"1.42.5": "0.15.0",
"1.42.6": "0.15.0",
"1.42.7": "0.15.0",
"1.42.8": "0.15.0",
"2.0.0-beta.1": "0.15.0",
"2.0.0-beta.2": "0.15.0",
"2.0.0-beta.3": "0.15.0",
"2.0.0-beta.4": "0.15.0",
"2.0.0-beta.5": "0.15.0",
"2.0.0-beta.6": "0.15.0",
"2.0.0-beta.7": "0.15.0",
"2.0.0-beta.8": "0.15.0",
"2.0.0-beta.9": "0.15.0",
"2.0.0-beta.10": "0.15.0",
"2.0.0-beta.11": "0.15.0",
"2.0.0-beta.12": "0.15.0",
"2.0.0-beta.13": "0.15.0",
"2.0.0-beta.14": "0.15.0",
"2.0.0-beta.15": "0.15.0",
"2.0.0-beta.16": "0.15.0",
"2.0.0-beta.17": "0.15.0",
"2.0.0-beta.18": "0.15.0",
"2.0.0-beta.19": "0.15.0",
"2.0.0-beta.20": "0.15.0",
"2.0.0-beta.21": "0.15.0",
"2.0.0-beta.22": "0.15.0",
"2.0.0-beta.23": "0.15.0",
"2.0.0-beta.24": "0.15.0",
"2.0.0-beta.25": "0.15.0",
"2.0.0-beta.26": "0.15.0",
"2.0.0-beta.27": "0.15.0",
"2.0.0-beta.28": "0.15.0"
}
File: src/interface/web/README.md
This is a Next.js project.
Getting Started
First, install the dependencies:
bun installIn case you run into any dependency linking issues, you can try running:
bun add nextRun the development server:
bun devMake sure the rewrites in next.config.mjs are set up correctly for your environment. The rewrites are used to proxy requests to the API server.
rewrites: async () => {
return [
{
source: '/api/:path*',
destination: 'http://localhost:42110/api/:path*',
},
];
},The destination should be the URL of the API server.
Open http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying any of the .tsx pages. The page auto-updates as you edit the file.
Testing built files
We've setup a utility command for building and serving the built files. This is useful for testing the production build locally.
- Exporting code
To build the files once and serve them, run:
bun exportIf you're using Windows:
bun windowsexport- Continuously building code
To keep building the files and serving them, run:
bun watchIf you're using Windows:
bun windowswatchNow you should be able to load your custom pages from the Khoj app at http://localhost:42110/. To server any of the built files, you should update the routes in the web_client.py like so, where new_file is the new page you've added in this repo:
@web_client.post("/new_route", response_class=FileResponse)
@requires(["authenticated"], redirect="login_page")
def index_post(request: Request):
return templates.TemplateResponse(
"new_file/index.html",
context={
"request": request,
},
)Learn More
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Next.js App Router - learn about the Next.js router.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
File: src/interface/web/components.json
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
File: src/interface/web/package.json
{
"name": "khoj-ai",
"version": "2.0.0-beta.28",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"collectstatic": "bash -c 'pushd ../../../ && source .venv/bin/activate && python3 src/khoj/manage.py collectstatic --noinput && deactivate && popd'",
"cicollectstatic": "bash -c 'pushd ../../../ && uv run python src/khoj/manage.py collectstatic --noinput && popd'",
"export": "bun run build && cp -r out/ ../../khoj/interface/built && bun run collectstatic",
"ciexport": "bun run build && cp -r out/ ../../khoj/interface/built && bun run cicollectstatic",
"pypiciexport": "bun run build && mkdir -p ../../khoj/interface/compiled && cp -r out/. ../../khoj/interface/compiled && bun run cicollectstatic",
"watch": "nodemon --watch . --ext js,jsx,ts,tsx,css --ignore 'out//*' --exec 'bun run export'",
"windowswatch": "nodemon --watch . --ext js,jsx,ts,tsx,css --ignore 'out//' --exec 'bun run windowsexport'",
"windowscollectstatic": "cd ..\..\.. && .\.venv\Scripts\Activate.bat && py .\src\khoj\manage.py collectstatic --noinput && .\.venv\Scripts\deactivate.bat && cd ..",
"windowsexport": "bun run build && xcopy out ..\..\khoj\interface\built /E /Y && bun run windowscollectstatic",
"prepare": "husky"
},
"dependencies": {
"@excalidraw/excalidraw": "^0.17.6",
"@hookform/resolvers": "^3.10.0",
"@phosphor-icons/react": "^2.1.10",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-menubar": "^1.1.16",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toast": "^1.2.15",
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.8",
"@radix-ui/themes": "^3.2.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"cronstrue": "^2.61.0",
"dompurify": "^3.3.2",
"embla-carousel-autoplay": "^8.6.0",
"embla-carousel-react": "^8.6.0",
"file-saver": "^2.0.5",
"framer-motion": "^12.23.12",
"input-otp": "^1.4.2",
"intl-tel-input": "^23.9.3",
"jszip": "^3.10.1",
"katex": "^0.16.22",
"libphonenumber-js": "^1.12.17",
"lucide-react": "^0.468.0",
"markdown-it": "^14.1.0",
"markdown-it-highlightjs": "^4.2.0",
"mermaid": "^11.11.0",
"next": "15.5.18",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.62.0",
"react-use-websocket": "^4.13.0",
"swr": "^2.3.6",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.9",
"zod": "^3.25.76"
},
"devDependencies": {
"@types/dompurify": "^3.2.0",
"@types/file-saver": "^2.0.7",
"@types/intl-tel-input": "^18.1.4",
"@types/katex": "^0.16.7",
"@types/markdown-it": "^14.1.2",
"@types/node": "^20.19.15",
"@types/react": "^18.3.24",
"@types/react-dom": "^18.3.7",
"autoprefixer": "^10.4.21",
"eslint": "^8.57.1",
"eslint-config-next": "15.5.18",
"eslint-config-prettier": "^9.1.2",
"eslint-plugin-prettier": "^5.5.4",
"husky": "^9.1.7",
"lint-staged": "^15.5.2",
"nodemon": "^3.1.10",
"postcss": "^8.5.6",
"prettier": "3.3.3",
"shadcn-ui": "^0.9.5",
"tailwindcss": "^3.4.17",
"typescript": "^5.9.2"
},
"prettier": {
"tabWidth": 4,
"printWidth": 100
},
"lint-staged": {
"": "bun run lint"
},
"overrides": {
"picomatch": ">=2.3.2"
}
}
File: src/interface/web/tsconfig.json
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"downlevelIteration": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/": [
"./"
]
},
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"/*.ts",
"/.tsx",
".next/types/**/.ts",
"out/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}
File: src/interface/web/.eslintrc.json
{
"extends": [
"next",
"next/core-web-vitals",
"plugin:prettier/recommended"
],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "warn"
}
}
File: src/khoj/app/README.md
Django App
Khoj uses Django as the backend framework primarily for its powerful ORM and the admin interface. The Django app is located in the src/app directory. We have one installed app, under the /database/ directory. This app is responsible for all the database related operations and holds all of our models. You can find the extensive Django documentation here 🌈.
Setup (Docker)
Prerequisites
- Ensure you have Docker installed.
- Ensure you have Docker Compose installed.
Run
Using the docker-compose.yml file in the root directory, you can run the Khoj app using the following command:
docker-compose upSetup (Local)
Install Postgres (with PgVector)
MacOS
- Install the Postgres.app.
Debian, Ubuntu
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo apt install postgres-16 postgresql-16-pgvectorWindows
- Use the recommended installer
From Source
- Follow instructions to Install Postgres
- Follow instructions to Install PgVector in case you need to manually install it. Reproduced instructions below for convenience.
cd /tmp
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
cd pgvector
make
make install # may need sudoCreate the Khoj database
MacOS
createdb khoj -U postgresDebian, Ubuntu
sudo -u postgres createdb khoj- [Optional] To set default postgres user's password
- Execute
ALTER USER postgres PASSWORD 'my_secure_password';usingpsql - Run
export $POSTGRES_PASSWORD=my_secure_passwordin your terminal for Khoj to use it later
- Execute
Install Khoj
uv sync --all-extrasMake Khoj DB migrations
This command will create the migrations for the database app. This command should be run whenever a new db model is added to the database app or an existing db model is modified (updated or deleted).
python3 src/manage.py makemigrationsRun Khoj DB migrations
This command will run any pending migrations in your application.
python3 src/manage.py migrateStart Khoj Server
While we're using Django for the ORM, we're still using the FastAPI server for the API. This command automatically scaffolds the Django application in the backend.
Note: Anonymous mode bypasses authentication for local, single-user usage.
python3 src/khoj/main.py --anonymous-modeFile: src/khoj/interface/web/.well-known/assetlinks.json
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "dev.khoj.app",
"sha256_cert_fingerprints": [
"CC:98:4A:0A:F1:CC:84:26:AC:02:86:49:AA:69:64:B9:5E:63:A3:EF:18:56:EA:CA:13:C1:3A:15:CA:49:77:46",
"D4:5A:6F:6C:18:28:D2:1C:78:27:92:C6:AC:DB:4C:12:C4:52:A1:88:9B:A1:F5:67:D1:22:FE:A0:0F:B1:AE:92"
]
}
}]
File: src/khoj/processor/operator/README.md
Khoj Operator (Experimental)
Overview
Give Khoj its own computer to operate in a transparent, controlled manner. Accomplish tasks that require visual browsing, file editing and terminal access. Operator with research mode can work for 30+ minutes to accomplish more substantial tasks like feature development, travel planning, shopping etc.
Setup
Prerequisites
- Docker and Docker Compose installed
- Anthropic API key (required - only Anthropic models currently enabled)
Installation Steps
Download the Khoj docker-compose.yml file
shellmkdir ~/.khoj && cd ~/.khoj wget https://raw.githubusercontent.com/khoj-ai/khoj/master/docker-compose.ymlUpdate the
docker-compose.ymlto enable computer operator- Set
ANTHROPIC_API_KEYto your Anthropic API key - Uncomment
KHOJ_OPERATOR_ENABLED=Trueto enable the operator tool - Uncomment
- /var/run/docker.sock:/var/run/docker.sockto mount docker socket to allow khoj to operate its computer container.
- Set
Start Khoj services
shelldocker-compose upAccess the web app at http://localhost:42110
Ensure you're using a claude 3.7+ models on your settings page
Usage
Use the /operator command or ask Khoj in normal or research mode to use the operator tool to have it operate its computer:
Examples:
/operator Find flights from Bangkok to Mexico City with no US layover/research Clone the khoj repo and tell me how the operator tool is implemented
Supported Models
Currently enables only Anthropic models:
- Claude Sonnet 4
- Claude 3.7 Sonnet
- Claude Opus 4
Note: OpenAI and other operator models are disabled while in development.
Capabilities
The operator can:
- Computer Control: Take screenshots, click, type, navigate desktop
- File Operations: Create, edit, and manage files
- Terminal Access: Execute bash commands and scripts
- Web Browsing: Navigate websites, documents and extract information
Architecture
- Environments: Operator Computer and Browser environments
- Models: Enable Vision Language Models (VLM) to operate computer
- Execution: Containerize computer environment for security and isolation
File: src/telemetry/requirements.txt
uvicorn
fastapi
posthog
python-dotenv
File: tests/data/config.yml
content-type:
org:
compressed-jsonl: .notes.json.gz
embeddings-file: .note_embeddings.pt
index-header-entries: true
input-files:
- ~/first_from_config.org
- ~/second_from_config.org
input-filter:
- '.org'
- ~/notes/.org
enable-offline-chat: false
search-type:
asymmetric:
cross-encoder: cross-encoder/ms-marco-MiniLM-L-6-v2
encoder: sentence-transformers/msmarco-MiniLM-L-6-v3
version: 0.15.0
File: tests/data/markdown/main_readme.md
Main Readme
Allow natural language search, chat with your documents using transformer based models
This is a test markdown file with multiple, nested child entries.
Dependencies
- Python3
- Miniconda
Installation
pip install khojRun
Load ML model, generate embeddings and expose API to query specified org-mode files
python3 main.py --input-files ~/Notes/Schedule.org ~/Notes/Incoming.org --verboseUse
**Khoj via API**
- Query:
GEThttp://localhost:42110/api/search?q="What is the meaning of life" - Update Index:
GEThttp://localhost:42110/api/update - Khoj API Docs
*Khoj via Web*
- Open browser to http://localhost:42110
- Enter query in search box
Acknowledgments
- MiniLM Model for Asymmetric Text Search. See (SBert Documentation)[https://www.sbert.net/examples/applications/retrieve_rerank/README.html]
- OpenAI CLIP Model for Image Search. See SBert Documentation
File: .devcontainer/devcontainer.json
{
"name": "Khoj Development Environment",
"build": {
"dockerfile": "Dockerfile",
"context": "..", // Build context is the project root
"args": {
"PYTHON_VERSION": "3.12"
}
},
"forwardPorts": [
42110
],
"containerEnv": {
"USE_EMBEDDED_DB": "True"
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.black-formatter",
"ms-python.mypy-type-checker",
"ms-python.isort",
"esbenp.prettier-vscode",
"GitHub.copilot",
"GitHub.copilot-chat",
"GitHub.vscode-pull-request-github",
"github.vscode-github-actions",
"unifiedjs.vscode-mdx"
],
"settings": {
"python.defaultInterpreterPath": "/opt/venv/bin/python",
"python.formatting.provider": "black",
"python.linting.enabled": true,
"python.linting.mypyEnabled": true,
"python.linting.mypyArgs": [
"--config-file=pyproject.toml"
],
"mypy.configFile": "pyproject.toml",
"isort.args": [
"--profile",
"black",
"--filter-files"
],
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
}
}
},
"postCreateCommand": "scripts/dev_setup.sh --devcontainer",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
},
"remoteUser": "vscode"
}
File: .devcontainer/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Khoj",
"type": "debugpy",
"request": "launch",
"module": "src.khoj.main",
"console": "integratedTerminal",
"justMyCode": false,
"sudo": true,
"args": [
"-v",
"--anonymous-mode",
"--non-interactive",
"--port=42110"
],
"envFile": "${workspaceFolder}/.env",
"env": {
"KHOJ_ADMIN_EMAIL": "admin",
"KHOJ_ADMIN_PASSWORD": "admin",
"USE_EMBEDDED_DB": "true",
"KHOJ_DEBUG": "true",
"KHOJ_TELEMETRY_DISABLED": "true",
"PROMPTRACE_DIR": "${workspaceFolder}/promptrace"
}
}
]
}
File: .github/ISSUE_TEMPLATE/bug-report.yml
name: "🪲 Bug Report"
labels: ["fix"]
body:
- type: "markdown"
attributes:
value: |
> [!IMPORTANT]
> To save time for both you and us, try follow these guidelines before submitting a new issue:
> 1. Check if there is an existing issue tracking your bug on our Github.
> 2. When unsure if your issue is an actual bug, first discuss it on a Github discussion or the #bugs channel of our Discord server.
> These steps avoid opening issues which are duplicate or not actual bugs.
- type: "checkboxes"
id: "server"
attributes:
label: "Server"
options:
- label: "Cloud (https://app.khoj.dev)"
required: false
- label: "Self-Hosted Docker"
required: false
- label: "Self-Hosted Python package"
required: false
- label: "Self-Hosted source code"
required: false
validations:
required: true
- type: "checkboxes"
id: "clients"
attributes:
label: "Clients"
options:
- label: "Web browser"
required: false
- label: "Desktop/mobile app"
required: false
- label: "Obsidian"
required: false
- label: "Emacs"
required: false
- label: "WhatsApp"
required: false
validations:
required: true
- type: "checkboxes"
id: "os"
attributes:
label: "OS"
options:
- label: "Windows"
required: false
- label: "macOS"
required: false
- label: "Linux"
required: false
- label: "Android"
required: false
- label: "iOS"
required: false
validations:
required: true
- type: "input"
id: "version"
attributes:
label: "Khoj version"
If using the cloud service, you can input, latest.\n
If self-hosting - please make sure to run the latest version of Khoj before reporting any issues as it may have already been fixed."
validations:
required: true
- type: "textarea"
id: "description"
attributes:
label: "Describe the bug"
validations:
required: true
- type: "textarea"
id: "current"
attributes:
label: "Current Behavior"
Please include full errors, uncaught exceptions, stack traces, screenshots and other relevant logs."
validations:
required: true
- type: "textarea"
id: "expected"
attributes:
label: "Expected Behavior"
validations:
required: true
- type: "textarea"
id: "reproduction"
attributes:
label: "Reproduction Steps"
code, if applicable.\n\n
For more complex issues, provide a link to a repository with the smallest sample that reproduces
the bug.\n
If the issue can be replicated without code, please provide a clear, step-by-step description of
the actions or conditions necessary to reproduce it. Any screenshots are also appreciated.\n
Avoid including business logic or unrelated details, as this makes diagnosis more difficult.\n\n
Whether it's a sequence of actions, code samples, or specific conditions, ensure that the steps
are clear enough to be easily followed and replicated."
validations:
required: true
- type: "textarea"
id: "workaround"
attributes:
label: "Possible Workaround"
validations:
required: false
- type: "textarea"
id: "context"
attributes:
label: "Additional Information"
Providing context helps us come up with a solution that is most useful in the real-world use case.\n
For example if self-hosting, provide environment details like OS versin, Docker version etc."
validations:
required: false
- type: "input"
id: "discussion_link"
attributes:
label: "Link to Discord or Github discussion"
This will help to keep history of why this bug exists."
validations:
required: falseFile: .github/ISSUE_TEMPLATE/feature-request.yml
name: "🙋 Feature Request"
labels: ["upgrade"]
body:
- type: "markdown"
attributes:
value: |
> [!IMPORTANT]
> To save time for both you and us, try follow these guidelines before submitting a feature request:
> 1. Check if there is an existing feature request that is similar to your on our Github.
> 2. We encourage you to first discuss your idea on a Github discussion or the #ideas channel of our Discord server.
> This step helps in understanding the new feature and determining if it's can be implemented at all.
Only proceed with this report if your idea was approved after the GitHub/Discord discussion.
- type: "textarea"
id: "description"
attributes:
label: "Describe the feature"
validations:
required: true
- type: "textarea"
id: "use-case"
attributes:
label: "Use Case"
validations:
required: true
- type: "textarea"
id: "solution"
attributes:
label: "Proposed Solution"
validations:
required: false
- type: "textarea"
id: "additional_info"
attributes:
label: "Additional Information"
validations:
required: false
- type: "input"
id: "discussion_link"
attributes:
label: "Link to Discord or Github discussion"
This will help to keep history of why this feature request exists."
validations:
required: falseFile: .github/workflows/build_khoj_el.yml
melpa quality checks like checkdoc, byte-compile, package-lint for khoj.el
using melpazoid: https://github.com/riscy/melpazoid
name: build khoj.el
on:
push:
branches:
- 'master'
- 'release/1.x'
paths:
- src/interface/emacs/.el
- .github/workflows/build_khoj_el.yml
pull_request:
branches:
- 'master'
- 'release/1.x'
paths:
- src/interface/emacs/.el
- .github/workflows/build_khoj_el.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.11
uses: actions/setup-python@v1
with: { python-version: 3.11 }
- name: ⏬️ Install Dependencies
run: |
python -m pip install --upgrade pip
sudo apt-get install emacs && emacs --version
git clone https://github.com/riscy/melpazoid.git ~/melpazoid
pip install ~/melpazoid
- name: 🌡️ Validate Khoj.el
env:
# Khoj recipe from https://github.com/melpa/melpa/pull/8321/files
RECIPE: (khoj :fetcher github :repo "khoj-ai/khoj" :files ("src/interface/emacs/*.el"))
EXIST_OK: true
LOCAL_REPO: ${{ github.workspace }}
run: echo $GITHUB_REF && make -C ~/melpazoid
File: .github/workflows/desktop.yml
name: desktop
on:
push:
tags:
- ""
branches:
- 'master'
- 'release/1.x'
paths:
- src/interface/desktop/*
- .github/workflows/desktop.yml
jobs:
build:
name: 🖥️ Build, Release Desktop App
runs-on: ubuntu-latest
env:
TODESKTOP_ACCESS_TOKEN: ${{ secrets.TODESKTOP_ACCESS_TOKEN }}
TODESKTOP_EMAIL: ${{ secrets.TODESKTOP_EMAIL }}
defaults:
run:
shell: bash
working-directory: src/interface/desktop
steps:
- name: ⬇️ Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: ⤵️ Install Node
uses: actions/setup-node@v3
with:
node-version: "lts/*"
- name: ⚙️ Setup Desktop Build
run: |
yarn
npm install @todesktop/cli
sed -i "s/\"id\": \"\"/\"id\": \"${{ secrets.TODESKTOP_ID }}\"/g" todesktop.json
- name: ⚙️ Build Desktop App
run: |
npx todesktop build
# - name: 📦 Release Desktop App
# if: startsWith(github.ref, 'refs/tags/')
# run: |
# npx todesktop release --latest --force
- name: ⤵️ Get Desktop Apps
if: startsWith(github.ref, 'refs/tags/')
run: |
build_no=`npx todesktop builds --latest | tail -n 1 | awk -F'/' '{print $NF}'`
sleep 900 # wait for 15 minutes for the build to be available
wget https://download.khoj.dev/builds/$build_no/mac/dmg/arm64 -O khoj-${{ github.ref_name }}-arm64.dmg
wget https://download.khoj.dev/builds/$build_no/mac/dmg/x64 -O khoj-${{ github.ref_name }}-x64.dmg
wget https://download.khoj.dev/builds/$build_no/windows/nsis/x64 -O khoj-${{ github.ref_name }}-x64.exe
wget https://download.khoj.dev/builds/$build_no/linux/deb/x64 -O khoj-${{ github.ref_name }}-x64.deb
wget https://download.khoj.dev/builds/$build_no/linux/appImage/x64 -O khoj-${{ github.ref_name }}-x64.AppImage
- name: ⏫ Upload Mac ARM App
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: khoj-${{ github.ref_name }}-arm64.dmg
path: src/interface/desktop/khoj-${{ github.ref_name }}-arm64.dmg
- name: ⏫ Upload Mac x64 App
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: khoj-${{ github.ref_name }}-x64.dmg
path: src/interface/desktop/khoj-${{ github.ref_name }}-x64.dmg
- name: ⏫ Upload Windows App
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: khoj-${{ github.ref_name }}-x64.exe
path: src/interface/desktop/khoj-${{ github.ref_name }}-x64.exe
- name: ⏫ Upload Debian App
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: khoj-${{ github.ref_name }}-x64.deb
path: src/interface/desktop/khoj-${{ github.ref_name }}-x64.deb
- name: ⏫ Upload Linux App Image
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: khoj-${{ github.ref_name }}-x64.AppImage
path: src/interface/desktop/khoj-${{ github.ref_name }}-x64.AppImageFile: .github/workflows/dockerize.yml
name: dockerize
on:
push:
tags:
- ""
branches:
- master
- release/1.x
paths:
- src/khoj/*
- src/interface/web/**
- pyproject.toml
- Dockerfile
- prod.Dockerfile
- computer.Dockerfile
- docker-compose.yml
- .github/workflows/dockerize.yml
workflow_dispatch:
inputs:
tag:
default: 'dev'
khoj:
type: boolean
default: true
khoj-cloud:
type: boolean
default: true
khoj-computer:
type: boolean
default: true
env:
Tag Image with tag name on release
else with user specified tag (default 'dev') if triggered via workflow
else with run_id if triggered via a pull request
else with 'pre' (if push to master) or 'pre-1x' (if push to release/1.x)
DOCKER_IMAGE_TAG: ${{ github.ref_type == 'tag' && github.ref_name || github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name == 'release/1.x' && 'pre-1x' || 'pre' }}
jobs:
build:
name: Publish Khoj Docker Images
strategy:
fail-fast: false
matrix:
include:
- image: 'local'
platform: linux/amd64
runner: ubuntu-latest
- image: 'local'
platform: linux/arm64
runner: ubuntu-linux-arm64
- image: 'cloud'
platform: linux/amd64
runner: ubuntu-latest
- image: 'cloud'
platform: linux/arm64
runner: ubuntu-linux-arm64
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
# Get all history to correctly infer Khoj version using hatch
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.PAT }}
- name: Get App Version
id: hatch
run: echo "version=$(pipx run hatch version)" >> $GITHUB_OUTPUT
- name: 🧹 Delete huge unnecessary tools folder
run: rm -rf /opt/hostedtoolcache
- name: 📦 Build and Push Docker Image
uses: docker/build-push-action@v4
if: (matrix.image == 'local' && github.event_name == 'workflow_dispatch') && github.event.inputs.khoj == 'true' || (matrix.image == 'local' && github.event_name == 'push')
with:
context: .
file: Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ env.DOCKER_IMAGE_TAG }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
build-args: |
VERSION=${{ steps.hatch.outputs.version }}
PORT=42110
cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.platform}}
labels: |
org.opencontainers.image.description=Khoj AI - Your second brain powered by LLMs and Neural Search
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
- name: 📦️⛅️ Build and Push Cloud Docker Image
uses: docker/build-push-action@v4
if: (matrix.image == 'cloud' && github.event_name == 'workflow_dispatch') && github.event.inputs.khoj-cloud == 'true' || (matrix.image == 'cloud' && github.event_name == 'push')
with:
context: .
file: prod.Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}-cloud:${{ env.DOCKER_IMAGE_TAG }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
build-args: |
VERSION=${{ steps.hatch.outputs.version }}
PORT=42110
cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.platform}}
labels: |
org.opencontainers.image.description=Khoj AI Cloud - Your second brain powered by LLMs and Neural Search
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
- name: 📦️️💻 Build and Push Computer for Khoj
uses: docker/build-push-action@v4
if: github.event_name == 'workflow_dispatch' && github.event.inputs.khoj-computer == 'true' && matrix.image == 'local'
with:
context: .
file: computer.Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}-computer:${{ env.DOCKER_IMAGE_TAG }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
cache-from: type=gha,scope=computer-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=computer-${{ matrix.platform }}
labels: |
org.opencontainers.image.description=Khoj AI Computer - A computer for your second brain to operate
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} manifest:
needs: build
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.PAT }}
- name: Create and Push Local Manifest
if: github.event.inputs.khoj == 'true' || github.event_name == 'push'
run: |
# Only put "latest.*" tag on stable releases (i.e 1.x, 2.x+)
if [[ "${{ env.DOCKER_IMAGE_TAG }}" =~ ^[1-9]\.[0-9]+\.[0-9]+$ ]]; then
LATEST_TAG="latest"
else
LATEST_TAG="${{ env.DOCKER_IMAGE_TAG }}"
fi
docker buildx imagetools create \
-t ghcr.io/${{ github.repository }}:${{ env.DOCKER_IMAGE_TAG }} \
-t ghcr.io/${{ github.repository }}:${LATEST_TAG} \
ghcr.io/${{ github.repository }}:${{ env.DOCKER_IMAGE_TAG }}-amd64 \
ghcr.io/${{ github.repository }}:${{ env.DOCKER_IMAGE_TAG }}-arm64
- name: Create and Push Cloud Manifest
if: github.event.inputs.khoj-cloud == 'true' || github.event_name == 'push'
run: |
# Only put "latest.*" tag on stable releases (i.e 1.x, 2.x+)
if [[ "${{ env.DOCKER_IMAGE_TAG }}" =~ ^[1-9]\.[0-9]+\.[0-9]+$ ]]; then
LATEST_TAG="latest"
else
LATEST_TAG="${{ env.DOCKER_IMAGE_TAG }}"
fi
docker buildx imagetools create \
-t ghcr.io/${{ github.repository }}-cloud:${{ env.DOCKER_IMAGE_TAG }} \
-t ghcr.io/${{ github.repository }}-cloud:${LATEST_TAG} \
ghcr.io/${{ github.repository }}-cloud:${{ env.DOCKER_IMAGE_TAG }}-amd64 \
ghcr.io/${{ github.repository }}-cloud:${{ env.DOCKER_IMAGE_TAG }}-arm64
- name: Create and Push Computer Manifest
if: github.event.inputs.khoj-computer == 'true'
run: |
docker buildx imagetools create \
-t ghcr.io/${{ github.repository }}-computer:${{ env.DOCKER_IMAGE_TAG }} \
-t ghcr.io/${{ github.repository }}-computer:${{ github.ref_type == 'tag' && 'latest' || env.DOCKER_IMAGE_TAG }} \
ghcr.io/${{ github.repository }}-computer:${{ env.DOCKER_IMAGE_TAG }}-amd64 \
ghcr.io/${{ github.repository }}-computer:${{ env.DOCKER_IMAGE_TAG }}-arm64File: .github/workflows/dockerize_telemetry_server.yml
name: dockerize telemetry server
on:
push:
branches:
- master
paths:
- src/telemetry/**
- .github/workflows/dockerize_telemetry_server.yml
pull_request:
branches:
- master
paths:
- src/telemetry/**
- .github/workflows/dockerize_telemetry_server.yml
workflow_dispatch:
env:
DOCKER_IMAGE_TAG: ${{ github.ref == 'refs/heads/master' && 'latest' || github.event.pull_request.number }}
jobs:
build:
name: Build Docker Image, Push to Container Registry
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.PAT }}
- name: 📦 Build and Push Docker Image
uses: docker/build-push-action@v2
with:
context: src/telemetry
file: src/telemetry/Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}-telemetry:${{ env.DOCKER_IMAGE_TAG }}
secrets: |
"POSTHOG_API_KEY=${{ secrets.POSTHOG_API_KEY }}"File: .github/workflows/github_pages_deploy.yml
name: deploy documentation
on:
push:
branches:
- 'master'
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
environment:
name: github-pages
url: https://docs.khoj.dev
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# 👇 Build steps
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: lts/*
cache: yarn
cache-dependency-path: documentation/yarn.lock
- name: Install dependencies
run: |
cd documentation
yarn install --frozen-lockfile --non-interactive
- name: Build
run: |
cd documentation
yarn build
# 👆 Build steps
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# 👇 Specify build output path
path: documentation/build
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
File: .github/workflows/pre-commit.yml
name: pre-commit
on:
pull_request:
branches:
- master
- release/1.x
paths:
- src/**
- tests/**
- config/**
- pyproject.toml
- .pre-commit-config.yml
- .github/workflows/test.yml
push:
branches:
- master
- release/1.x
paths:
- src/khoj/**
- tests/**
- config/**
- pyproject.toml
- .pre-commit-config.yml
- .github/workflows/test.yml
jobs:
test:
name: Setup Application and Lint
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python 3.11
run: uv python install 3.11
- name: ⏬️ Install Dependencies
run: |
sudo apt update && sudo apt install -y libegl1
- name: ⬇️ Install Application
env:
UV_INDEX: "https://download.pytorch.org/whl/cpu"
UV_INDEX_STRATEGY: "unsafe-best-match"
CUDA_VISIBLE_DEVICES: ""
run: uv sync --all-extras
- name: 🌡️ Validate Application
run: uv run pre-commit run --hook-stage manual --allFile: .github/workflows/pypi.yml
name: pypi
on:
push:
tags:
- ""
branches:
- 'master'
- 'release/1.x'
paths:
- src/khoj/*
- src/interface/web/**
- pyproject.toml
- .github/workflows/pypi.yml
pull_request:
branches:
- 'master'
- 'release/1.x'
paths:
- src/khoj/**
- src/interface/web/**
- pyproject.toml
- .github/workflows/pypi.yml
workflow_dispatch:
jobs:
publish:
name: Publish Python Package to PyPI
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python 3.11
run: uv python install 3.11.12
- name: ⬇️ Install Server
run: uv sync --all-extras
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: ⬇️ Install Web Client
run: |
bun install
bun pypiciexport
working-directory: src/interface/web
- name: ⚙️ Build Python Package
run: |
# Setup Environment for Reproducible Builds
export PYTHONHASHSEED=42
export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
rm -rf dist
# Build PyPI Package
uv build
- name: 🌡️ Validate Python Package
run: |
# Validate PyPi Package
uv tool run check-wheel-contents dist/*.whl --ignore W002,W004
uv tool run twine check dist/*
- name: ⏫ Upload Python Package Artifacts
uses: actions/upload-artifact@v4
with:
name: khoj
path: dist/khoj-*.whl
- name: 📦 Publish Python Package to PyPI
if: startsWith(github.ref, 'refs/tags') || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/release/1.x'
uses: pypa/gh-action-pypi-publish@release/v1.12
with:
skip-existing: true
print-hash: trueFile: .github/workflows/release.yml
name: release
on:
push:
tags:
- "*"
workflow_dispatch:
inputs:
version:
required: true
type: string
jobs:
publish_obsidian_plugin:
name: 💎 Publish Obsidian Plugin
runs-on: ubuntu-latest
permissions:
contents: write
defaults:
run:
shell: bash
working-directory: src/interface/obsidian
steps:
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: "lts/*"
- name: ⚙️ Build Obsidian Plugin
run: |
yarn
yarn run build --if-present
- name: ⏫ Upload Obsidian Plugin main.js
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: main.js
path: src/interface/obsidian/main.js
- name: ⏫ Upload Obsidian Plugin manifest.json
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: manifest.json
path: src/interface/obsidian/manifest.json
- name: ⏫ Upload Obsidian Plugin styles.css
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: styles.css
path: src/interface/obsidian/styles.css
- name: 🌈 Create Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
generate_release_notes: true
files: |
src/interface/obsidian/main.js
src/interface/obsidian/manifest.json
src/interface/obsidian/styles.cssFile: .github/workflows/run_evals.yml
name: eval
on:
Run on every release
push:
tags:
- "*"
Allow manual triggers from GitHub UI
workflow_dispatch:
inputs:
khoj_mode:
required: true
default: 'default'
type: choice
options:
- general
- default
- research
dataset:
required: true
default: 'frames'
type: choice
options:
- frames
- simpleqa
- gpqa
- math500
sample_size:
required: false
default: 200
type: number
sandbox:
required: false
default: 'terrarium'
type: choice
options:
- terrarium
- e2b
chat_model:
required: false
default: 'gemini-2.5-flash'
type: string
max_research_iterations:
required: false
default: 5
type: number
openai_api_key:
required: false
default: ''
type: string
openai_base_url:
required: false
default: 'https://api.openai.com/v1'
type: string
randomize:
required: false
default: 'true'
type: choice
options:
- 'false'
- 'true'
dataset_seed:
required: false
default: ''
type: string
jobs:
eval:
runs-on: ubuntu-latest
strategy:
matrix:
# Use input from manual trigger if available, else run all combinations
khoj_mode: ${{ github.event_name == 'workflow_dispatch' && fromJSON(format('["{0}"]', inputs.khoj_mode)) || fromJSON('["general", "default", "research"]') }}
dataset: ${{ github.event_name == 'workflow_dispatch' && fromJSON(format('["{0}"]', inputs.dataset)) || fromJSON('["frames", "gpqa"]') }}
services:
postgres:
image: pgvector/pgvector:pg18
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python
run: uv python install 3.10
- name: Get App Version
id: hatch
run: |
# Mask relevant workflow inputs as secret early
OPENAI_API_KEY=$(jq -r '.inputs.openai_api_key' $GITHUB_EVENT_PATH)
echo ::add-mask::$OPENAI_API_KEY
echo OPENAI_API_KEY="$OPENAI_API_KEY" >> $GITHUB_ENV
# Get app version from hatch
echo "version=$(pipx run hatch version)" >> $GITHUB_OUTPUT
- name: ⏬️ Install Dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
# install dependencies
sudo apt update && sudo apt install -y git libegl1 sqlite3 libsqlite3-dev libsqlite3-0 ffmpeg libsm6 libxext6
# install terrarium for code sandbox
git clone https://github.com/khoj-ai/terrarium.git && cd terrarium && npm install --legacy-peer-deps && mkdir pyodide_cache
- name: ⬇️ Install Application
env:
UV_INDEX: "https://download.pytorch.org/whl/cpu"
UV_INDEX_STRATEGY: "unsafe-best-match"
CUDA_VISIBLE_DEVICES: ""
run: |
sed -i 's/dynamic = \["version"\]/version = "${{ steps.hatch.outputs.version }}"/' pyproject.toml
uv sync --all-extras
- name: 📝 Run Eval
env:
KHOJ_MODE: ${{ matrix.khoj_mode }}
SAMPLE_SIZE: ${{ github.event_name == 'workflow_dispatch' && inputs.sample_size || 200 }}
BATCH_SIZE: "20"
RANDOMIZE: ${{ github.event_name == 'workflow_dispatch' && inputs.randomize || 'true' }}
DATASET_SEED: ${{ github.event_name == 'workflow_dispatch' && inputs.dataset_seed || github.run_id }}
KHOJ_LLM_SEED: "42"
KHOJ_URL: "http://localhost:42110"
KHOJ_DEFAULT_CHAT_MODEL: ${{ github.event_name == 'workflow_dispatch' && inputs.chat_model || 'gemini-2.5-flash' }}
KHOJ_RESEARCH_ITERATIONS: ${{ github.event_name == 'workflow_dispatch' && inputs.max_research_iterations || 10 }}
KHOJ_AUTO_READ_WEBPAGE: ${{ github.event_name == 'workflow_dispatch' && inputs.auto_read_webpage || 'false' }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
OPENAI_BASE_URL: ${{ github.event_name == 'workflow_dispatch' && inputs.openai_base_url || 'https://api.openai.com/v1' }}
SERPER_DEV_API_KEY: ${{ matrix.dataset != 'math500' && secrets.SERPER_DEV_API_KEY || '' }}
OLOSTEP_API_KEY: ${{ matrix.dataset != 'math500' && secrets.OLOSTEP_API_KEY || ''}}
FIRECRAWL_API_KEY: ${{ matrix.dataset != 'math500' && secrets.FIRECRAWL_API_KEY || '' }}
HF_TOKEN: ${{ secrets.HF_TOKEN }}
E2B_API_KEY: ${{ inputs.sandbox == 'e2b' && secrets.E2B_API_KEY || '' }}
E2B_TEMPLATE: ${{ vars.E2B_TEMPLATE }}
KHOJ_ADMIN_EMAIL: khoj
KHOJ_ADMIN_PASSWORD: khoj
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
USE_EMBEDDED_DB: "true"
KHOJ_TELEMETRY_DISABLE: "True" # To disable telemetry for tests
run: |
set -euo pipefail
# Start Khoj server in background
# Capture stdout/stderr to a log for debugging if startup fails
uv run khoj --anonymous-mode --non-interactive -vv > khoj_server.log 2>&1 &
KHOJ_PID=$!
echo "Started Khoj (PID=$KHOJ_PID)"
# Start code sandbox
npm install pm2
NODE_ENV=production npm run ci --prefix terrarium
# Wait for server to be ready
timeout=120
while ! curl -s http://localhost:42110/api/health > /dev/null; do
# If process died, surface logs and fail fast
if ! kill -0 "$KHOJ_PID" 2>/dev/null; then
echo "Khoj process exited before becoming healthy. Logs:" >&2
sed -n '1,200p' khoj_server.log >&2 || true
exit 1
fi
if [ $timeout -le 0 ]; then
echo "Timed out waiting for Khoj server. Partial logs:" >&2
sed -n '1,200p' khoj_server.log >&2 || true
exit 1
fi
echo "Waiting for Khoj server... ($timeout s left)"
sleep 2
timeout=$((timeout-2))
done
echo "Khoj server is healthy"
# Run evals
uv run python tests/evals/eval.py -d ${{ matrix.dataset }}
- name: Upload Results
if: always() # Upload results even if tests fail
uses: actions/upload-artifact@v4
with:
name: eval-results-${{ steps.hatch.outputs.version }}-${{ matrix.khoj_mode }}-${{ matrix.dataset }}
path: |
*_evaluation_results_*.csv
*_evaluation_summary_*.txt
khoj_server.log
- name: Display Results
if: always()
run: |
# Read and display summary
echo "## Evaluation Summary of Khoj on ${{ matrix.dataset }} in ${{ matrix.khoj_mode }} mode" >> $GITHUB_STEP_SUMMARY
echo "**$(head -n 1 *_evaluation_summary_*.txt)**" >> $GITHUB_STEP_SUMMARY
echo "- Khoj Version: ${{ steps.hatch.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- Chat Model: ${{ inputs.chat_model || 'gemini-2.5-flash' }}" >> $GITHUB_STEP_SUMMARY
echo "- Code Sandbox: ${{ inputs.sandbox || 'terrarium' }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
tail -n +2 *_evaluation_summary_*.txt >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
# Display in logs too
echo "===== EVALUATION RESULTS ====="
cat *_evaluation_summary_*.txtFile: .github/workflows/test.yml
name: test
on:
pull_request:
branches:
- master
- release/1.x
paths:
- src/khoj/**
- tests/**
- '!tests/evals/'
- config/
- pyproject.toml
- .pre-commit-config.yml
- .github/workflows/test.yml
push:
branches:
- master
- release/1.x
paths:
- src/khoj/**
- tests/**
- '!tests/evals/'
- config/
- pyproject.toml
- .pre-commit-config.yml
- .github/workflows/test.yml
jobs:
test:
name: Run Tests
runs-on: ubuntu-latest
container: ubuntu:26.04
strategy:
fail-fast: false
matrix:
python_version:
- '3.10'
- '3.11'
- '3.12'
services:
postgres:
image: pgvector/pgvector:pg18
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python ${{ matrix.python_version }}
run: uv python install ${{ matrix.python_version }}
- name: ⏬️ Install Dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt update && apt install -y git libegl1 libgl1 sqlite3 libsqlite3-dev libsqlite3-0 ffmpeg libsm6 libxext6
- name: ⬇️ Install Postgres
env:
DEBIAN_FRONTEND: noninteractive
run : |
apt install -y postgresql postgresql-client postgresql-server-dev-all
- name: ⬇️ Install Application
env:
UV_INDEX: "https://download.pytorch.org/whl/cpu"
UV_INDEX_STRATEGY: "unsafe-best-match"
CUDA_VISIBLE_DEVICES: ""
run: sed -i 's/dynamic = \["version"\]/version = "0.0.0"/' pyproject.toml && uv sync --all-extras
- name: 🧪 Test Application
env:
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
run: uv run pytest
timeout-minutes: 10File: .github/workflows/test_khoj_el.yml
name: test khoj.el
on:
push:
branches:
- 'master'
- 'release/1.x'
paths:
- src/interface/emacs/.el
- src/interface/emacs/tests/.el
- .github/workflows/test_khoj_el.yml
pull_request:
branches:
- 'master'
- 'release/1.x'
paths:
- src/interface/emacs/.el
- src/interface/emacs/tests/.el
- .github/workflows/test_khoj_el.yml
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
emacs_version:
- 28.2
- 29.4
- 30.2
- snapshot
steps:
- uses: purcell/setup-emacs@master
with:
version: ${{ matrix.emacs_version }}
- uses: actions/checkout@v3
- name: 🧪 Test Khoj.el
run: |
# Run ERT tests on khoj.el
emacs -batch
--eval "(progn
(require 'package)
(push '("melpa" . "https://melpa.org/packages/\") package-archives)
(package-initialize)
(unless package-archive-contents (package-refresh-contents))
(unless (package-installed-p 'transient) (package-install 'transient))
(unless (package-installed-p 'dash) (package-install 'dash))
(unless (package-installed-p 'org) (package-install 'org))
)"
-l ert
-l ./src/interface/emacs/khoj.el
-l ./src/interface/emacs/tests/khoj-tests.el
-f ert-run-tests-batch-and-exit