@functional-systems/srcx 0.1.0-dev.4 → 0.1.0-dev.40

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +179 -0
  2. package/CONTRIBUTING.md +4 -0
  3. package/DESIGN.md +378 -58
  4. package/README.md +628 -35
  5. package/RELEASING.md +15 -3
  6. package/VALIDATION.md +1120 -16
  7. package/dist/artifact.d.ts +31 -0
  8. package/dist/artifact.js +237 -0
  9. package/dist/artifact.js.map +1 -0
  10. package/dist/build.d.ts +86 -3
  11. package/dist/build.js +233 -71
  12. package/dist/build.js.map +1 -1
  13. package/dist/chunk.d.ts +9 -3
  14. package/dist/chunk.js +341 -14
  15. package/dist/chunk.js.map +1 -1
  16. package/dist/cli.js +130 -21
  17. package/dist/cli.js.map +1 -1
  18. package/dist/file-policy.d.ts +20 -0
  19. package/dist/file-policy.js +103 -0
  20. package/dist/file-policy.js.map +1 -0
  21. package/dist/implementation.d.ts +11 -0
  22. package/dist/implementation.js +191 -0
  23. package/dist/implementation.js.map +1 -0
  24. package/dist/publish.d.ts +18 -0
  25. package/dist/publish.js +224 -46
  26. package/dist/publish.js.map +1 -1
  27. package/dist/releases.js +21 -3
  28. package/dist/releases.js.map +1 -1
  29. package/dist/remote.d.ts +1 -0
  30. package/dist/remote.js +50 -9
  31. package/dist/remote.js.map +1 -1
  32. package/dist/repository.d.ts +4 -1
  33. package/dist/repository.js +26 -11
  34. package/dist/repository.js.map +1 -1
  35. package/dist/rerank.d.ts +16 -0
  36. package/dist/rerank.js +87 -0
  37. package/dist/rerank.js.map +1 -0
  38. package/dist/search.d.ts +18 -3
  39. package/dist/search.js +143 -23
  40. package/dist/search.js.map +1 -1
  41. package/dist/skills.d.ts +24 -0
  42. package/dist/skills.js +155 -0
  43. package/dist/skills.js.map +1 -0
  44. package/package.json +17 -6
  45. package/runtime/grammars/README.md +50 -0
  46. package/runtime/grammars/tree-sitter-bash.LICENSE +21 -0
  47. package/runtime/grammars/tree-sitter-bash.wasm +0 -0
  48. package/runtime/grammars/tree-sitter-sql.LICENSE +21 -0
  49. package/runtime/grammars/tree-sitter-sql.wasm +0 -0
  50. package/runtime/grammars/tree-sitter-wasm.LICENSE +21 -0
  51. package/runtime/qwen.py +132 -0
  52. package/runtime/requirements.txt +34 -0
  53. package/skills/srcx-search/SKILL.md +103 -0
  54. package/src/artifact.ts +303 -0
  55. package/src/build.ts +313 -84
  56. package/src/chunk.ts +360 -12
  57. package/src/cli.ts +263 -23
  58. package/src/file-policy.ts +166 -0
  59. package/src/implementation.ts +253 -0
  60. package/src/publish.ts +321 -47
  61. package/src/releases.ts +36 -3
  62. package/src/remote.ts +70 -13
  63. package/src/repository.ts +40 -11
  64. package/src/rerank.ts +131 -0
  65. package/src/search.ts +229 -28
  66. package/src/skills.ts +205 -0
package/README.md CHANGED
@@ -19,10 +19,86 @@ srcx --version
19
19
  srcx --help
20
20
  ```
21
21
 
22
+ ## Install the agent skill
23
+
24
+ The npm package includes the [srcx-search skill](skills/srcx-search/SKILL.md).
25
+ After installing the CLI, explicitly select your agent:
26
+
27
+ ```sh
28
+ srcx skills install --agent codex
29
+ # Or, for Claude Code:
30
+ srcx skills install --agent claude
31
+ srcx skills status --agent codex
32
+ ```
33
+
34
+ The default scope is `user`. Installation copies the bundled instructions into
35
+ one of the following local discovery directories:
36
+
37
+ | Agent | User scope | Project scope |
38
+ | ----------- | --------------------------------------- | ----------------------------------------------- |
39
+ | Codex | `~/.agents/skills/srcx-search/SKILL.md` | `<project>/.agents/skills/srcx-search/SKILL.md` |
40
+ | Claude Code | `~/.claude/skills/srcx-search/SKILL.md` | `<project>/.claude/skills/srcx-search/SKILL.md` |
41
+
42
+ These are the documented local skill locations for
43
+ [Codex](https://learn.chatgpt.com/docs/build-skills#where-codex-loads-local-skills)
44
+ and [Claude Code](https://code.claude.com/docs/en/skills#where-skills-live).
45
+ Cloud sessions need their own installation; a local user installation does not
46
+ configure remote agents or account-synced skills. The installer targets these
47
+ default locations, not custom agent configuration directories.
48
+
49
+ To share a skill with a project, select an existing project directory and commit
50
+ the installed file if appropriate for your team:
51
+
52
+ ```sh
53
+ srcx skills install --agent codex --scope project --path /path/to/project
54
+ ```
55
+
56
+ Project scope defaults to the current directory when `--path` is omitted; it does
57
+ not infer the Git root. `--path` is accepted only for project scope. Prefer one
58
+ scope per agent to avoid duplicate skill names. The installer does not change
59
+ `AGENTS.md`, `CLAUDE.md`, agent permissions, shell profiles or credentials, and npm
60
+ installation alone does not place skills in your environment.
61
+
62
+ Make sure the agent's shell can run `srcx --version`. Configure LambdaDB and
63
+ prepare the repository using the [connected workflow](#connected-workflow) below,
64
+ or use an already indexed repository in the configured project. The agent process
65
+ must inherit the API-key environment variable named by `srcx configure`; no key
66
+ is copied into the skill. `srcx doctor` checks authentication/read access only.
67
+
68
+ Start a new agent session after installation. Invoke `$srcx-search` in Codex or
69
+ `/srcx-search` in Claude Code, and ask it to investigate an indexed repository at a
70
+ specific branch, release or commit. Skill-aware agents may also select it from its
71
+ description. Installation/status confirms files on disk, not that an agent loaded
72
+ or selected them. Agent policy, disabled skills and custom discovery paths can
73
+ still affect availability.
74
+
75
+ ### Update and remove
76
+
77
+ ```sh
78
+ npm install -g @functional-systems/srcx@dev
79
+ srcx skills update --agent codex
80
+ srcx skills status --agent codex
81
+ srcx skills remove --agent codex
82
+ ```
83
+
84
+ Repeat for each installed agent/scope, supplying the same `--scope project --path`
85
+ when applicable. `update` uses the currently running CLI's bundled skill and does
86
+ not download anything. npm upgrades do not silently update skill copies, and npm
87
+ uninstall does not remove them: run `skills remove` before uninstalling the CLI.
88
+
89
+ A provenance comment records the package version and content hash. Repeated
90
+ installation is a no-op when the installed copy matches. A different managed
91
+ version requires `update`. Locally edited skills, extra files, unowned skills and
92
+ symlinked managed paths are preserved by refusing the operation; there is no
93
+ force-overwrite flag. Move a customized copy to a separate skill name/location
94
+ before installing a managed copy. Interrupted operations can leave a sibling
95
+ `.srcx-search.srcx-lock` directory: check that no installer is running and preserve
96
+ any staged file before manually removing that lock and retrying.
97
+
22
98
  ## Run locally
23
99
 
24
- Requires Node.js 22.14+ and Git. The initial preset uses lexical search with
25
- `embedding=none`; no embedding account or paid API is needed.
100
+ Requires Node.js 22.14+ and Git. The default preset uses lexical search with
101
+ `embedding=none` and the `standard` text analyzer; no embedding account or paid API is needed.
26
102
 
27
103
  ```sh
