@javierkaiser/opencode-indexing 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,12 +5,166 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [0.2.1] - 2026-10-15
9
+
10
+ ### Added
11
+
12
+ - **`opencode plugin add @javierkaiser/opencode-indexing` is now the documented
13
+ install.** It was already possible — the package was published and exported
14
+ `./tui` — but the README told people to run `npm install` and edit
15
+ `opencode.json` by hand, which puts the package in whatever directory they were
16
+ standing in and never tells OpenCode about it. The CLI command installs into
17
+ OpenCode's own cache, records the entry, and brings the update and removal path
18
+ (`plugin check`, `plugin update`, `plugin remove`) with it.
19
+ - **The installer has a package mode**, and picks between the two from where it
20
+ runs: a checkout installs the working tree, an installed copy installs the
21
+ published package. `npx @javierkaiser/opencode-indexing` therefore does the
22
+ right thing with no flags, including the permission rules and the restart that
23
+ `plugin add` alone does not do.
24
+ - `bin` in `package.json`, so `npx` has something to run.
25
+ - The plugin options and `ignoreKiloConfig` are documented in the README. The
26
+ option existed in the code and had tests, but appeared in no documentation.
27
+
28
+ ### Fixed
29
+
30
+ - **"No Kilo index found" for a workspace that has one.** The server plugin is
31
+ instantiated for the directory the service runs in, so every RPC that omitted a
32
+ `directory` described *that* project. `kilo.discover` took no directory at all,
33
+ which is why opening the palette in one project and importing reported nothing
34
+ while the footer, using the same client and passing the directory, looked
35
+ correct. `kilo.discover` and `settings.test` now accept a directory, and the
36
+ palette, the settings page and the index actions all send the caller's. The
37
+ directory is injected once by `bindWorkspace` rather than passed at each call
38
+ site, so a new workspace-scoped RPC is correct by default instead of correct by
39
+ remembering.
40
+ - **The tools read and indexed the service's directory.** All seven were pinned to
41
+ the plugin instance's root, so `indexing_search` in a session answered from
42
+ another codebase — results from the wrong project read as plausible — and
43
+ `indexing_import` refused an index that was sitting right there. They now use
44
+ `context.directory`, with the instance root as the fallback for hosts that do
45
+ not report one.
46
+ - **`@lancedb/lancedb` could never load, so no Kilo index was ever importable
47
+ from LanceDB.** `apache-arrow` is that package's *peerDependency*, and the
48
+ installer runs `npm install --omit=peer`, which drops peers from the tree: the
49
+ native binary loaded and then threw `Cannot find module 'apache-arrow'` on first
50
+ use. It is now declared explicitly. This also broke `vectorStore: lancedb`
51
+ outright.
52
+ - **An unreadable index was reported as a missing one.** Discovery swallowed
53
+ backend failures, so "Kilo is not running here" and "Kilo is not installed here"
54
+ both surfaced as *No Kilo index found*. It now names the path it found and the
55
+ reason it could not be read, in `indexing_status`, `indexing_build`,
56
+ `indexing_config`, `settings test kilo`, the import tool and the empty-state
57
+ toast. `indexing_build` is the one that matters most: with nothing reported, a
58
+ build in a workspace whose Kilo index could not be read re-embedded everything
59
+ without saying why.
60
+ - **`apache-arrow` is declared in `package.json`, not only in the installer.**
61
+ It is a *peer* of `@lancedb/lancedb`, and the two install paths disagreed about
62
+ peers: `install.mjs` runs `npm install --omit=peer`, which drops them, while
63
+ the npm-based install OpenCode performs keeps them. Declaring it makes the
64
+ dependency true for both instead of true for whichever path happened to be
65
+ tested.
66
+ - The installer no longer keeps its own copy of the dependency list; it derives
67
+ the installed `package.json` from the published one. That duplication is how
68
+ `apache-arrow` came to be declared for one install path and missing from the
69
+ other.
70
+ - `--package` deletes a previously copied plugin. Both sources define
71
+ `id: "opencode.indexing"` and the config directory is scanned automatically, so
72
+ leaving both would load the plugin twice.
73
+
74
+ ## [0.2.0] - 2026-10-14
75
+
76
+ ### Added
77
+
78
+ - **`gemini`, `voyage` and `openrouter` are implemented.** They were selectable in
79
+ the provider list, passed every validation gate, and then threw
80
+ `Unsupported embedder provider` once indexing had already started and been billed
81
+ for a probe. A test asserted that they were unimplemented, which pinned the gap in
82
+ place.
83
+ - **The model catalog is visible.** The TUI model field is now a chooser built from
84
+ the catalog, with a *Custom* entry for anything not listed and for providers with
85
+ no catalog at all. `indexing_config` lists every model with its dimension and
86
+ whether Kilo also knows it — which is the whole answer to whether a free import
87
+ will work.
88
+ - **Per-model input ceilings and per-provider batch limits.** The ceilings differ by
89
+ more than an order of magnitude (`mxbai-embed-large` takes 512 tokens,
90
+ `voyage-code-4` takes 32,000), and one global constant truncated every chunk past
91
+ the smallest model's limit. Batch limits are now per provider: OpenAI caps a
92
+ request at 300,000 tokens whatever the item count, Gemini accepts a fixed number of
93
+ items, Voyage has both.
94
+ - `voyage-code-4`, `voyage-4`, `voyage-4-large`, `voyage-4-lite`,
95
+ `gemini-embedding-2` and Ollama's `bge-m3` in the catalog, each marked as not
96
+ present in Kilo's registry so it is clear they cannot be imported.
97
+ - `indexing_status` warns before a model change re-embeds the workspace, with the
98
+ point count, rather than after the embeddings have been paid for.
99
+
100
+ ### Changed
101
+
102
+ - **A search that cannot read part of the corpus now fails instead of shrinking.**
103
+ An embedding failure per profile was pushed onto a list rendered as "Warnings", and
104
+ the results that came back looked exactly like a complete set whose missing half
105
+ ranked lower. An index holding points whose profile cannot be embedded is now an
106
+ error naming the profile. An index with no points is not an error, so the common
107
+ case is unaffected.
108
+ - Changing provider clears the model, because model ids are namespaced per provider.
109
+ The previous code claimed to do this and did not, so switching to Voyage produced
110
+ `voyage` + `codestral-embed-2505`, which outranks the provider default.
111
+ - The stored dimension of a previous index is no longer inherited across a provider
112
+ change. A 1536-wide Mistral index made any new model look 1536-dimensional, and the
113
+ inherited number was then persisted as though it had been measured, making the
114
+ mismatch self-consistent and invisible on every later run.
115
+ - The `apiKeys` merge is derived from the incoming keys instead of a hand-written list
116
+ of provider names, which silently dropped any credential added to the shape but not
117
+ to the list.
118
+ - The settings page reports which providers have credentials instead of deriving it
119
+ from two booleans, which reported "none configured" for a Gemini, Voyage,
120
+ OpenRouter, Ollama or OpenAI-compatible setup.
121
+ - `indexing_config` and `settings test kilo` pass a target profile to the Kilo source
122
+ scan. Without it every source was reported as compatible, including ones that would
123
+ be refused a moment later.
124
+ - Ollama and Voyage are sent `truncate` / `truncation: false`, so an over-long chunk
125
+ fails instead of being silently shortened into a valid-looking wrong vector.
126
+ - Embedding results are placed by `data[].index` where the provider supplies it.
127
+ OpenAI documents the field rather than promising response order, and its own samples
128
+ fetch by it; a repeated or out-of-range index is now an error.
129
+ - The catalog's `openrouter` Gemini entry names `google/gemini-embedding-2-preview`,
130
+ which is what Kilo writes. It said `google/gemini-embedding-001`, and since the
131
+ profile comparison is exact string equality the drift was invisible and made every
132
+ such index un-importable.
133
+
134
+ ### Fixed
135
+
136
+ - The model field is cleared on a provider change in the TUI as well as the chat
137
+ command; both paths had the same stale-model bug.
138
+ - `searchCode` and `getStatus` had no unit tests — only the e2e and cli scripts
139
+ exercised them, and those assert nothing. Both have tests now.
140
+
141
+ ### Documentation
142
+
143
+ - The README states how far each provider has actually been tested. `mistral` has
144
+ touched its real API; `openrouter` reached the API and authenticated but was
145
+ refused by the key's own spend limit; `openai`, `gemini`, `voyage`,
146
+ `openai-compatible` and `ollama` have never contacted a real endpoint and are
147
+ covered only by fixtures written alongside their adapters. The same fact is
148
+ surfaced in the model chooser and in `indexing_config`, and a test pins the list so
149
+ the claim cannot quietly widen.
9
150
 
