[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1251":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":23,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":16,"starSnapshotCount":16,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},1251,"dexter","remoteoss\u002Fdexter","remoteoss","A fast, full-featured Elixir LSP optimized for large codebases.","",null,"Go",331,20,3,11,0,4,10,47,12,3.97,"MIT License",false,"main",[],"2026-06-12 02:00:25","# Dexter\n\n\u003Cimg src=\"dexter-logo.png\" width=\"200\" height=\"200\" alt=\"Dexter logo\" \u002F>\n\nA fast, full-featured Elixir LSP optimized for large Elixir codebases.\n\n## Table of contents\n\n- [Features](#features)\n- [Quick start](#quick-start)\n- [Editor setup](#editor-setup)\n  - [VS Code \u002F Cursor](#vs-code--cursor)\n    - [Configuration](#configuration)\n  - [Neovim (0.11+)](#neovim-011)\n    - [Configuring format on save](#configuring-format-on-save)\n  - [Neovim (with nvim-lspconfig — \\\u003C 0.11)](#neovim-with-nvim-lspconfig---011)\n  - [Zed](#zed)\n  - [Emacs](#emacs)\n    - [Eglot](#eglot)\n      - [Emacs version \\>= 30](#emacs-version--30)\n      - [Emacs version \\\u003C= 29](#emacs-version--29)\n    - [lsp-mode](#lsp-mode)\n  - [Helix](#helix)\n- [Why build another LSP?](#why-build-another-lsp)\n- [Performance](#performance)\n- [CLI usage](#cli-usage)\n  - [Index a project](#index-a-project)\n  - [Look up definitions](#look-up-definitions)\n  - [Find references](#find-references)\n  - [Reindexing files manually](#reindexing-files-manually)\n- [Hover documentation](#hover-documentation)\n  - [Cursor-position-aware resolution](#cursor-position-aware-resolution)\n- [Rename](#rename)\n  - [Modules](#modules)\n  - [Functions](#functions)\n  - [Variables](#variables)\n- [Lightning-fast formatting](#lightning-fast-formatting)\n- [LSP options](#lsp-options)\n- [Index database location (.dexter\u002F)](#index-database-location-dexter)\n- [Debugging](#debugging)\n- [Development (building from source)](#development-building-from-source)\n- [Releasing](#releasing)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n- **Fast indexing** — cold index completes in ~11s on a 57k-file Elixir monorepo, ~100ms on Oban, ~300ms on the Elixir standard library (measured on an M1 MacBook Pro). After your first index, incremental indexing makes sure that you never have to reindex the whole codebase again.\n- **Go-to-definition** — jump to any module, function, type, or variable definition. Resolves aliases, imports, `defdelegate` chains, `use` injections, and the Elixir stdlib. Handles all definition forms: `def`, `defp`, `defmacro`, `defprotocol`, `defimpl`, `defstruct`, and more.\n- **Go-to-references** — find all usages of a function or module across the codebase, including through `import`, `use` chains, and `defdelegate`.\n- **Hover documentation** — `@doc`, `@moduledoc`, `@typedoc`, and `@spec` annotations rendered as Markdown when you hover over a symbol.\n- **Autocompletion** — modules, functions, types, and variables with full snippet support. Resolves through aliases, imports, `use` injections, and the Elixir stdlib. Works for qualified calls (`MyApp.Accounts.|`), bare function calls, and module prefixes.\n- **Rename** — rename modules, functions, and variables with automatic file renaming when the convention is followed.\n- **No compilation required** — the index is built by parsing source files directly, not by compiling your project. Dexter works immediately on any codebase, even ones that don't compile.\n- **Monorepo and umbrella support** — a single index at the repository root covers all apps and shared libraries. Go-to-definition, find references, and rename work cross-project out of the box.\n- **Format on save** — formats `.ex`, `.exs`, and `.heex` files on save via a persistent Elixir process. Near-instant after the first save. Formatter plugins (Styler, Phoenix.LiveView.HTMLFormatter) are loaded from your project's `_build` — no install needed. Syntax errors are surfaced as diagnostics.\n- **Elixir stdlib indexing** — jump to `Enum`, `String`, `Mix`, and other bundled modules by indexing your local Elixir installation sources.\n- **Signature help** — parameter hints as you type function calls.\n- **Workspace symbols** — search for any module or function across the entire codebase.\n- **Call hierarchy** — navigate incoming and outgoing calls.\n- **Code actions** — add missing aliases with a single action.\n- **Document symbols** — outline view of all functions and modules in the current file.\n- **Document highlight** — highlight all occurrences of the symbol under the cursor.\n- **Variable support** — go-to-definition, rename, and completion for local variables via tree-sitter, with correct scoping across `case`, `with`, `for`, and other block constructs.\n- **Git branch switch detection** — automatically reindexes when you switch branches.\n\n\u003Cdetails>\n\u003Csummary>More features\u003C\u002Fsummary>\n\n- **Delegate following** — `defdelegate fetch_user(id), to: MyApp.Accounts.Finders.FetchUser, as: :find` jumps to `MyApp.Accounts.Finders.FetchUser.find`, respecting `as:` renames.\n- **Alias resolution** — `alias MyApp.Handlers.Foo`, `alias MyApp.Handlers.Foo, as: Cool`, `alias MyApp.Handlers.{Foo, Bar}`.\n- **Import resolution** — bare function calls resolved through `import` declarations.\n- **Type definitions** — `@type` and `@opaque` are indexed for go-to-definition and hover.\n- **Folding ranges** — collapse functions and modules in your editor.\n- **Monorepo-aware formatting** — walks up from the file to find the nearest `.formatter.exs`, so subprojects with their own formatter configs (including nested `subdirectories:` configs) just work.\n- **Heredoc awareness** — code examples in `@moduledoc`\u002F`@doc` are skipped.\n- **Module nesting** — correctly tracks `end` keywords to attribute functions to the right module.\n\n\u003C\u002Fdetails>\n\n## Quick start\n\n1. **Install Dexter.** Pick one:\n\n   ```sh\n   # via mise\n   mise plugin add dexter https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Fdexter.git && mise use -g dexter@latest\n\n   # via asdf\n   asdf plugin add dexter https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Fdexter.git && asdf install dexter latest && asdf set --home dexter latest\n   \n   # via Homebrew\n   brew install remoteoss\u002Ftap\u002Fdexter\n   ```\n\n   Or [build from source](#development-building-from-source).\n\n2. **Configure your editor** — see [Editor setup](#editor-setup) below.\n\n3. **Open an Elixir project.** Dexter indexes automatically the first time the LSP starts.\n\n## Editor setup\n\nDexter works with any editor that supports the Language Server Protocol. Below are setup instructions for the most common ones — if your editor isn't listed, point it at `dexter lsp` over stdio.\n\n### VS Code \u002F Cursor\n\nInstall the [Dexter VS Code Extension](https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=remoteoss.dexter-lsp).\n\nOr, if you prefer to install from source: [dexter-vscode](https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Fdexter-vscode?tab=readme-ov-file#development).\n\n#### Configuration\n\nIf you installed via Mise or ASDF, you're all done!\n\nBut if Dexter is not on your `PATH`, set the binary path in your editor settings:\n\n```json\n{\n  \"dexter.binary\": \"\u002FUsers\u002Fyou\u002F.local\u002Fshare\u002Fmise\u002Fshims\u002Fdexter\"\n}\n```\n\nTo enable format-on-save, update your VS Code\u002FCursor settings:\n\n```json\n\u002F\u002F global in your editor\n{\n  \"editor.formatOnSave\": true,\n}\n\n\u002F\u002F or, for Elixir specifically\n{\n  \"[elixir]\": {\n      \"editor.formatOnSave\": true,\n      \u002F\u002F you may need to set Dexter as your default Elixir formatter, depending on your setup\n      \"editor.defaultFormatter\": \"remoteoss.dexter-lsp\" \u002F\u002F \"remote-com-oss.dexter-lsp\" for Cursor\n  },\n  \"[phoenix-heex]\": { \"editor.formatOnSave\": true }\n}\n```\n\n### Neovim (0.11+)\n\nAdd to your LSP configuration (e.g., `after\u002Fplugin\u002Flsp.lua`):\n\n```lua\nvim.lsp.config('dexter', {\n  cmd = { 'dexter', 'lsp' },\n  root_markers = { '.dexter\u002Fdexter.db', '.dexter.db', '.git', 'mix.exs' },\n  filetypes = { 'elixir', 'eelixir', 'heex' },\n  init_options = {\n    followDelegates = true,  -- jump through defdelegate to the target function\n    -- stdlibPath = \"\",      -- override Elixir stdlib path (auto-detected)\n    -- debug = false,        -- verbose logging to stderr (view with :LspLog)\n  },\n})\n\nvim.lsp.enable 'dexter'\n```\n\nThat's it. Go-to-definition (`gd`, `\u003CC-]>`, or whatever you have mapped to `vim.lsp.buf.definition()`) will now use dexter alongside any other attached LSP servers.\n\nIf you want a dedicated binding just for dexter:\n\n```lua\nvim.keymap.set(\"n\", \"\u003Cleader>va\", function()\n  vim.lsp.buf.definition({ filter = function(client) return client.name == \"dexter\" end })\nend)\n```\n\n#### Configuring format on save\n\nIf you want formatting on save, you'll need to configure a `PreWrite` autocmd. You can do something like this:\n\n```lua\nvim.api.nvim_create_autocmd('LspAttach', {\n  group = vim.api.nvim_create_augroup('my.lsp', {}),\n\n  callback = function(args)\n    local opts = { remap = false }\n    local client = assert(vim.lsp.get_client_by_id(args.data.client_id))\n    local builtin = require(\"telescope.builtin\")\n\n    -- along with your other config\n\n    if client:supports_method('textDocument\u002Fformatting') then\n      -- the most important part\n      vim.api.nvim_create_autocmd('BufWritePre', {\n        buffer = args.buf,\n        callback = function()\n          vim.lsp.buf.format({ bufnr = args.buf, id = client.id, timeout_ms = 5000 })\n        end,\n      })\n    end\n  end\n})\n```\n\n### Neovim (with nvim-lspconfig — \u003C 0.11)\n\n```lua\nlocal lspconfig = require(\"lspconfig\")\nlocal configs = require(\"lspconfig.configs\")\n\nconfigs.dexter = {\n  default_config = {\n    cmd = { \"dexter\", \"lsp\" }, -- update this if you don't have Dexter in your PATH\n    filetypes = { \"elixir\", \"eelixir\", \"heex\" },\n    root_dir = lspconfig.util.root_pattern(\".dexter\u002Fdexter.db\", \".dexter.db\", \"mix.exs\", \".git\"),\n  },\n}\n\nlspconfig.dexter.setup({})\n```\n\n\n### Zed\n\nSee the [Zed docs](https:\u002F\u002Fzed.dev\u002Fdocs\u002Flanguages\u002Felixir#using-dexter) for full details. Enable Dexter in your Zed `settings.json`:\n\n```json\n{\n  \"languages\": {\n    \"Elixir\": {\n      \"language_servers\": [\"dexter\", \"!elixir-ls\", \"!expert\"]\n    },\n    \"EEx\": {\n      \"language_servers\": [\"dexter\", \"!elixir-ls\", \"!expert\"]\n    },\n    \"HEEx\": {\n      \"language_servers\": [\"dexter\", \"!elixir-ls\", \"!expert\"]\n    }\n  }\n}\n```\n\nIf you already have Dexter installed via [mise](https:\u002F\u002Fmise.jdx.dev\u002F), the extension will use your local binary from PATH instead of downloading.\n\nTo override the binary path manually, add this to your `settings.json`:\n\n```json\n{\n  \"lsp\": {\n    \"dexter\": {\n      \"binary\": {\n        \"path\": \"\u002FUsers\u002Fyou\u002F.local\u002Fshare\u002Fmise\u002Fshims\u002Fdexter\", \u002F\u002F or wherever `which dexter` points to\n        \"arguments\": [\"lsp\"]\n      }\n    }\n  }\n}\n```\n\n### Emacs\n\nThe emacs instructions assume you're using **use-package**.\n\n#### Eglot\n\n##### Emacs version >= 30\n\n```emacs-lisp\n(use-package eglot\n  :ensure t\n\n  :config\n  (setf (alist-get '(elixir-mode elixir-ts-mode heex-ts-mode)\n                   eglot-server-programs\n                   nil nil #'equal)\n        '(\"\u002Fpath\u002Fto\u002Fdexter\" \"lsp\")) ;; wherever `which dexter` points to\n\n  ;; other config\n  )\n```\n\n##### Emacs version \u003C= 29\n\n```emacs-lisp\n(use-package eglot\n  :ensure t\n\n  :config\n  (setf (alist-get 'elixir-mode eglot-server-programs)\n        '(\"\u002Fpath\u002Fto\u002Fdexter\" \"lsp\")) ;; wherever `which dexter` points to\n\n  ;; other config\n  )\n```\n\n#### lsp-mode\n\n```emacs-lisp\n(use-package lsp-mode\n  :ensure t\n  :hook ((elixir-mode elixir-ts-mode heex-ts-mode) . lsp-deferred)\n  :config\n  (add-to-list 'lsp-disabled-clients 'elixir-ls)\n\n  (lsp-register-client\n   (make-lsp-client\n    :new-connection (lsp-stdio-connection\n                     '(\"\u002Fpath\u002Fto\u002Fdexter\" \"lsp\")) ;; wherever `which dexter` points to\n    :activation-fn (lsp-activate-on \"elixir\")\n    :server-id 'dexter-elixir)))\n```\n\n### Helix\n\nAdd to your LSP configuration in `~\u002F.config\u002Fhelix\u002Flanguages.toml`:\n\n```toml\n[language-server.dexter]\ncommand = \"dexter\"\nargs = [\"lsp\"]\n\n[[language]]\nname = \"elixir\"\nlanguage-servers = [\"dexter\"]\n```\n\n## Why build another LSP?\n\nRemote has one of the largest Elixir codebases in existence (at least that we're aware of), now around 57k files. As our codebase has grown, we've had more and more struggles with language servers. We had found that they simply couldn't keep up with such a large codebase. On large codebases like ours, existing LSPs take hours to index, and even after indexing, operations like go-to-definition and go-to-references are still slow. On top of that, changing branches means a whole new round of indexing. The result has been frustration. Many of us on the engineering team had all but given up on the idea of ever having a working LSP.\n\nDexter is designed with speed and efficiency as core guiding principles. It takes a different approach from other Elixir LSPs, parsing source files directly as text and storing everything in SQLite so lookups are fast. The speed difference is noticeable on codebases of all sizes. Although Dexter isn't fully aware of the compiled state of the code like compilation-based LSPs, some clever parsing and deferring complex macro following to runtime allow it to get very close. In fact, you probably wouldn't even notice this limitation if you weren't reading this.\n\n## Performance\n\nMeasured on a 57k-file Elixir monorepo (330k definitions, 2.7M references) on a 32GB M1 MacBook Pro:\n\n| Operation                     | Time  |\n| ----------------------------- | ----- |\n| Cold first-time index         | ~11s  |\n| Lookup (LSP or CLI)           | ~10ms |\n| Single file reindex (on save) | ~10ms |\n| Full reindex (no changes)     | ~2s   |\n| Format on save                | \u003C1ms  |\n\n## CLI usage\n\nThe CLI commands are available for scripting and manual use.\n\n### Index a project\n\n```sh\n# First time — indexes all .ex\u002F.exs files (including deps\u002F and the Elixir standard library)\ndexter init ~\u002Fcode\u002Fmy-elixir-project\n\n# Re-init from scratch (deletes existing index)\ndexter init --force ~\u002Fcode\u002Fmy-elixir-project\n\n# Print timing breakdown for each indexing phase (walk, parse, store)\ndexter init --profile ~\u002Fcode\u002Fmy-elixir-project\n```\n\nDexter auto-detects your Elixir installation. If it can't find it (e.g. a non-standard install, it's not in your `PATH`, etc.), set:\n\n```sh\nexport DEXTER_ELIXIR_LIB_ROOT=\"\u002Fpath\u002Fto\u002Felixir\u002Flib\"\n```\n\n### Look up definitions\n\n```sh\n# Find where a module is defined\ndexter lookup MyApp.Accounts\n# => \u002Fpath\u002Fto\u002Flib\u002Fmy_app\u002Faccounts.ex:1\n\n# Find where a function is defined (follows defdelegates by default)\ndexter lookup MyApp.Accounts fetch_user\n# => \u002Fpath\u002Fto\u002Flib\u002Fmy_app\u002Faccounts\u002Ffinders\u002Ffetch_user.ex:8\n\n# Don't follow defdelegates\ndexter lookup --no-follow-delegates MyApp.Accounts fetch_user\n# => \u002Fpath\u002Fto\u002Flib\u002Fmy_app\u002Faccounts.ex:5\n\n# Strict mode — exit 1 if exact function not found (no fallback to module)\ndexter lookup --strict MyApp.Accounts nonexistent\n# => (exit code 1)\n```\n\n### Find references\n\n```sh\n# Find all usages of a module\ndexter references MyApp.Accounts\n# => \u002Fpath\u002Fto\u002Flib\u002Fmy_app_web\u002Fuser_controller.ex:12\n# => \u002Fpath\u002Fto\u002Flib\u002Fmy_app\u002Fauth.ex:8\n\n# Find all usages of a specific function\ndexter references MyApp.Accounts fetch_user\n# => \u002Fpath\u002Fto\u002Flib\u002Fmy_app_web\u002Fuser_controller.ex:45\n```\n\nExits 1 with a message to stderr if no references are found.\n\n### Reindexing files manually\n\nThe LSP does this for you automatically, but if for some reason you need to, you can reindex files manually via the CLI.\n\n```sh\n# Re-index a single file (~10ms)\ndexter reindex \u002Fpath\u002Fto\u002Flib\u002Fmy_app\u002Faccounts.ex\n\n# Re-index the whole project (only re-parses changed files)\ndexter reindex ~\u002Fcode\u002Fmy-elixir-project\n```\n\nWhen running as an LSP server, dexter automatically:\n\n- Reindexes files on save (`textDocument\u002FdidSave`)\n- Runs an incremental reindex on startup\n- Watches `.git\u002FHEAD` for branch switches and reindexes when detected\n\n## Hover documentation\n\nDexter serves hover docs (`textDocument\u002Fhover`) for functions, modules, and types. When you hover over a symbol, it looks up the definition in the index and reads the `@doc`, `@moduledoc`, `@typedoc`, or `@spec` annotations from the source file.\n\nThe hover response shows the function signature (with `@spec` if present), followed by the doc string:\n\n```\ndef fetch_user(id, opts)\n@spec fetch_user(binary(), keyword()) :: {:ok, User.t()} | {:error, term()}\n\nFetches a user by ID. Options are passed to the underlying query.\n```\n\n### Cursor-position-aware resolution\n\nDexter resolves hover (and go-to-definition) based on which segment of a dotted expression your cursor is on:\n\n| Cursor position                              | Expression                  | Resolves to                  |\n| -------------------------------------------- | --------------------------- | ---------------------------- |\n| On `Accounts` in `MyApp.Accounts.list_users` | `MyApp.Accounts`            | The `MyApp.Accounts` module  |\n| On `list_users` in `MyApp.Accounts.list_users` | `MyApp.Accounts.list_users` | The `list_users` function  |\n| On `MyApp` in `MyApp.Accounts.list_users`    | `MyApp`                     | The `MyApp` module           |\n\n## Rename\n\nDexter supports renaming modules, functions, and variables across the codebase via `textDocument\u002Frename` (F2 in most editors).\n\n### Modules\n\nPlace your cursor on any segment of a module name and invoke rename. Dexter highlights just the last segment for editing — the parent namespace is preserved automatically. For example, renaming `Accounts` in `MyApp.Accounts` to `Users` renames the module to `MyApp.Users`.\n\n**What gets updated:**\n\n- The `defmodule` declaration\n- All aliases, imports, and uses referencing the module\n- All call sites\n- All submodules (renaming `MyApp.Foo` also renames `MyApp.Foo.Bar`, `MyApp.Foo.Baz`, etc.)\n\n**File renaming after a module rename:** If the source file follows the Elixir naming convention (module `MyApp.Accounts` → file `accounts.ex`), dexter renames the file alongside the module. For submodules, the containing directory segment is also renamed to match (e.g., renaming `MyApp.Companies` to `MyApp.Clients` moves `lib\u002Fcompanies\u002Fservices\u002Fdo_something.ex` → `lib\u002Fclients\u002Fservices\u002Fdo_something.ex`). After the rename, dexter opens the new file automatically if your editor supports `window\u002FshowDocument`.\n\n**When path renaming won't happen:** If the file name doesn't match the snake_case form of the module's last segment — for example, a file named `my_custom_name.ex` that defines `MyApp.Accounts` — the file stays in place and only the contents are updated.\n\nFiles not open in the editor are written directly to disk; open buffers receive edits via the LSP workspace edit response.\n\n### Functions\n\nPlace your cursor on a function name (qualified or bare) and invoke rename. Dexter updates:\n\n- All `def`\u002F`defp`\u002F`defmacro`\u002F`defguard`\u002Fetc. clauses\n- `@spec` and `@callback` annotations\n- Direct calls and pipe calls (`|> function_name`)\n- `import Module, only: [function_name: ...]` lines\n- Transitive call sites via `__using__` chains\n\nRenaming is blocked for functions defined in stdlib or deps.\n\n### Variables\n\nPlace your cursor on a local variable and invoke rename. Dexter uses tree-sitter to find all occurrences within the\nenclosing function scope and renames them in a single edit. This is file-local only.\n\nGo-to-definition also works for variables — it jumps to the first occurrence (pattern match or assignment) in scope.\n\n## Lightning-fast formatting\n\nDexter formats files on save via `textDocument\u002FwillSaveWaitUntil` using a persistent Elixir process per `.formatter.exs`. This persistent formatter server starts once when you open the first file in a project under a given `.formatter.exs`, so formatting is near-instant.\n\nPlugins ([`Styler`](https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Felixir-styler), `Phoenix.LiveView.HTMLFormatter`, etc.) are loaded from\nyour project's `_build\u002Fdev\u002Flib`. So as long as your formatter plugins are installed and compiled, everything is ready to\ngo.\n\nIf the persistent process can't start, dexter falls back to running `mix format` directly.\n\n**Syntax errors** found by the formatter are surfaced as LSP diagnostics pointing to the exact line and column, with a warning at the hint location (e.g. \"the `do` on line 52 does not have a matching `end`\"). Diagnostics clear on the next successful format (which again, is nearly instantaneous!).\n\n**Nested `.formatter.exs`:** Dexter walks up from the file to the mix root and uses the nearest `.formatter.exs`. A file in `config\u002F` uses `config\u002F.formatter.exs` if it exists (for projects using `subdirectories:`), falling back to the root config.\n\n**Elixir detection:** The `mix` and `elixir` binaries are derived from the same Elixir install used for stdlib detection, so the correct version is always used regardless of which tool manager you use (mise, asdf, etc.).\n\n## LSP options\n\nDexter reads `initializationOptions` from your editor configuration:\n\n- **`followDelegates`** (boolean, default: `true`): follow `defdelegate` targets on lookup.\n- **`stdlibPath`** (string): override the Elixir stdlib directory to index. Defaults to auto-detection; use this if your install is non-standard.\n- **`debug`** (boolean, default: `false`): enable verbose logging to stderr. Logs timing and resolution details for every definition, hover, references, and rename request. Can also be enabled via the `DEXTER_DEBUG=true` environment variable.\n\n## Index database location (.dexter\u002F)\n\nDexter creates `.dexter\u002Fdexter.db` at the root of your project when you start the LSP for the first time. But if you prefer, you can run `dexter init` yourself in the root of your project. Where you place it determines what gets indexed.\n\nThe `.dexter\u002F` folder includes its own `.gitignore` (containing `*`), so its contents are automatically ignored by git — no need to update your project's `.gitignore`.\n\nWhen the LSP server starts, it walks up from the project root looking for `.dexter\u002Fdexter.db`, preferring `.git` as the anchor point. This means if you initialised from the monorepo root, the server will find the right database even when Neovim's `rootUri` points to a sub-app (e.g. because `mix.exs` is there).\n\nIf you're upgrading from a pre-`.dexter\u002F` version of dexter, any existing `.dexter.db` file at your project root will be automatically deleted and rebuilt into the new `.dexter\u002F` folder on the next `dexter init` or LSP startup. You can also remove any `.dexter.db*` or `.dexter\u002F` entries from your `.gitignore`, as they are no longer needed.\n\n**Monorepo root (recommended if using an Elixir monorepo or umbrella structure)** — Put the index at the root of your repository, next to `.git`. This indexes everything: all apps, all shared libraries, and all deps. Go-to-definition works across the entire codebase.\n\n```sh\ncd ~\u002Fcode\u002Fmy-monorepo   # where .git lives\ndexter init .\n```\n\n**Single app** — Put the index inside a specific Mix project. Go-to-definition works within that app and its deps, but not across other apps in the monorepo.\n\n```sh\ncd ~\u002Fcode\u002Fmy-monorepo\u002Fapps\u002Fmy_app\ndexter init .\n```\n\n## Debugging\n\nIf something isn't working as expected, start by forcing a full reindex to rule out a stale\u002Fcorrupted index. It's\nunlikely that this is actually the problem, but it's better to have a clean slate just to be sure.\n\n```sh\ndexter init --force ~\u002Fcode\u002Fmy-elixir-project\n```\n\nIf the issue persists, enable debug mode to get verbose logs. You can do this in two ways:\n\n1. Set the `debug` option in your editor's LSP `initializationOptions` (see [LSP options](#lsp-options))\n2. Or set the `DEXTER_DEBUG=true` environment variable before launching your editor\n\nDebug mode logs timing and resolution details for every definition, hover, references, and rename request to stderr. In Neovim you can usually view these at `~\u002F.local\u002Fstate\u002Fnvim\u002Flsp.log`. In VS Code, you can see them in Output > Dexter.\n\nWhen [filing an issue](https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Fdexter\u002Fissues\u002Fnew), please include:\n\n- Your Dexter version (`dexter --version`)\n- Your Elixir version (`elixir --version`)\n- The debug logs from the failing operation\n- A minimal code snippet that reproduces the issue, if possible\n\n## Development (building from source)\n\nRequires Go 1.21+, SQLite, and Elixir.\n\n```sh\ngit clone https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Fdexter.git\ncd dexter\nmise install    # install dependencies\nmake build      # to build from source\nmake test       # to test\n```\n\n## Releasing\n\n```sh\n# 1. Create a release branch with the version bump\nmake release VERSION=0.2.0\n\n# 2. Push the branch and merge it into main\n\n# 3. Tag and push the tag\nmake tag VERSION=0.2.0\n```\n\nThis updates the version in `internal\u002Fversion\u002Fversion.go` on a release branch. After merging to main, `make tag` creates and pushes the git tag. Users can then upgrade via mise:\n\n```sh\nmise plugin update dexter && mise install dexter@latest\n```\n\nThe plugin update step is required to pick up newly tagged releases. Without it, `mise install dexter@latest` will resolve against a stale list.\n\nIf the release changes how Elixir files are parsed or what gets stored in the index (e.g. a new definition kind, a change to delegate resolution), also bump `IndexVersion` in `internal\u002Fversion\u002Fversion.go`. Dexter will automatically rebuild the index when users upgrade to a binary with a higher `IndexVersion` — no manual `dexter init --force` required.\n\n## Contributing\n\nDexter is a new project and we're actively expanding its capabilities. If you come across code that causes issues, do let us know so we can support it. Bug reports, pull requests, and feature suggestions are all welcome on [GitHub](https:\u002F\u002Fgithub.com\u002Fremoteoss\u002Fdexter). We try to address issues quickly and would love to hear what you'd like to see next.\n\n## License\n\nDexter is released under the [MIT License](LICENSE).\n","Dexter 是一个为大型 Elixir 代码库优化的快速且功能全面的语言服务器协议（LSP）。其核心功能包括快速索引、跳转到定义、查找引用、悬停文档、自动补全和重命名等，特别强调了对 Elixir 特有语言特性的支持如模块别名解析、`use`注入及标准库处理。Dexter 通过直接解析源文件来构建索引，无需编译整个项目即可工作，这使得它非常适合用于需要高效开发体验的大规模 Elixir 项目中，尤其是在团队协作环境或持续集成流水线中提高开发者效率。",2,"2026-06-11 02:42:34","CREATED_QUERY"]