28
104
  npm ci --ignore-scripts
@@ -63,19 +139,413 @@ and tag names that collide require `refs/heads/...` or `refs/tags/...`. No autom
63
139
  fetch, history replay, or revision expressions are supported.
64
140
 
65
141
  Each artifact contains `build.json` (inventory, configuration, counts, hashes,
66
- change/deletion plan) and `records.jsonl` (exact file records and retrieval chunks).
142
+ change/deletion plan) and, by default, `records.jsonl` (exact file records and
143
+ retrieval chunks).
144
+
145
+ For an experimental alternative that reduces retained-record rewrites, use
146
+ `--artifact-storage segments` when creating a new build:
147
+
148
+ ```sh
149
+ srcx import --path /path/to/repo --ref main --dry-run \
150
+ --artifact-storage segments --output /tmp/srcx-segmented-a
151
+ srcx import --path /path/to/repo --ref next --dry-run \
152
+ --artifact-storage segments --previous /tmp/srcx-segmented-a \
153
+ --output /tmp/srcx-segmented-b
154
+ ```
155
+
156
+ Format 2 stores `build.json` and digest-addressed JSONL objects under `objects/`.
157
+ Unchanged objects can share filesystem storage through hardlinks, while each
158
+ artifact remains usable after deleting the previous directory. Full local source
159
+ and record/hash checks still run; publication retains complete candidate
160
+ validation. Fewer bytes are written, but more
161
+ file operations can make builds slower; descriptor construction and full checks
162
+ still scale with corpus size. Segmented mode requires native no-follow and
163
+ nonblocking file-open support. Cross-filesystem/unsupported-link copies rewrite the
164
+ retained bytes too. See [local build measurements](VALIDATION.md).
165
+
166
+ The default is `--artifact-storage jsonl`; storage does not change the embedding
167
+ preset or require a new Collection. Preview JSON includes `artifactFormat` (1 or 2).
168
+ Use `--artifact <directory>` to import/resume either format without a storage flag;
169
+ an explicit `--artifact-storage` cannot override an existing artifact. Older CLIs
170
+ accept only format 1, and tools that directly read `records.jsonl` need the shared
171
+ artifact reader to support format 2. Linked files are not tamper-proof: full checks
172
+ detect shared-object corruption. Preserve the pending artifact and journal until
173
+ publication completes.
174
+
175
+ Local retention is manual: remove whole completed artifact directories, keeping
176
+ any pending artifact and its original retry journal. Unchanged hardlinked objects
177
+ remain available through surviving artifacts. Losing the latest local artifact
178
+ requires a full local rebuild unless a surviving compatible checkpoint is
179
+ explicitly selected with `--previous` during a dry-run build; checkpoint discovery
180
+ is not automatic. Import that rebuilt artifact with `--artifact`.
181
+ Local cleanup does not delete published versions or their immutable remote data.
182
+ See [cumulative history and recovery measurements](VALIDATION.md#cumulative-segmented-history-and-recovery)
183
+ for the storage/time tradeoff across 50 successive versions.
184
+
67
185
  Artifacts contain source code; keep them with the same access policy as the repo.
68
186
  Every tree entry is accounted for, including explicit exclusions for symlinks,
69
- submodules, LFS pointers, dependencies/build output, binary/invalid UTF-8 data,
187
+ submodules, LFS pointers, dependencies/build output, image assets (including SVG), binary/invalid UTF-8 data,
70
188
  invalid UTF-8 paths, and files above 1 MiB. Excluded paths are preserved losslessly
71
189
  in `pathBase64`.
190
+ Image extensions are matched case-insensitively and excluded before chunking or
191
+ embedding, even when their payload is readable text. Source files containing
192
+ inline images, such as a TSX component with SVG markup, remain included.
193
+
194
+ File selection and embedding eligibility are separate:
195
+
196
+ | Default treatment | Examples |
197
+ | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
198
+ | Exclude source and chunks | Credential files (`.env`, `.env.*`, `.npmrc`, `.netrc`, `.aws/`, `.ssh/`), key/certificate payloads, images, binaries, installed dependencies (`.venv/`, `node_modules/`, `vendor/`, `third_party/`), build/cache output, logs, minified assets and source maps |
199
+ | Keep source and lexical chunks; skip embeddings | Lockfiles, license/author files, CSV/TSV/JSONL data, snapshots, generated code identified by common suffixes or an explicit generated/do-not-edit comment in the first 8 KiB |
200
+ | Keep source, lexical chunks and eligible embeddings | Authored code, tests, documentation, package manifests, CI/build configuration and other readable text |
201
+
202
+ `.env.example`, `.env.sample`, `.env.template` and equivalent suffixes remain
203
+ included as templates. Private-key PEM headers also exclude files with unrelated
204
+ extensions. These are targeted exclusions, **not a general secret scanner**;
205
+ review the dry-run inventory before uploading. `.gitignore` does not remove
206
+ already tracked Git objects, and `.gitattributes` is not interpreted for selection.
207
+
208
+ Java files under `src/<source-set>/java/` keep package directories named `build`,
209
+ `dist`, `target` or `coverage`. For example, `src/main/java/example/build/Builder.java`
210
+ is source, while `build/generated/src/main/java/example/Builder.java` is excluded.
211
+ Dependency and cache exclusions still apply inside source roots. Other ambiguous
212
+ layouts can use explicit file-policy rules below.
213
+
214
+ Use `--file-policy policy.json` with `repo add` or `import --dry-run --path` to
215
+ adjust the scope explicitly. The JSON contents are pinned in the repository
216
+ preset; subsequent connected imports use that preset, not the local policy file.
217
+
218
+ ```json
219
+ {
220
+ "version": 1,
221
+ "rules": [
222
+ { "pattern": "eval/**", "action": "exclude" },
223
+ { "pattern": "third_party/special/**", "action": "lexical" },
224
+ { "pattern": "generated/api.pb.go", "action": "semantic" }
225
+ ]
226
+ }
227
+ ```
228
+
229
+ Patterns match case-sensitive, repository-relative paths. `*` and `?` stay within
230
+ one path segment; `**` must occupy a whole segment and matches any depth. Rules
231
+ run in order; the last match wins. `semantic` permits embeddings when enabled but
232
+ still skips structural/import-only chunks. Rules override dependency/generated/
233
+ data defaults, but cannot override credential, crypto, image, binary, private-key
234
+ content, size, encoding, symlink or LFS exclusions. `retrieval` and `policyReason`
235
+ in dry-run coverage explain each included file's policy; chunk records retain
236
+ `embeddingSkipReason`. A changed policy selects a distinct Collection/configuration.
237
+
238
+ ```sh
239
+ srcx import --path . --ref develop --dry-run --embedding text-embedding-3-small --file-policy policy.json --output /tmp/srcx-preview
240
+ srcx repo add --path . --embedding text-embedding-3-small --file-policy policy.json
241
+ ```
242
+
243
+ Evaluation labels need an explicit corpus boundary. The checkout evaluation
244
+ harnesses use [this policy](eval/source-corpus-policy.json) to exclude `eval/**`;
245
+ labels stored elsewhere require additional exclusions before a new evaluation.
246
+ General-purpose imports do not discard all evaluation or test directories.
247
+
248
+ Java, TypeScript/TSX, JavaScript/JSX, Python, Go, Rust, C/C++, Shell and SQL use
249
+ pinned Tree-sitter WASM grammars.
250
+
251
+ | Language filter | File extensions | Boundaries and metadata |
252
+ | --------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
253
+ | `python` | `.py`, `.pyi` | Decorators, functions, classes, method scopes and docstrings |
254
+ | `go` | `.go` | Named types, functions and generic/pointer/value receiver scopes |
255
+ | `rust` | `.rs` | Functions, types and `impl`/`trait`/module scopes; outer attributes and doc comments stay with declarations |
256
+ | `c` | `.c`, `.h` | Functions, pointer declarators, types and preprocessor branches |
257
+ | `cpp` | `.cpp`, `.cc`, `.cxx`, `.C`, `.hpp`, `.hh`, `.hxx` | Functions, templates, namespace/class scopes and qualified names |
258
+ | `shell` | `.sh`, `.bash` | Bash-compatible functions and compound commands, including heredocs |
259
+ | `sql` | `.sql` | Statements, CTEs and supported function bodies; created object names/schema scopes |
260
+
261
+ `.h` files use the C grammar deterministically; C++ headers should use a listed
262
+ C++ extension for syntax chunking. Shell does not infer extensionless scripts from
263
+ shebangs or claim Zsh/Fish/PowerShell support. Shell and SQL use bundled
264
+ [grammar artifacts](runtime/grammars/README.md); SQL dialect-specific syntax unsupported
265
+ by that grammar falls back to text. SQL strings and supported dollar-quoted bodies
266
+ are parsed as part of their containing statement, not split at each semicolon.
267
+ Rust macros/`cfg` and C/C++ preprocessor conditions are not expanded or evaluated;
268
+ search uses authored source, including both conditional branches.
269
+
270
+ Markdown uses heading/paragraph/fence boundaries; configuration text uses
271
+ section/line boundaries. Parse errors and unsupported languages use recorded text
272
+ fallback. Chunks cover the exact source bytes, carry one-based line ranges, target
273
+ 800 tokens, and stay below 1,500 tokens including path/symbol context. The internal
274
+ window baseline is available to the test/build API, not as a public storage backend.
275
+
276
+ Added-language functions and SQL statements stay together when they fit the token
277
+ ceiling. Larger units use bounded text splitting with the same symbol/scope
278
+ metadata; nested functions remain inside their containing function. Syntax
279
+ unsupported by the pinned grammars uses recorded whole-file parse fallback.
280
+ Language labels remain available to `--language` filters even after fallback.
281
+
282
+ ## Choose text analyzers
283
+
284
+ New repositories use `standard` by default. Choose any nonempty combination of
285
+ LambdaDB's supported analyzers: `english`, `korean`, `japanese`, and `standard`.
286
+ These analyze searchable text; they are separate from programming-language
287
+ chunking and the `--language` file filter.
288
+
289
+ ```sh
290
+ srcx repo add --path /path/to/repo --analyzers english,korean
291
+ srcx repo add --path /path/to/repo --analyzers english
292
+
293
+ # Preview exactly the same settings without credentials or service calls.
294
+ srcx import --path /path/to/repo --ref main --dry-run \
295
+ --analyzers english,korean --output /tmp/srcx-preview
296
+ ```
72
297
 
73
- Java, TypeScript/TSX, and JavaScript use pinned Tree-sitter WASM grammars. Markdown
74
- uses heading/paragraph/fence boundaries; configuration text uses section/line
75
- boundaries. Parse errors and unsupported languages use recorded text fallback.
76
- Chunks cover the exact source bytes, carry one-based line ranges, target 800 tokens,
77
- and stay below 1,500 tokens including path/symbol context. The internal window
78
- baseline is available to the test/build API, not as a public storage backend.
298
+ Order and duplicates do not matter: `korean,english,english` selects the same
299
+ preset as `english,korean`. Unknown names and empty entries are rejected.
300
+ The chosen analyzers are stored in the repository preset, included in its
301
+ configuration hash, and checked against the Collection schema during discovery.
302
+ Different analyzer sets select separate Collections. Connected imports and
303
+ searches use the registered preset; `--analyzers` on import is only accepted with
304
+ `--dry-run --path`. Inspect the selection with `srcx repo show --repo <collection>`.
305
+
306
+ This pre-release preset now requires an explicit analyzer list. Older descriptors
307
+ and artifacts without it are not accepted; existing Collections are not changed
308
+ in place. A new registration/import uses the chosen preset.
309
+
310
+ Analyzers affect lexical search and the lexical part of hybrid search. They do
311
+ not translate queries or change the raw text sent to the embedding provider.
312
+ The same selection configures `searchText` and managed `embeddingText` text indexes.
313
+ See [LambdaDB text indexes](https://docs.lambdadb.ai/guides/collections/index-types#text).
314
+
315
+ ## Opt into managed embeddings
316
+
317
+ Supported models are `text-embedding-3-small` (1536 dimensions) and
318
+ `text-embedding-3-large` (3072 dimensions), both cosine. Use either name with
319
+ `--embedding`; each model/analyzer combination has a separate pinned preset and
320
+ Collection. Changing models requires a separate import.
321
+
322
+ LambdaDB generates vectors for meaningful code, tests and prose. Imports-only
323
+ and structural chunks remain lexical. The CLI uses LambdaDB credentials; it does not need an OpenAI key.
324
+ Source text sent for embedding and semantic/hybrid queries pass through LambdaDB
325
+ to OpenAI and incur usage charges. See [LambdaDB managed embeddings](https://docs.lambdadb.ai/guides/collections/managed-embeddings).
326
+
327
+ ```sh
328
+ # Offline preview: no upload or embedding request.
329
+ srcx import --path /path/to/repo --ref main --dry-run \
330
+ --embedding text-embedding-3-small --output /tmp/srcx-managed-preview
331
+
332
+ # Creates a separate Collection; existing lexical Collections stay usable.
333
+ srcx repo add --path /path/to/repo --embedding text-embedding-3-small
334
+ # Use the exact collection value returned above, especially with multiple presets.
335
+ srcx import --repo <collection> --ref main
336
+ srcx search --repo <collection> --version main --query "retry failed writes" --mode hybrid
337
+ srcx search --repo <collection> --version main --query "retry failed writes" --mode semantic
338
+ ```
339
+
340
+ Connected imports, including `--dry-run --repo`, use the selected repository's
341
+ pinned preset. `--embedding` on import is only for `--dry-run --path`.
342
+ `search` keeps `--mode lexical` as its default; semantic and hybrid require a
343
+ managed Collection. Hybrid uses LambdaDB RRF with identical filters on both legs.
344
+ Existing result handles, lexical config hashes and publication journals stay valid.
345
+
346
+ Local artifacts contain eligible `embeddingText` and input hashes, not vectors.
347
+ `counts.managed` and `counts.managedTokens` estimate the complete corpus's eligible
348
+ chunks and input tokens; `embedded=0` does not mean the server will skip them.
349
+ Publication requires valid generated vectors in the immutable candidate Tag,
350
+ plus the same exact payload/source checks as lexical publication. Unchanged
351
+ records are not uploaded again. Changed file chunks and uncertain write retries
352
+ may be embedded again; no global or query embedding cache is promised.
353
+
354
+ A small synthetic live check is available after building:
355
+
356
+ ```sh
357
+ npm run build
358
+ node --env-file=.env.local scripts/live-managed.mjs
359
+ ```
360
+
361
+ It uploads two synthetic commits, bounds document inputs to 10,000 estimated
362
+ tokens and issues four managed search queries plus lexical checks. It retains a
363
+ Collection, local fixture, artifacts, result handles and `.srcx/live-managed/report.json`.
364
+ Completed reruns preserve the original report and make no service calls; changed
365
+ runtime inputs require a fresh directory. Failed runs retain journals and reject
366
+ automatic replay. These are correctness checks, not retrieval-quality measurements.
367
+
368
+ ## Optional local Qwen reranker
369
+
370
+ `search --rerank qwen` reranks candidates from any retrieval mode with
371
+ [Qwen3-Reranker-0.6B](https://huggingface.co/Qwen/Qwen3-Reranker-0.6B/blob/e61197ed45024b0ed8a2d74b80b4d909f1255473/README.md).
372
+ It is off by default. Prepare Python 3.12+ and the model separately; npm does not
373
+ install Python dependencies or download model weights. From a checkout:
374
+
375
+ ```sh
376
+ python3.12 -m venv .srcx/qwen-venv
377
+ .srcx/qwen-venv/bin/pip install -r runtime/requirements.txt
378
+ .srcx/qwen-venv/bin/hf download Qwen/Qwen3-Reranker-0.6B \
379
+ --revision e61197ed45024b0ed8a2d74b80b4d909f1255473 \
380
+ config.json generation_config.json model.safetensors tokenizer.json tokenizer_config.json vocab.json merges.txt
381
+ export SRCX_RERANK_PYTHON="$PWD/.srcx/qwen-venv/bin/python"
382
+
383
+ srcx search --repo <collection> --version <commit> \
384
+ --query "retry failed writes" --mode semantic \
385
+ --rerank qwen --candidates 50 --limit 10
386
+ ```
387
+
388
+ For a global npm installation, the requirements file is at
389
+ `$(npm root -g)/@functional-systems/srcx/runtime/requirements.txt`; place the venv
390
+ in a persistent directory of your choice and use its absolute Python path.
391
+ `HF_HUB_CACHE` can select an existing Hugging Face cache for both download and
392
+ search. The worker loads only the pinned revision from that cache, offline.
393
+ `SRCX_RERANK_DEVICE` accepts `auto` (default: CUDA, then MPS, then CPU), `cuda`,
394
+ `mps`, or `cpu`. The current worker uses float32, SDPA and batch size one.
395
+
396
+ `--candidates` defaults to `max(50, limit)` and must be between `--limit` and 100.
397
+ It requires `--rerank qwen`. Both hybrid retrieval legs use this candidate limit;
398
+ path/language filters and the immutable version apply before reranking. The
399
+ worker receives the query and complete, verified source bytes of each chunk,
400
+ without a path prefix or evaluator labels. Identical source text shares a score
401
+ within the query; every candidate remains present and ties retain retrieval order.
402
+ It uses the code-search instruction from the CoSQA evaluation and ranks by the
403
+ raw yes-minus-no logit margin, not a calibrated relevance probability.
404
+
405
+ JSON stdout remains an array of results. `score` retains the retrieval score;
406
+ `rerankScore`, `retrievalRank` (one-based), and `reranker` identify the new order.
407
+ Only the returned results receive persisted evidence handles. Reranked excerpts
408
+ use the exact chunk bytes; normal reads still expand to complete source lines.
409
+ A JSON timing record on stderr reports verified retrieval, worker, search, and
410
+ command-handler times. Worker time includes Python startup, model loading and
411
+ inference. External process timing additionally includes Node startup and output.
412
+
413
+ Each CLI invocation loads a fresh model; this is an opt-in local integration,
414
+ not a warm inference service. The worker has a 120-second timeout, a 4 MiB input
415
+ cap and an 8,192-token limit per query/chunk pair. Missing setup, oversized input,
416
+ invalid scores and inference failures fail the command without silent truncation
417
+ or fallback. Empty candidate pools skip model execution. Existing search defaults
418
+ and managed embedding usage rules remain unchanged; wider pools increase source
419
+ verification work. See the [integration validation](VALIDATION.md#local-reranker-integration).
420
+
421
+ Failures include a fixed remediation message where the cause is known:
422
+
423
+ | Failure | Action |
424
+ | ------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
425
+ | Python executable missing or not executable | Check the path and execute permissions in `SRCX_RERANK_PYTHON`. |
426
+ | Missing or incompatible Python imports | Install `runtime/requirements.txt` using that Python environment. |
427
+ | Missing or incomplete model cache | Download the pinned revision and all files listed above; check `HF_HUB_CACHE`. |
428
+ | Invalid or unavailable device | Use `SRCX_RERANK_DEVICE=auto` or `cpu`, or an available `mps`/`cuda` device. |
429
+ | Request exceeds 4 MiB | Reduce `--candidates` or shorten the query. |
430
+ | A query/chunk pair exceeds 8,192 tokens | Shorten the query or omit `--rerank`; reducing candidate count does not shorten an individual chunk. |
431
+ | Worker exceeds 120 seconds | Reduce `--candidates` or select an available faster device. |
432
+
433
+ Unknown worker failures remain generic. Raw subprocess output and library
434
+ exceptions are never included in these messages. Failed reranking does not
435
+ silently return the original ranking; rerun without `--rerank` to opt out.
436
+
437
+ For practical search → read → change-planning examples, see the
438
+ [developer workflow pilot](https://github.com/lambdadb/srcx/blob/develop/eval/DEVELOPER-WORKFLOW-PILOT.md).
439
+ It follows three maintenance investigations through related source and tests,
440
+ including the limitations of previews and optional reranking.
441
+
442
+ The [agent workflow diagnostic](https://github.com/lambdadb/srcx/blob/develop/eval/AGENT-WORKFLOW-PILOT.md)
443
+ compares fresh agent sessions with Git/local tools and optional or explicitly
444
+ invoked srcx. It found no established efficiency advantage on the small public
445
+ corpora and records the remaining workflow hypotheses.
446
+
447
+ The [semantic agent follow-up](https://github.com/lambdadb/srcx/blob/develop/eval/SEMANTIC-AGENT-RESULTS.md)
448
+ compares local, lexical-first and semantic-first investigations on Requests. It
449
+ finds no established agent efficiency gain and records an unresolved candidate
450
+ retrieval discrepancy and excessive embedding of a generated SVG asset.
451
+
452
+ ## Query language and agent use
453
+
454
+ Queries can use any language; the CLI does not translate them. For lexical search,
455
+ match the language of the source you want to find. Prefer English search terms for
456
+ English code and comments, preserving identifiers, API names and error messages
457
+ exactly. For Korean documentation, use Korean terms in a Collection registered
458
+ with the `korean` analyzer. Analyzers tokenize text; they do not translate between
459
+ languages. The `--language` search filter selects a programming language, not the
460
+ natural language of the query.
461
+
462
+ For example, an agent answering the Korean question “데이터베이스 연결을 닫을 때
463
+ 어떻게 되나요?” can search English source with:
464
+
465
+ ```sh
466
+ srcx search --repo <collection> --version <commit> \
467
+ --query "What happens when closing a database connection?"
468
+ ```
469
+
470
+ This is a query-writing example, not a measured retrieval result. Read the returned
471
+ source before answering. Semantic and hybrid search can help across languages,
472
+ but relevant implementation evidence is not guaranteed to appear in the first
473
+ results. English wording is a starting point, not an input requirement or a
474
+ promise of better ranking for every question.
475
+
476
+ Agents can use the following search guidance:
477
+
478
+ > Choose query wording for the target source language, independently of the user's
479
+ > conversation language. For English code and comments, translate the user's
480
+ > intent into a concise English query. Preserve supplied identifiers, API names,
481
+ > paths and error messages exactly; do not invent implementation names or assume
482
+ > the question's premise is correct. Use the original language when seeking
483
+ > documentation written in that language. Read results at the pinned version and
484
+ > check that they support the answer. If evidence is incomplete, inspect relevant
485
+ > surrounding code or try another query based on observed source. Answer in the
486
+ > user's language and cite the source; state when evidence is missing.
487
+
488
+ ## Evaluate retrieval quality
489
+
490
+ The [fresh agent navigation comparison](https://github.com/lambdadb/srcx/blob/develop/eval/FRESH-AGENT-NAVIGATION-RESULTS.md)
491
+ measures complete answers, model input and wall time with local tools available in
492
+ both conditions. It does not establish a clear efficiency advantage on a small
493
+ local repository; retrieval quality and agent-workflow benefits remain separate.
494
+
495
+ The [cross-repository version workflow](https://github.com/lambdadb/srcx/blob/develop/eval/VERSION-WORKFLOW-RESULTS.md)
496
+ verifies exact source delivery across CLI/SDK releases from a fresh client without
497
+ local source attachments. It is a scripted known-range diagnostic, not an agent
498
+ benchmark. Local Git reads are much faster in this run; repeated project-wide
499
+ repository discovery is a measured source of remote overhead.
500
+ The subsequent [exact-Collection lookup replay](https://github.com/lambdadb/srcx/blob/develop/eval/DIRECT-LOOKUP-RESULTS.md)
501
+ removes 22 requests per command in that project, with identical source results
502
+ and lower observed read/search latency. It does not measure complete-agent cost.
503
+
504
+ In the subsequent [agent choice comparison](https://github.com/lambdadb/srcx/blob/develop/eval/VERSION-AGENT-RESULTS.md),
505
+ all three agents offered srcx read its installed skill but used local tools only
506
+ to investigate the prepared CLI/SDK versions. No srcx retrieval benefit was
507
+ established; multiple repositories and historical versions alone did not lead to
508
+ tool adoption when their source trees were already available locally.
509
+
510
+ The internal [lexical chunking pilot](https://github.com/lambdadb/srcx/blob/develop/eval/README.md) compares syntax-aware and
511
+ window chunks on a fixed public corpus and 16 pinned investigation queries.
512
+ `npm run eval:prepare` builds and validates the comparison offline. Live evaluation
513
+ is an explicit separate operation and retains isolated evaluation Collections.
514
+
515
+ The [default CLI workflow evaluation](https://github.com/lambdadb/srcx/blob/develop/eval/CLI-WORKFLOW.md)
516
+ adds a second public repository and verifies real `search` → `read` results with
517
+ the unchanged CLI preset. It uses normal repository Collections and separate local
518
+ state; see its documented effects before opting into the live run.
519
+
520
+ The [retrieval mode comparison](https://github.com/lambdadb/srcx/blob/develop/eval/RETRIEVAL-MODES.md) runs lexical, semantic and
521
+ hybrid against the same managed corpora. It retains original and reviewed labels,
522
+ full stdout accounting, command timings and bounded embedding request estimates.
523
+ `npm run eval:modes:prepare` is offline; live execution is explicit and incurs
524
+ managed embedding and LambdaDB usage.
525
+
526
+ The [query-style diagnostic](https://github.com/lambdadb/srcx/blob/develop/eval/QUERY-STYLES.md)
527
+ pairs identifiers, natural-language descriptions and mixed questions on eight new
528
+ tasks. It adds rank-prefix and stdout-budget measurements without changing the
529
+ model or ranking. [Embedding model candidates](https://github.com/lambdadb/srcx/blob/develop/eval/EMBEDDING-MODELS.md)
530
+ separately describe possible follow-up comparisons and integration requirements.
531
+ The [managed model comparison](https://github.com/lambdadb/srcx/blob/develop/eval/MODEL-COMPARISON.md)
532
+ compares small and large on both frozen suites, including lexical controls.
533
+ [Results](https://github.com/lambdadb/srcx/blob/develop/eval/MODEL-COMPARISON-RESULTS.md)
534
+ show mixed gains and regressions; small remains the initial managed choice.
535
+
536
+ [Transfer evaluation preparation](https://github.com/lambdadb/srcx/blob/develop/eval/TRANSFER-EVAL.md) adds source-verified,
537
+ unreviewed Python/Go questions. The [completed development diagnostic](https://github.com/lambdadb/srcx/blob/develop/eval/TRANSFER-RESULTS.md)
538
+ compares all three modes with managed small and text fallback; it is not an
539
+ independently reviewed benchmark.
540
+ The [local reranking diagnostic](https://github.com/lambdadb/srcx/blob/develop/eval/RERANK-RESULTS.md)
541
+ compares Qwen selection on the same saved candidates, with separate offline
542
+ coverage and compute accounting.
543
+ The [public retrieval baseline](https://github.com/lambdadb/srcx/blob/develop/eval/PUBLIC-BENCHMARK.md)
544
+ uses pinned CoIR CoSQA and MTEB CodeSearchNet Python/Go tasks with official
545
+ labels and trec_eval metrics. It evaluates retrieval separately from Git import,
546
+ chunking and CLI reads.
547
+ New evaluation roots retain [safe command failure diagnostics](https://github.com/lambdadb/srcx/blob/develop/eval/COMMAND-DIAGNOSTICS.md)
548
+ for explicit recovery.
79
549
 
80
550
  ## Explicit live acceptance run
81
551
 
@@ -96,39 +566,114 @@ It saves connection settings under `.srcx/live/config.json` and keeps its state
96
566
  separate under `.srcx/live/state`. Rerunning resumes the saved synthetic run and
97
567
  refuses to reuse it against a different destination.
98
568
 
569
+ For persistent Git branch acceptance, run `npm run test:live:branches`. It uses a
570
+ separate synthetic Collection and `.srcx/live-branches/` state/report, covering
571
+ in-place A/B updates, last-published reads during a pending update, shared commit
572
+ Tags across two branches, rewinds, no-op imports, and SHA-only manual imports.
573
+ From an isolated worktree, load the original checkout's env file explicitly:
574
+
575
+ ```sh
576
+ npm run build
577
+ node --env-file=/absolute/path/to/srcx/.env.local scripts/live-branches.mjs
578
+ ```
579
+
580
+ The branch harness retains resources and resumes saved checkpoints on rerun.
581
+ It preserves the original source revision and completion time. Checkpoints from
582
+ different runtime code, harness, fixture, lockfile, or Node version are rejected
583
+ before connecting or overwriting evidence. To validate changed code, select a new
584
+ `SRCX_LIVE_BRANCHES_DIR` (for example `.srcx/live-branches-next`); retain the old
585
+ run and any pending journal. Its per-import deadline defaults to 300 seconds and accepts
586
+ `SRCX_LIVE_TIMEOUT_MS` up to 600000. Do not delete pending journals to start over.
587
+
99
588
  ## Connected workflow
100
589
 
590
+ Use the installed `srcx` binary below. For a source checkout, build first and
591
+ replace `srcx` with `node dist/cli.js`.
592
+
101
593
  These commands create and write LambdaDB resources. Select an approved project
102
- and source scope before running them. Start live validation with the synthetic
103
- fixture, not a production repository.
594
+ and source scope before running them. Start live validation with a small synthetic
595
+ fixture. `repo add` returns a `collection` value: use that value as `<name>` below
596
+ to disambiguate repositories with multiple presets. If isolating a first-use run,
597
+ set `SRCX_CONFIG` and `SRCX_STATE_DIR` to fresh paths before `configure`; keep
598
+ credentials in the shell and preserve these paths for later result reads.
104
599
 
105
600
  ```sh
106
601
  # Supply LAMBDADB_API_KEY through your shell or secret manager.
107
- node dist/cli.js configure --endpoint https://api.lambdadb.ai --project <project>
108
- node dist/cli.js doctor
109
- node dist/cli.js repo add --path /path/to/repo \
602
+ srcx configure --endpoint https://api.lambdadb.ai --project <project>
603
+ srcx doctor
604
+ srcx repo add --path /path/to/repo \
110
605
  --description "Repository source, tests, and documentation for code search." \
111
606
  --tag team=search
112
- node dist/cli.js repo list
113
- node dist/cli.js repo show --repo <name>
607
+ srcx repo list
608
+ srcx repo show --repo <name>
114
609
 
115
610
  # Import the exact artifact reviewed in the credential-free preview.
116
- node dist/cli.js import --repo <name> --artifact /tmp/srcx-build-a
117
- node dist/cli.js versions --repo <name>
118
- node dist/cli.js search --repo <name> --version <full-commit-A> --query retry
119
- node dist/cli.js read --result <result-id> --context 20
120
- node dist/cli.js read --result <result-id> --full-file
121
- node dist/cli.js read --repo <name> --version <full-commit-A> \
611
+ srcx import --repo <name> --artifact /tmp/srcx-build-a
612
+ srcx versions --repo <name>
613
+
614
+ # Keep a Git branch connected to its Collection Branch.
615
+ srcx import --repo <name> --ref develop
616
+ srcx search --repo <name> --version develop --query retry
617
+ srcx resolve --repo <name> --ref refs/heads/develop
618
+ srcx search --repo <name> --version <full-commit-A> --query retry
619
+ srcx read --result <result-id> --context 20
620
+ srcx read --result <result-id> --implementation
621
+ srcx read --result <result-id> --full-file
622
+ srcx read --repo <name> --version <full-commit-A> \
122
623
  --path src/example.ts --lines 10:30
123
624
 
124
- node dist/cli.js import --repo <name> --artifact /tmp/srcx-build-b
625
+ srcx import --repo <name> --artifact /tmp/srcx-build-b
125
626
  # An old A result still reads A after B is published.
126
- node dist/cli.js read --result <result-id> --full-file
627
+ srcx read --result <result-id> --full-file
127
628
 
128
- node dist/cli.js git sync-tags --repo <name>
129
- node dist/cli.js resolve --repo <name> --ref v1.0.0
629
+ srcx git sync-tags --repo <name>
630
+ srcx resolve --repo <name> --ref v1.0.0
130
631
  ```
131
632
 
633
+ Prefer the exact `collection` value returned by `repo list` when the repository
634
+ is already known. Generated Collection names (`code-<slug>-<hash>`) are looked up
635
+ directly and take precedence over repository aliases with the same spelling.
636
+ Repository names and keys still use discovery and reject ambiguous matches across
637
+ presets. Only a missing Collection (HTTP 404) falls back to alias discovery;
638
+ permission, service, descriptor and schema errors remain errors. This does not
639
+ cache or bypass immutable-version and source-integrity checks.
640
+
641
+ `lookup --symbol <name>` returns exact, case-sensitive indexed symbol matches
642
+ and their verified `sourceText` in one call:
643
+
644
+ ```sh
645
+ srcx lookup --repo <collection> --version <resolved-commit> \
646
+ --symbol readToFile --limit 5
647
+ ```
648
+
649
+ Use a name found in the question, search results or source. For `Type.method`,
650
+ look up `method` and inspect the returned `scope` and `path`; use `--path` or
651
+ `--language` to narrow ambiguity. Lookup uses the existing keyword index and
652
+ requires no managed embeddings or reindexing. Results include definitions and
653
+ declarations, including same-name symbols and pieces of token-split definitions.
654
+ They are source chunks, not guaranteed complete function bodies or resolved
655
+ call targets. The limit defaults to five chunks and accepts 1–20. Results are
656
+ bounded, not an exhaustive symbol inventory; an empty result is not proof of
657
+ absence. `resultId` remains usable with `read` for surrounding lines or a full
658
+ file. Supplied source text can be cited directly without another read.
659
+
660
+ `read --implementation` follows a contiguous Python or TypeScript/TSX overload
661
+ group to its unique implementation in the same file and AST scope. It reads the
662
+ stored source at the result's immutable Tag; no reindexing or embedding is needed.
663
+ Python supports direct `from typing`/`typing_extensions import overload` imports,
664
+ including aliases used only as decorators. Stub files, ambiguous/interrupted
665
+ groups, unrecognized decorators and parse failures retain the original span.
666
+ Other languages and cross-file/type-based dispatch are not resolved. This is
667
+ syntax navigation, not proof of runtime binding or behavior.
668
+
669
+ The returned `implementation.status` is `resolved`, `not-linked`, `unsupported`,
670
+ `parse-error` or `too-large`. Resolved reads return the body's actual lines and
671
+ citation. Multiple overload hits may return the same body; the option does not
672
+ deduplicate results or skip reads. Bodies exceeding 1,500 source tokens retain the
673
+ original span with `too-large`; no silent truncation is applied. Ordinary reads
674
+ and search rankings are unchanged. The option requires `--result` and cannot be
675
+ combined with `--context`, `--lines` or `--full-file`.
676
+
132
677
  `doctor` checks authentication and Collection read access, not write permission
133
678
  or indexing/query readiness. `configure --api-key-env NAME` selects another
134
679
  credential environment variable; only its name is stored. Endpoint/project changes
@@ -142,7 +687,9 @@ identity or Collection name. Registration normalizes the selected Git remote;
142
687
  without remotes receive a persistent local source identity. Repeated registration
143
688
  preserves existing descriptions/labels and attaches the local checkout.
144
689
 
145
- Search is literal analyzed lexical text, restricted to `kind=chunk`. Optional
690
+ Search defaults to literal analyzed lexical text. All retrieval modes are
691
+ restricted to `kind=chunk`; semantic/hybrid and optional Qwen reranking are
692
+ described above. Optional
146
693
  `--path` and `--language` filters are exact keyword filters. `--limit` is 1–100.
147
694
  Search results include a durable local `resultId`, commit, immutable Tag/Snapshot,
148
695
  path, lines, and citation. Reads verify the original content hash and refuse
@@ -152,10 +699,28 @@ are one-based and inclusive.
152
699
  ## Publication and recovery
153
700
 
154
701
  The control Branch `main` holds descriptors/version summaries. `checkpoint-empty`
155
- is forked before any control write. Each import uses a new `work-*` Branch,
156
- optionally forked from the last locally retained, remotely validated writer
157
- baseline. Writers are frozen after publication. A fresh local state can start a
158
- full import from `checkpoint-empty`; source data is never forked from a Tag.
702
+ is forked before any control write. Importing a Git branch creates or updates its
703
+ stable `git-*` Collection Branch, derived from the full `refs/heads/...` name.
704
+ Git `main` also uses a `git-*` Branch; Collection `main` remains control-only.
705
+ Each later import reconciles against that branch's last validated snapshot,
706
+ including deletions and non-fast-forward changes. Branches sharing a commit share
707
+ one canonical `ver-*` Tag while retaining their own writer snapshots.
708
+
709
+ `search/read --version develop` and `resolve --ref develop` select the branch's
710
+ last successfully published commit Tag. During an import or after a failed update,
711
+ they keep serving the previous published commit; the first import is unavailable
712
+ until publication. This is the last indexed state, not a live Git HEAD lookup.
713
+ Nothing polls or fetches Git automatically: run import again to advance the branch.
714
+ If an indexed branch and synchronized Git tag share a short name, use
715
+ `refs/heads/<name>` or `refs/tags/<name>` explicitly. Known Git names take precedence
716
+ over commit prefixes.
717
+
718
+ A commit SHA or Git tag import does not infer a containing branch. An unpublished
719
+ commit uses a fresh `work-*` Branch, optionally forked from a validated previous
720
+ manual writer; an already published commit reuses its Tag. Manual writers remain
721
+ frozen. Source data is never forked from a Tag. A clean tracked branch can be
722
+ updated from fresh local state using its remote baseline. Local build reuse is
723
+ cached separately for each Git branch and for manual imports.
159
724
 
160
725
  The importer deletes obsolete IDs, upserts changed records and inventory parts in
161
726
  bounded sequential requests, then sends `__manifest__` **alone** after every prior
@@ -167,7 +732,10 @@ an early/stale snapshot even after the marker is observed.
167
732
 
168
733
  A per-Collection local lock and durable `pending.json` journal prevent another
169
734
  commit from overwriting a partial attempt. Only one importing host is supported.
170
- After a timeout or unknown write result, retain the artifacts and journal:
735
+ A tracked branch also records pending import ownership in control `main` before
736
+ writing code. If the local journal is lost, new local state refuses to overwrite
737
+ that pending branch even when its committed head has not advanced yet. After a
738
+ timeout or unknown write result, retain the artifacts and journal:
171
739
 
172
740
  ```sh
173
741
  node dist/cli.js import --repo <name> --artifact /path/from/pending.json \
@@ -186,6 +754,22 @@ remove that specific lock directory. Do not delete `pending.json` to force a new
186
754
  commit over an uncertain workspace. Unexpected baselines fail closed; automatic
187
755
  recovery to a new workspace and resource cleanup are not implemented yet.
188
756
 
757
+ Incremental publication can reuse a fully validated local baseline artifact's
758
+ record hashes after matching its repository/configuration, commit, build and
759
+ inventory/record hashes to the pinned remote baseline. Missing local files or a
760
+ different cached build fall back to listing that immutable baseline; corrupted
761
+ matching artifacts fail validation. Unchanged inventory parts also need no write.
762
+ Every new candidate still receives full document/hash and managed-vector
763
+ validation. A successful check is reused only within that invocation, after
764
+ confirming the candidate Tag still names the same Snapshot. Publication-stage
765
+ retries repeat full validation rather than trusting the journal.
766
+
767
+ This reduces redundant remote reads, not import complexity to the changed-code
768
+ size. Git tree enumeration, local full-artifact materialization/validation,
769
+ inventory construction and at least one complete candidate read remain. Further
770
+ reductions need a verified backend contract proving both mutation completeness
771
+ and preservation of unchanged baseline data; the final marker alone is insufficient.
772
+
189
773
  Git tag synchronization observes local `refs/tags/*` only. Multiple Git tags for
190
774
  one commit create separate `rel-*` Aliases targeting the same published Tag.
191
775
  An unimported/moved target is pending; the previously pinned version remains usable
@@ -195,8 +779,17 @@ For search and resolve, a synchronized Git tag name takes precedence over a comm
195
779
  prefix, matching Git import's tag-before-OID rule. A pending tag fails explicitly
196
780
  instead of falling back to a matching commit prefix. Use `refs/tags/<name>` to
197
781
  select a Git tag explicitly.
198
- Explicit authoritative pruning and persistent tracked-branch synchronization are
199
- follow-up work; no full history import is required.
782
+ Automatic Git observation, authoritative pruning, branch rename/deletion handling,
783
+ and garbage collection remain follow-up work; no full history import is required.
784
+
785
+ Existing commit Tags and frozen `work-*` Branches remain valid. The next import
786
+ using a Git branch name establishes its fixed mapping, even if that commit was
787
+ already published. A pending journal from the previous implementation resumes on
788
+ its original `work-*` writer; import the branch again after recovery to establish
789
+ tracking. `--artifact` uses the Git branch recorded when the artifact was built,
790
+ with its pinned commit; it does not reread the branch's current tip. The publication
791
+ JSON continues to describe the canonical commit Tag: its `writer` can be the
792
+ original publishing branch when multiple Git branches share that commit.
200
793
 
201
794
  ## State and implementation map
202
795