10
151
  ## [0.1.1] - 2026-10-14
11
152
 
153
+ ### Added
154
+
155
+ - `src/lancedb-support.ts` reports up front that LanceDB ships one native binary per
156
+ platform and that there is no `lancedb-darwin-x64` build (there is no WASM
157
+ fallback), so the embedded store is unavailable on macOS on Intel — instead of
158
+ failing later with a module-not-found error.
159
+
12
160
  ### Changed
13
161
 
162
+ - **The own index now defaults to embedded LanceDB** instead of inheriting Kilo's
163
+ `vectorStore`. Kilo's setting is read as `kiloVectorStore`: it still decides where
164
+ an *import* reads from, and it is still reported, but it no longer decides where
165
+ the own index writes to. Dropping that inheritance is reported as a warning rather
166
+ than applied silently, so an existing Qdrant own index is not discovered to be
167
+ empty.
14
168
  - npm releases are now automated: pushing a `v*` tag triggers a GitHub Actions
15
169
  workflow that publishes through npm trusted publishing (OIDC), with no
16
170
  long-lived token.
@@ -37,6 +191,7 @@ First public release.
37
191
  - Cross-platform installer (`install.mjs`, plus `install.sh` / `install.ps1`
38
192
  wrappers).
39
193
 
40
- [Unreleased]: https://github.com/Javierkaiser/opencode-indexing/compare/v0.1.1...HEAD
194
+ [Unreleased]: https://github.com/Javierkaiser/opencode-indexing/compare/v0.2.0...HEAD
195
+ [0.2.0]: https://github.com/Javierkaiser/opencode-indexing/releases/tag/v0.2.0
41
196
  [0.1.1]: https://github.com/Javierkaiser/opencode-indexing/releases/tag/v0.1.1
