Chat with a Claude agent over your codebase β with semantic code search.
An open-source AI Ask platform for your codebase.
Sign in with GitHub, chat with a Claude engine over one mounted codebase, backed by a
Qdrant indexer and per-user long-term memory.
Bring your own API keys, docker compose up, and go.
π dexiask.com
Dexiask is a small, self-hostable stack for asking questions about a codebase and getting rich, streamed answers from a Claude agent that can read your files, search the web, and run semantic code search over an indexed repository.
It stays deliberately focused β one workspace (your mounted codebase), no teams, no projects, no config UI β while supporting multiple users:
- Claude agent (ask mode, read-only)
- Sign in with a GitHub token (OAuth optional) β per-user conversation history (in the sidebar, paginated), memory, and MCP servers, with admin/member roles and admin-only invites (or run with no auth configured for a single local dev user)
- Per-user repo access β each member only sees the repos their own GitHub token grants, validated inside the indexer
- Streaming chat with rich rendering (code, mermaid, math)
- File upload (attach files to a message)
- Custom skills (drop-in
SKILL.mdpacks) - Semantic code indexer (Qdrant + Voyage), default branch, plus optional LLM-generated domain docs searchable alongside code
- Long-term memory β the agent records observations and a "dream" judge consolidates them into durable user/repo/global memory injected into later answers
- Two-way Slack bot (Socket Mode)
Index once, ask anything. Point it at a repo, index the default branch a single time, and from then on ask questions in plain language β "where is auth handled?", "what calls this function?", "how does a request flow end to end?". No wiki, no docs, no comments required: the code is the source of truth, and the agent reads it directly via semantic + lexical search.
- No documentation debt. Docs rot the moment they're written; the index tracks the actual committed code, so answers reflect what's really there β not a stale README from six months ago.
- Decentralized knowledge. New joiners, on-call engineers, PMs, or anyone outside the original authors can get accurate answers without interrupting the one person who "knows that part." The codebase stops being tribal knowledge locked in a few heads.
- Speed. Seconds to an answer instead of an afternoon spent grepping, reading,
or waiting on a Slack reply. Ask from the browser, or
@mentionthe bot right in Slack where the question came up. - Onboarding & code archaeology. Ramp on an unfamiliar service, understand a
legacy module, or trace "why is this here?" through
git blame/git logβ all from a conversation. - Yours, self-hosted. Runs on your machine with your keys; your code never leaves your infrastructure beyond the model/embedding API calls you opt into.
βββββββββββββββ
Browser ββHTTP/SSEβββΆ web β Next.js β
BFF β (login + β
β chat + β¦) β
ββββββββ¬βββββββ
β SSE
ββββββββΌβββββββ βββββββββββββ
Slack ββSocket ModeβββββββΆ backend βββMCPβββΆβ indexer ββββΆ Qdrant
β (Go) β β (Python) ββββΆ git mirrors (FS)
β chat Β· SSE β βββββββββββββ
β auth βββMCPβββΆβββββββββββββ
β attachmentsβ β memory ββββΆ FS volume
β Postgres β β (Go) β
ββββββββ¬βββββββ βββββββββββββ
β Agent Job Protocol
βΌ
βββββββββββββββ
β engine β
β (Python, β
β Claude SDK)β
βββββββββββββββ
- web β Next.js BFF + login + chat/indexer/memory UI. The only thing the browser talks to.
- backend β Go. Streams chat as SSE, bridges to the engine over the Agent Job Protocol, handles GitHub OAuth + sessions, stores conversations/messages/ attachments in Postgres, proxies the indexer + memory, and runs the Slack bot.
- engine β Python. Runs the Claude Agent SDK; reads
ANTHROPIC_API_KEYfrom env; loads skill packs from/skills. - indexer β Python. Semantic + lexical code search (and optional generated domain docs) over the mounted codebase, exposed to the engine as an MCP server. Qdrant for vectors, the filesystem for git mirrors.
- memory β Go. FS-backed user/repo/global memory exposed as an MCP server, with a periodic "dream" consolidation judge. No database.
- qdrant / postgres β vector store and relational store.
- ollama (optional,
COMPOSE_PROFILES=local) β local text + embedding models baked into the image, so everything runs with no API keys.
One shared /workspace mount is the codebase the agent reads and the indexer
indexes (read-only for the indexer).
Prerequisites: Docker + Docker Compose, an Anthropic API key, and a Voyage AI key (for code embeddings) β or no keys at all with local mode below.
git clone <your-fork> dexiask && cd dexiask
cp .env.example .env
# β edit .env: set ANTHROPIC_API_KEY and VOYAGE_API_KEY,
# and point DEXIASK_WORKSPACE_PATH at the repo you want to explore.
make up # or: docker compose up --build -dOpen http://localhost:25051 and start chatting. make logs to tail, make down
to stop, make clean to wipe the DB + index.
No Anthropic or Voyage key? Enable the Ollama sidecar and run entirely locally:
cp .env.example .env
# β edit .env: uncomment COMPOSE_PROFILES=local (leave the key vars blank)
make upThe sidecar serves a small local text model (qwen2.5:1.5b) and local code
embeddings (qwen3-embedding:0.6b). Both models are baked into the sidecar
image at build time β the first build downloads ~2 GB; nothing is downloaded
after the stack is up. With no keys configured the engine and indexer fall back
to the sidecar automatically (the engine switches to a compact local agent loop
sized for small models β first answer in ~30s on a laptop CPU, follow-ups in
seconds); if you later add real keys they take over (hosted keys always win).
Worth knowing:
- Quality/speed: a small local model is noticeably less capable than Claude β
fine for exploring a codebase, not a Claude replacement. For better answers at
a higher resource cost, set a bigger non-reasoning model, e.g.
DEXIASK_LOCAL_TEXT_MODEL=qwen2.5:7b(~4.7 GB). Avoid reasoning models (qwen3, deepseek-r1): they burn the whole turn "thinking" on CPU. - Resources: runs CPU-only on a regular laptop β ~4 GB free disk for the
image and ~3 GB RAM while running. The sidecar pins generation to 4 threads
(
DEXIASK_OLLAMA_THREADS) β counter-intuitively much faster than all cores on laptops. On an NVIDIA GPU host, uncomment the GPU block on theollamaservice indocker-compose.ymlfor faster responses. - Tools: the local agent gets every indexer/memory MCP tool by default
(
DEXIASK_LOCAL_REMOTE_TOOLS=*). If a small model stops calling tools and answers from thin air, narrow it to a short list (e.g.semantic_search,get_chunk,read_range) β fewer tools are easier to follow. - CPU-only boxes: set
DEXIASK_DREAM_INTERVAL=0to skip the hourly memory consolidation model runs. - Re-index on switch: local and hosted embeddings share a dimension but not a
vector space β switching providers requires
make clean(or a per-repo reindex). - Models are overridable via
DEXIASK_LOCAL_TEXT_MODEL/DEXIASK_LOCAL_EMBED_MODEL(image build args; the embedding model must produceDEXIASK_EMBEDDING_DIM-sized vectors).
The indexer indexes the default branch of any git repo under your mounted
/workspace.
- Set
DEXIASK_WORKSPACE_PATHin.envto a directory containing the repo. - Open the Indexer page in the UI β Add repo (git URL or a path under
/workspace) β Reindex. - Ask the agent a question about the code β it will call
semantic_searchautomatically (you'll see the tool card in the chat).
Indexing uses one central git token an admin sets on the Indexer page β
Git access token β paste a GitHub PAT β Save. It is held server-side by the
indexer, persisted 0600, and never returned to the browser β injected as an
Authorization header via GIT_CONFIG_*, never placed in a mirror's stored remote
URL. Clear it any time with Clear.
Members still only see the repos their own GitHub token can access: the indexer
validates every member's token against each repo via the GitHub API itself (cached),
so a forged header β or a direct hit on the indexer port β only ever reveals what the
caller's token grants. Admins are unrestricted; local / non-GitHub repos are admin-only.
This gating (across semantic_search, repo-scoped tools, and repo listings) turns on
when DEXIASK_INTERNAL_TOKEN is set on both the backend and the indexer.
Dexiask is multi-user. The primary login is a GitHub token: paste a GitHub PAT on
/login β it's validated against the GitHub API, stored AES-GCM encrypted, and becomes
your identity (also used for per-user repo access). Auth turns on once the session infra
is configured β set DEXIASK_SESSION_SECRET, DEXIASK_TOKEN_ENC_KEY
(openssl rand -hex 32), and web AUTH_ENABLED=true. Leave them blank to run in
dev-fallback mode (a single local admin user, no login) β the zero-config default.
GitHub OAuth is optional on top: create a GitHub OAuth app (callback
http://localhost:25051/api/auth/callback) and set DEXIASK_GITHUB_CLIENT_ID /
_SECRET + DEXIASK_OAUTH_CALLBACK_URL to add a one-click sign-in button.
Two roles β admin and member. The first user to sign in bootstraps as admin;
everyone else needs an admin-created invite (keyed by GitHub login, consumed on first
login) or login is refused. Members get chat, and their own history / memory / MCP
servers. Admin-only: the Team page (invites + roster), MCP-server management, indexer
mutations (reindex / register / the central git token), and memory edits + consolidation.
Conversations, MCP servers, and memory are all scoped per user.
The agent records observations about you and your repos during chat. A periodic
dream run (an LLM "judge") consolidates them into durable user / repo / global
memory, which is injected into later answers so the assistant improves over time. Browse
what it remembers β and trigger a consolidation manually β on the Memory page.
Backed by the memory service on the memory-data volume (no database); tune with
DEXIASK_DREAM_MODEL / DEXIASK_DREAM_INTERVAL (0 disables the loop).
Beyond the built-in code indexer, you can connect your own MCP servers so
the agent gains their tools. Open the MCP page β add a server (name,
transport http or sse, URL, and optional request headers for auth) and
toggle it Enabled. Every enabled server is injected into each of your chat
turns alongside the indexer + memory. Servers are scoped per user; header values
(which may hold auth secrets) are stored in Postgres in plaintext.
Drop a folder into skills/ containing a SKILL.md and restart the engine
(make restart). The engine appends every skills/*/SKILL.md to the agent's system
prompt. Bundled packs: code-explain, helpful, voice. See skills/README.md.
Dexiask can run a two-way Slack bot over Socket Mode (no public URL needed).
- Create a Slack app β enable Socket Mode β generate an App-Level Token
(
xapp-β¦) with scopeconnections:write. - Under OAuth & Permissions, add bot scopes:
app_mentions:read,chat:write,im:history,im:read,im:write. Install the app and copy the Bot Token (xoxb-β¦). - Under Event Subscriptions, subscribe to bot events:
app_mention,message.im. - Put both tokens in
.env(SLACK_APP_TOKEN,SLACK_BOT_TOKEN) andmake restart. - DM the bot or
@mentionit in a channel β its reply streams into the thread.
Leave the tokens blank to keep the bot disabled.
Everything is env-driven β see .env.example for the full list. The essentials:
| Variable | Purpose |
|---|---|
COMPOSE_PROFILES=local |
Enable the Ollama sidecar β run with no API keys (see Local mode) |
ANTHROPIC_API_KEY |
Claude engine credential (required unless local mode) |
VOYAGE_API_KEY |
Indexer embedding credential (required unless local mode) |
DEXIASK_LOCAL_TEXT_MODEL / _LOCAL_EMBED_MODEL |
Models baked into the local sidecar image (defaults qwen2.5:1.5b / qwen3-embedding:0.6b) |
DEXIASK_MODEL |
Claude model for ask mode (default claude-sonnet-5) |
DEXIASK_WORKSPACE_PATH |
Host codebase mounted at /workspace |
DEXIASK_SESSION_SECRET / _TOKEN_ENC_KEY |
Session signing + GitHub-token encryption β enables auth (token login) |
DEXIASK_GITHUB_CLIENT_ID / _SECRET |
Add optional GitHub OAuth on top of token login (blank = token login only) |
DEXIASK_INTERNAL_TOKEN |
Shared backendβindexer secret; enables per-user repo gating in the indexer |
DEXIASK_ENABLE_DOMAIN_DOCS |
Generate + index LLM domain docs during indexing |
DEXIASK_DREAM_MODEL / _DREAM_INTERVAL |
Memory consolidation model + cadence (0 disables) |
SLACK_APP_TOKEN / SLACK_BOT_TOKEN |
Enable the Slack bot |
Each service is independently developable β see the per-service README.md
(backend/, engine/, indexer/, memory/, web/).
make test # run every suite: Go (backend + memory) + engine + indexer + web
make test-backend # Go unit tests
make test-engine # pytest (engine)
make test-indexer # pytest (indexer)
make test-web # vitest
make lint # vet + ruff + eslintMIT.