42
197
  [0.1.0]: https://github.com/Javierkaiser/opencode-indexing/releases/tag/v0.1.0
package/README.md CHANGED
@@ -26,44 +26,83 @@ index is still installed.
26
26
 
27
27
  ## Install
28
28
 
29
- ### From npm (recommended)
29
+ ### With the OpenCode CLI (recommended)
30
30
 
31
31
  ```bash
32
- npm install @javierkaiser/opencode-indexing
32
+ opencode plugin add @javierkaiser/opencode-indexing
33
33
  ```
34
34
 
35
- Then reference it from `opencode.json`:
35
+ That is the whole install. OpenCode downloads the package into its own cache and
36
+ records it in the global `plugins` array, and it loads both halves of the plugin:
37
+ the server side (`index.ts`, which registers the tools) and the terminal UI
38
+ (`tui.ts`, which adds the prompt-footer indicator and the `/indexing` page).
39
+
40
+ Update and remove it with the same command family:
41
+
42
+ ```bash
43
+ opencode plugin check # is there a newer version?
44
+ opencode plugin update # install it
45
+ opencode plugin remove @javierkaiser/opencode-indexing
46
+ ```
47
+
48
+ `plugin add` installs the plugin but knows nothing about its tools, so it does
49
+ not write permission rules. Add this one to `opencode.json` to keep the host
50
+ asking before the only tool that writes your settings file:
36
51
 
37
52
  ```jsonc
38
53
  {
39
- "plugins": [
40
- { "package": "@javierkaiser/opencode-indexing" }
54
+ "permissions": [
55
+ { "action": "indexing_config_set", "resource": "*", "effect": "ask" }
41
56
  ]
42
57
  }
43
58
  ```
44
59
 
45
- ### Global installer (alternative)
60
+ The other six tools only read. OpenCode's base policy already allows everything
61
+ (`{ "action": "*", "resource": "*", "effect": "allow" }`), so they need no rule;
62
+ write them out only if you want to tighten the set.
63
+
64
+ ### One command, permissions included
46
65
 
47
- The installer is cross-platform; it only needs Node >= 22.6.
66
+ To skip the manual rule:
48
67
 
49
68
  ```bash
50
- # Linux / macOS
51
- ./install.sh
69
+ npx @javierkaiser/opencode-indexing
70
+ ```
52
71
 
53
- # Windows
54
- powershell -ExecutionPolicy Bypass -File .\install.ps1
72
+ The installer runs `opencode plugin add`, writes the permission rules, and
73
+ restarts the service. It picks its strategy from where it runs: from an installed
74
+ copy — an npx cache, an unpacked tarball — it installs the published package;
75
+ from a checkout it installs your working tree instead, so edits take effect on
76
+ restart with no publish in between. It prints which one it chose.
55
77
 
56
- # Any platform (the wrappers just call this)
57
- node install.mjs
58
- ```
78
+ | Flag | Effect |
79
+ | --- | --- |
80
+ | `--package [spec]` | Install the published package (default spec `@latest`) |
81
+ | `--local` | Copy this directory into the config dir (development) |
82
+ | `--skip-deps` | `--local` only: copy the files, install no dependencies |
83
+ | `--no-restart` | Do not restart the service |
59
84
 
60
- It copies the plugin to the global config directory (`$XDG_CONFIG_HOME/opencode` or `~/.config/opencode`, same path used on Windows), installs runtime deps (`ignore`, plus optional `@lancedb/lancedb@0.26.2` and the tree-sitter WASM packages), adds one `permissions` rule per tool to `opencode.json` (read tools `allow`, `indexing_config_set` `ask`), and restarts the OpenCode service.
85
+ `install.sh` and `install.ps1` are thin wrappers over it; PowerShell also accepts
86
+ `-Local`, `-Package`, `-Spec`, `-SkipDeps` and `-NoRestart`.
61
87
 
62
- Those are V2 rules — `{ "action": "indexing_search", "resource": "*", "effect": "allow" }` inside the `permissions` array. The older `permission` action map is a V1 shape that V2 ignores, so the installer removes any of its own entries from that map rather than leaving something that looks configured but grants nothing.
88
+ `--package` deletes any copied plugin it finds: both sources define the same
89
+ plugin id and the config directory is scanned automatically, so leaving both
90
+ would load the plugin twice.
63
91
 
64
- Options: `--skip-deps` (copy files only), `--no-restart`. PowerShell accepts `-SkipDeps` / `-NoRestart` too.
92
+ If no package manager is available, a `--local` install still copies the files
93
+ and the plugin runs with reduced features (line chunker instead of tree-sitter,
94
+ no LanceDB).
65
95
 
66
- If no package manager is available the copy still happens and the plugin runs with reduced features (line chunker instead of tree-sitter, no LanceDB).
96
+ ### Manual
97
+
98
+ To manage the directory yourself, point `opencode.json` at it. Relative paths
99
+ resolve from the config file containing the entry:
100
+
101
+ ```jsonc
102
+ {
103
+ "plugins": ["./plugins/opencode-indexing"]
104
+ }
105
+ ```
67
106
 
68
107
  ## How it works
69
108
 
@@ -176,11 +215,123 @@ Configurable from all three:
176
215
  - **Vector store** for the own index: Qdrant or LanceDB.
177
216
  - **Qdrant URL + API key** (local or remote) with connection test.
178
217
  - **LanceDB directory** with availability test.
179
- - **Embedding provider/model** (mistral, openai, ollama, openai-compatible, gemini, voyage, openrouter) and **API key**.
218
+ - **Embedding provider/model** (mistral, openai, ollama, openai-compatible, gemini, voyage, openrouter) and **API key**. The model is chosen from a catalog rather than typed blind. The model is chosen from a catalog rather than typed blind.
180
219
  - **Import from Kilo** toggle with live source detection ("Qdrant ws-… (31,261 pts) · LanceDB …").
181
220
  - **Auto-refresh on search** toggle.
182
221
  - Build / refresh / import actions and a status summary.
183
222
 
223
+ ### Embedding providers
224
+
225
+ All seven have an adapter. Every model below is in the catalog, which is what
226
+ supplies the dimension, the score threshold and the input ceiling; a model that
227
+ is not listed still works, and its dimension is probed from the provider on
228
+ first use. See the next section for how far each one has actually been tested.
229
+
230
+ | Provider | Default model | Also in the catalog | Input ceiling |
231
+ | --- | --- | --- | --- |
232
+ | `mistral` | `codestral-embed-2505` | `codestral-embed`, `mistral-embed` | 8,192 |
233
+ | `openai` | `text-embedding-3-small` | `text-embedding-3-large`, `text-embedding-ada-002` | 8,192 |
234
+ | `voyage` | `voyage-code-3` | **`voyage-code-4`**, `voyage-4`, `voyage-4-large`, `voyage-4-lite`, `voyage-3-lite` | **32,000** |
235
+ | `gemini` | `gemini-embedding-001` | **`gemini-embedding-2`**, `text-embedding-004`, `embedding-001` | 2,048 (001) / 8,192 (2) |
236
+ | `openrouter` | `openai/text-embedding-3-small` | `openai/text-embedding-3-large`, `google/gemini-embedding-2-preview` | 8,192 |
237
+ | `ollama` | `nomic-embed-text` | `mxbai-embed-large`, `all-minilm`, `bge-m3` | 512 – 8,192 |
238
+ | `openai-compatible` | none | whatever your endpoint serves | probed |
239
+
240
+ #### Getting an API key (Mistral)
241
+
242
+ Mistral is the default provider and the only one tested end to end here, so it is
243
+ the shortest path to a working index. API access is enabled by default on a free
244
+ account — **no credit card** — with a usage limit that is enough to index a
245
+ repository.
246
+
247
+ 1. Create an account at <https://console.mistral.ai> if you do not have one.
248
+ 2. Open the **Studio** console and click **API Keys** in the left sidebar.
249
+ 3. Click **Create new key**: give it a name, set an expiration date, and choose the
250
+ connector access scope (*Shared connectors only* is enough for an API key).
251
+ 4. Click **Create new key** and **copy the key right away** — it is shown once and
252
+ cannot be retrieved later.
253
+
254
+ Then hand it to the plugin. The simplest way keeps the key out of any file:
255
+
256
+ ```bash
257
+ export KILO_INDEX_MISTRAL_KEY=... # Linux / macOS
258
+ # PowerShell: $env:KILO_INDEX_MISTRAL_KEY = "..."
259
+ ```
260
+
261
+ Equivalently, set it from **`/indexing-config`** in any client or the `/indexing`
262
+ page in the terminal (the field is masked), or through the plugin's options in
263
+ `opencode.json` — see
264
+ [Configuration](#configuration-optional-opencodejson). Settings resolve in the
265
+ order *plugin options → `indexing.json` → environment → defaults*, so an
266
+ environment variable is overridden by anything set in the file or in the options.
267
+
268
+ To check the key before indexing:
269
+
270
+ ```bash
271
+ curl -s https://api.mistral.ai/v1/models \
272
+ -H "Authorization: Bearer $KILO_INDEX_MISTRAL_KEY" | head -c 200
273
+ ```
274
+
275
+ A list of models means it works; a `401` means the key is wrong or the header is
276
+ missing.
277
+
278
+ #### How far each provider has actually been tested
279
+
280
+ Worth stating plainly, because "implemented" and "seen working" are not the
281
+ same claim and only one of them is safe to rely on.
282
+
283
+ | Provider | Against the real API | What that means |
284
+ | --- | --- | --- |
285
+ | `mistral` | **Yes** | Two inputs, 1536 dimensions, distinct vectors, ~680 ms |
286
+ | `openrouter` | **Partly** | The request reached the API and authenticated; it was refused by the key's own $0 spend limit, so the response parser is unverified |
287
+ | `ollama` | **No** | The local server was not running during the check |
288
+ | `openai`, `gemini`, `voyage`, `openai-compatible` | **No** | No credentials available; only mock-based tests |
289
+
290
+ The adapters for the last four were written from each provider's documentation
291
+ and tested against fixtures written alongside them, which means the tests encode
292
+ the same reading of the docs as the code. A wrong assumption about a field name
293
+ or a response shape would pass every test and fail on first use.
294
+
295
+ Three specific things this leaves open, in descending order of how quietly they
296
+ would fail:
297
+
298
+ - **Gemini's aggregation.** `gemini-embedding-2` returns a single aggregated
299
+ vector for a plain list of inputs, where `gemini-embedding-001` returns one per
300
+ input. The adapter wraps each input in its own `Content` to make both behave
301
+ the same way, and a test asserts the count — but the test is against a fixture,
302
+ not the model. If the wrapping is wrong, N inputs silently become one vector.
303
+ - **Voyage's response shape.** It is treated as OpenAI-shaped
304
+ (`data[].embedding` with an `index`). This matches its published API reference
305
+ and was not confirmed against the service.
306
+ - **Voyage and Ollama truncation.** Both are sent `truncation`/`truncate: false`
307
+ so that an over-long chunk fails instead of being silently shortened. If a
308
+ provider rejects that field rather than honouring it, indexing stops with an
309
+ error rather than degrading — which is the intended direction to fail, but it
310
+ is a guess about the field being accepted.
311
+
312
+ If you use one of these providers and it fails, the error message names the
313
+ provider and the endpoint; please report it, since this is the part of the
314
+ plugin most likely to be wrong.
315
+
316
+ Two things worth knowing before switching:
317
+
318
+ - **Model ids are namespaced per provider.** Changing provider clears the model
319
+ so the new provider's default applies. A leftover id like
320
+ `codestral-embed-2505` under `provider: "voyage"` would be sent to Voyage and
321
+ rejected.
322
+ - **Changing the model invalidates the own index.** A different model means a
323
+ different vector space, so the next build deletes the existing points and
324
+ re-embeds the whole workspace. `indexing_status` warns with the point count
325
+ *before* that happens. Re-embedding a repository is cheap — well under a
326
+ couple of dollars at any paid provider — but a large one takes a while.
327
+
328
+ **Which models can import from Kilo.** Kilo's registry is mirrored entry for
329
+ entry, because an import is accepted only when provider, model id and dimension
330
+ match exactly. Models marked *ours* in the table above are not in Kilo's
331
+ registry and can never be imported; `indexing_config` says which is which. If
332
+ your Kilo index uses a different model, set the same provider and model here and
333
+ the import costs nothing.
334
+
184
335
  Settings are stored in `~/.config/opencode/indexing.json` (plugin options → `indexing.json` → environment → defaults). Plugin options in `opencode.json` still work and take precedence. API keys are never written to `indexing.json` in plain text; set them through the environment or plugin options.
185
336
 
186
337
  `~/.config/kilo/kilo.jsonc` is still read, and still supplies the embedding provider, model, dimensions and API keys — and it still says where *Kilo* keeps its index. It no longer decides where this plugin's own index is written; that stopped being coupled so that the default could actually take effect for people running Kilo. See [Where each index lives](#where-each-index-lives).
@@ -190,16 +341,36 @@ Settings are stored in `~/.config/opencode/indexing.json` (plugin options → `i
190
341
  ```jsonc
191
342
  {
192
343
  "plugins": [
193
- { "package": "./plugins/opencode-indexing", "options": {
344
+ { "package": "@javierkaiser/opencode-indexing", "options": {
194
345
  "vectorStore": "qdrant",
195
346
  "qdrantUrl": "http://localhost:6333",
196
347
  "importFromKilo": true,
197
- "autoRefresh": false
348
+ "autoRefresh": false,
349
+ "ignoreKiloConfig": false
198
350
  }}
199
351
  ]
200
352
  }
201
353
  ```
202
354
 
355
+ | Option | Meaning |
356
+ | --- | --- |
357
+ | `vectorStore` | `qdrant` or `lancedb` for the **own** index. Does not affect where an import reads from. |
358
+ | `qdrantUrl` / `qdrantApiKey` | Qdrant connection |
359
+ | `provider` / `model` / `dimension` | Embedding profile, overriding the resolved one |
360
+ | `importFromKilo` | Import a compatible Kilo index on build instead of re-embedding |
361
+ | `autoRefresh` | Refresh inline on search when few files changed |
362
+ | `enabled` | Master switch: when false the own index is neither written nor refreshed |
363
+ | `ignoreKiloConfig` | Stop reading `~/.config/kilo/kilo.jsonc` entirely |
364
+
365
+ `~/.config/kilo/kilo.jsonc` is read as a fallback for the embedding provider,
366
+ model, dimensions **and API keys**, which is what makes a free import possible:
367
+ the same model has to be used to reuse Kilo's vectors. Set `ignoreKiloConfig` to
368
+ `true` to cut that off, or override any single value with the options above, an
369
+ environment variable, or `~/.config/opencode/indexing.json` — in that order of
370
+ precedence, with plugin options winning.
371
+
372
+ ### Environment variables
373
+
203
374
  | Variable | Meaning |
204
375
  | --- | --- |
205
376
  | `KILO_INDEX_VECTOR_STORE` | `lancedb` (default) or `qdrant` for the own index |