@bndynet/ragbox 0.1.0

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 (45) hide show
  1. package/README.md +765 -0
  2. package/README.zh-CN.md +774 -0
  3. package/dist/src/advanced.d.ts +13 -0
  4. package/dist/src/advanced.js +29 -0
  5. package/dist/src/cli.d.ts +2 -0
  6. package/dist/src/cli.js +1013 -0
  7. package/dist/src/config-file.d.ts +69 -0
  8. package/dist/src/config-file.js +246 -0
  9. package/dist/src/folder-index/config.d.ts +2 -0
  10. package/dist/src/folder-index/config.js +56 -0
  11. package/dist/src/folder-index/hash.d.ts +1 -0
  12. package/dist/src/folder-index/hash.js +14 -0
  13. package/dist/src/folder-index/indexer.d.ts +2 -0
  14. package/dist/src/folder-index/indexer.js +154 -0
  15. package/dist/src/folder-index/llm-client.d.ts +3 -0
  16. package/dist/src/folder-index/llm-client.js +45 -0
  17. package/dist/src/folder-index/manifest.d.ts +17 -0
  18. package/dist/src/folder-index/manifest.js +158 -0
  19. package/dist/src/folder-index/multi-query.d.ts +45 -0
  20. package/dist/src/folder-index/multi-query.js +109 -0
  21. package/dist/src/folder-index/pageindex-runner.d.ts +3 -0
  22. package/dist/src/folder-index/pageindex-runner.js +218 -0
  23. package/dist/src/folder-index/path-utils.d.ts +5 -0
  24. package/dist/src/folder-index/path-utils.js +33 -0
  25. package/dist/src/folder-index/query.d.ts +19 -0
  26. package/dist/src/folder-index/query.js +597 -0
  27. package/dist/src/folder-index/queue.d.ts +1 -0
  28. package/dist/src/folder-index/queue.js +18 -0
  29. package/dist/src/folder-index/root-tree.d.ts +3 -0
  30. package/dist/src/folder-index/root-tree.js +82 -0
  31. package/dist/src/folder-index/scan.d.ts +14 -0
  32. package/dist/src/folder-index/scan.js +152 -0
  33. package/dist/src/folder-index/types.d.ts +368 -0
  34. package/dist/src/folder-index/types.js +2 -0
  35. package/dist/src/folder-index/watch.d.ts +17 -0
  36. package/dist/src/folder-index/watch.js +550 -0
  37. package/dist/src/index.d.ts +6 -0
  38. package/dist/src/index.js +45 -0
  39. package/dist/src/sdk.d.ts +101 -0
  40. package/dist/src/sdk.js +352 -0
  41. package/dist/src/serve.d.ts +64 -0
  42. package/dist/src/serve.js +466 -0
  43. package/dist/src/setup-pageindex.d.ts +30 -0
  44. package/dist/src/setup-pageindex.js +184 -0
  45. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,765 @@
1
+ # RAGbox
2
+
3
+ Ask questions about your Markdown/MDX docs from the terminal, an HTTP service, or a Node.js app.
4
+
5
+ `ragbox` turns a documentation folder into a local queryable index. You can use it to search product docs, API guides, runbooks, internal handbooks, and multi-package docs without setting up a vector database.
6
+
7
+ Use `ragbox` when you want to:
8
+
9
+ - answer questions from a local docs folder
10
+ - inspect which docs and sections were used for an answer
11
+ - keep an index fresh while docs change
12
+ - expose docs Q&A to an internal backend through HTTP
13
+ - run the same workflow locally, in CI, and in a container
14
+
15
+ [中文文档](./README.zh-CN.md)
16
+
17
+ ## Quick Start
18
+
19
+ The default path is meant to work out of the box: install `ragbox`, let it prepare PageIndex locally, then index and query your docs.
20
+
21
+ ```bash
22
+ # Install the CLI.
23
+ npm install -g @bndynet/ragbox
24
+
25
+ # Clone PageIndex into ./.ragbox/PageIndex, create a Python venv,
26
+ # install PageIndex dependencies, and write ragbox.config.json.
27
+ ragbox setup pageindex
28
+ ```
29
+
30
+ Before continuing, edit `ragbox.config.json`: add your model settings and point `docs.rootDir` / `docs.outputDir` at your documentation and index locations.
31
+
32
+ ```json
33
+ {
34
+ "version": 1,
35
+ "pageIndex": {
36
+ "cli": "./.ragbox/PageIndex/run_pageindex.py",
37
+ "python": "./.ragbox/pageindex-venv/bin/python"
38
+ },
39
+ "llm": {
40
+ "baseUrl": "https://api.openai.com/v1",
41
+ "model": "gpt-4o-mini",
42
+ "apiKey": "sk-..."
43
+ },
44
+ "docs": {
45
+ "rootDir": "./docs",
46
+ "outputDir": "./.ragbox-index"
47
+ }
48
+ }
49
+ ```
50
+
51
+ If you have more than one docs folder, use the `sources` map described in [Project Config](#project-config). Then index and query:
52
+
53
+ ```bash
54
+ # Build the local index from the configured docs/source.
55
+ ragbox index
56
+
57
+ # Ask a question.
58
+ ragbox query "How do I configure authentication?"
59
+
60
+ # Optional: keep the index fresh while docs change.
61
+ ragbox watch --jsonl
62
+ ```
63
+
64
+ Use `start` when you want one foreground process for indexing, watching, and serving the query API:
65
+
66
+ ```bash
67
+ ragbox start
68
+ ```
69
+
70
+ You can still pass explicit paths when you want to override the config for one command:
71
+
72
+ ```bash
73
+ ragbox index ./docs --output-dir ./.ragbox-index
74
+ ragbox query ./.ragbox-index "How do I configure authentication?"
75
+ ```
76
+
77
+ If you do not want to store credentials in JSON, the same model settings can be supplied with environment variables or flags:
78
+
79
+ ```bash
80
+ export OPENAI_API_KEY=sk-...
81
+ export OPENAI_BASE_URL=https://api.openai.com/v1
82
+
83
+ ragbox index ./docs \
84
+ --output-dir ./.ragbox-index \
85
+ --model gpt-4o-mini
86
+
87
+ ragbox query ./.ragbox-index "How do I configure authentication?" \
88
+ --api-key sk-... \
89
+ --base-url https://api.openai.com/v1 \
90
+ --model gpt-4o-mini
91
+ ```
92
+
93
+ ## What Setup Does
94
+
95
+ `ragbox setup pageindex` prepares the local PageIndex dependency for you:
96
+
97
+ - clones PageIndex into `./.ragbox/PageIndex`
98
+ - creates `./.ragbox/pageindex-venv`
99
+ - installs PageIndex Python dependencies
100
+ - writes `pageIndex.cli` and `pageIndex.python` into `ragbox.config.json`
101
+ - adds `.ragbox/` to `.gitignore`
102
+
103
+ If you already have a PageIndex checkout, use `ragbox setup pageindex --dir ../PageIndex --skip-install`, or set `PAGEINDEX_CLI` manually.
104
+
105
+ ## Requirements
106
+
107
+ The default setup needs:
108
+
109
+ - Node.js 18 or newer
110
+ - Git, for cloning PageIndex
111
+ - Python 3 with `venv` and `pip`, for PageIndex dependencies
112
+ - a docs folder containing `.md` or `.mdx` files
113
+ - an OpenAI-compatible `/chat/completions` endpoint
114
+ - an API key for that endpoint
115
+
116
+ ## Common Workflows
117
+
118
+ | Goal | Use |
119
+ | --- | --- |
120
+ | Start from nothing | `npm install -g @bndynet/ragbox`, then `ragbox setup pageindex` |
121
+ | Try ragbox on one docs folder | `ragbox index ./docs --output-dir ./.ragbox-index`, then `ragbox query ./.ragbox-index "..."` |
122
+ | Avoid repeating paths | use the `ragbox.config.json` written by `ragbox setup pageindex`, or run `ragbox init` |
123
+ | Query several docs folders together | Configure `sources`, run `ragbox index --source <name>`, then `ragbox query --all-sources "..."` |
124
+ | Debug answer quality | `ragbox query --trace --json "..."` or `ragbox trace query "..."` |
125
+ | Check whether an index is usable | `ragbox status ./.ragbox-index` |
126
+ | Diagnose local setup issues | `ragbox doctor` |
127
+ | Keep docs indexed while editing | `ragbox watch ./docs --output-dir ./.ragbox-index --jsonl` |
128
+ | Run the full local service loop | `ragbox start --auth-token <token>` |
129
+ | Serve an already-built index only | `ragbox serve ./.ragbox-index --auth-token <token>` |
130
+
131
+ ## Project Config
132
+
133
+ `ragbox setup pageindex` creates or updates `ragbox.config.json` for the default local setup. After adding your model credentials, a typical config looks like this:
134
+
135
+ ```json
136
+ {
137
+ "version": 1,
138
+ "pageIndex": {
139
+ "cli": "./.ragbox/PageIndex/run_pageindex.py",
140
+ "python": "./.ragbox/pageindex-venv/bin/python"
141
+ },
142
+ "llm": {
143
+ "baseUrl": "https://api.openai.com/v1",
144
+ "model": "gpt-4o-mini",
145
+ "apiKey": "sk-..."
146
+ },
147
+ "docs": {
148
+ "rootDir": "./docs",
149
+ "outputDir": "./.ragbox-index"
150
+ }
151
+ }
152
+ ```
153
+
154
+ You can also create a config without installing PageIndex:
155
+
156
+ ```bash
157
+ ragbox init
158
+ ragbox init --docs-dir ./content --output-dir ./.idx
159
+ ```
160
+
161
+ Relative paths are resolved from the config file directory. Server-side deployments can keep `baseUrl`, `model`, and `apiKey` together in a private `ragbox.config.json` or environment-specific config such as `ragbox.config.prod.json`. If a config file is committed or shared, keep `apiKey` in environment variables or a secret manager instead.
162
+
163
+ For one documentation source, use the top-level `docs` object. No `--source` flag is needed. If a project needs multiple named sources, use the optional `sources` map.
164
+
165
+ After that, commands can use the configured docs automatically:
166
+
167
+ ```bash
168
+ ragbox index
169
+ ragbox query "How do I configure authentication?"
170
+ ragbox watch --jsonl
171
+ ragbox start
172
+ ragbox --config ./ragbox.config.json index
173
+ ```
174
+
175
+ For multiple documentation directories, name each one under `sources`. This is useful for monorepos, product docs plus API docs, or separate app/package documentation:
176
+
177
+ ```json
178
+ {
179
+ "version": 1,
180
+ "pageIndex": {
181
+ "cli": "./.ragbox/PageIndex/run_pageindex.py",
182
+ "python": "./.ragbox/pageindex-venv/bin/python"
183
+ },
184
+ "llm": {
185
+ "baseUrl": "https://api.openai.com/v1",
186
+ "model": "gpt-4o-mini",
187
+ "apiKey": "sk-..."
188
+ },
189
+ "sources": {
190
+ "ragbox": {
191
+ "rootDir": "./ragbox",
192
+ "outputDir": "./.ragbox-index/ragbox",
193
+ "include": ["**/*.md", "**/*.mdx"]
194
+ },
195
+ "icharts": {
196
+ "rootDir": "./icharts",
197
+ "outputDir": "./.ragbox-index/icharts",
198
+ "include": ["**/*.md", "**/*.mdx"]
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ A runnable copy of this multi-source layout lives in `./examples/ragbox.config.json`.
205
+
206
+ Index named sources separately, then query globally or narrow to selected sources:
207
+
208
+ ```bash
209
+ ragbox index --source ragbox
210
+ ragbox index --source icharts
211
+
212
+ ragbox query "What does ragbox start do?"
213
+ ragbox query --source ragbox "How does query tracing work?"
214
+ ragbox query --source ragbox,icharts "How do these projects handle runtime workflows?"
215
+ ragbox query --all-sources "What documentation topics are available?"
216
+ ragbox start --all-sources
217
+ ```
218
+
219
+ When multiple sources are configured, `ragbox query "..."` queries all of them. `--all-sources` is an explicit alias for the same behavior; use `--source` to limit the search.
220
+
221
+ You can keep environment-specific files too:
222
+
223
+ ```bash
224
+ ragbox --config prod index
225
+ ragbox --config ./ragbox.config.prod.json query "How do I deploy?"
226
+ ```
227
+
228
+ ## Configuration
229
+
230
+ For server-side use, keep the stable settings in `ragbox.config.json`: PageIndex paths, docs paths, LLM `baseUrl`, `model`, and, when the file is private, `apiKey`. Environment variables and CLI flags are still supported for overrides, secret managers, and one-off runs.
231
+
232
+ Resolution order is command-line flags, then `ragbox.config.json`, then environment variables, then defaults.
233
+
234
+ | Setting | Env | CLI flag | Used by | Default |
235
+ | --- | --- | --- | --- | --- |
236
+ | PageIndex script | `PAGEINDEX_CLI` | `ragbox setup pageindex` writes config | `index`, `watch` | required when indexing |
237
+ | Python executable | `PAGEINDEX_PYTHON` | `--pageindex-python` | `index`, `watch` | `python3` |
238
+ | Output directory | `RAGBOX_OUTPUT_DIR` | `--output-dir` | `index`, `watch` | `<folder>/.pageindex` |
239
+ | Concurrency | `PAGEINDEX_CONCURRENCY` | `--concurrency` | `index`, `watch` | `1` |
240
+ | API base URL | `OPENAI_BASE_URL` | `--base-url` | `index`, `watch`, `query` | `https://api.openai.com/v1` |
241
+ | API key | `OPENAI_API_KEY` | `--api-key` | `index`, `watch`, `query` | required for query and usually PageIndex |
242
+ | Model | `PAGEINDEX_MODEL`, `LLM_MODEL` | `--model` | `index`, `watch`, `query` | `gpt-4o-mini` |
243
+ | Serve host | `RAGBOX_SERVE_HOST` | `--host` | `serve` | `127.0.0.1` |
244
+ | Serve port | `RAGBOX_SERVE_PORT` | `--port` | `serve` | `8787` |
245
+ | Serve token | `RAGBOX_SERVE_TOKEN` | `--auth-token` | `serve` | none |
246
+ | Watch debounce | `RAGBOX_WATCH_DEBOUNCE_MS` | `--debounce-ms` | `watch` | `500` |
247
+ | Watch retry attempts | `RAGBOX_WATCH_RETRY_ATTEMPTS` | `--retry-attempts` | `watch` | `0` |
248
+ | Watch retry delay | `RAGBOX_WATCH_RETRY_DELAY_MS` | `--retry-delay-ms` | `watch` | `1000` |
249
+ | Watch lock file | `RAGBOX_WATCH_LOCK_FILE` | `--lock-file` | `watch` | none |
250
+ | Watch staging | `RAGBOX_WATCH_STAGING` | `--staging` | `watch` | off |
251
+ | Watch staging output | `RAGBOX_WATCH_STAGING_OUTPUT_DIR` | `--staging-output-dir` | `watch` | `<outputDir>.staging` |
252
+ | Watch health file | `RAGBOX_WATCH_HEALTH_FILE` | `--health-file` | `watch` | none |
253
+ | Watch webhook | `RAGBOX_WATCH_WEBHOOK_URL` | `--webhook` | `watch` | none |
254
+
255
+ For private server config, putting `llm.apiKey` in JSON keeps the deployment self-contained. For shared repositories, containers, or managed secret stores, leave `apiKey` out of JSON and provide `OPENAI_API_KEY` at runtime. Passing `--api-key` is useful for local testing, but command-line secrets can appear in shell history and process listings.
256
+
257
+ ## Commands
258
+
259
+ Use this section as a command reference. If you are new to `ragbox`, start with [Quick Start](#quick-start) and [Common Workflows](#common-workflows).
260
+
261
+ ### `ragbox setup pageindex`
262
+
263
+ Clones PageIndex into `./.ragbox/PageIndex`, creates `./.ragbox/pageindex-venv`, installs PageIndex Python dependencies, updates `ragbox.config.json`, and adds `.ragbox/` to `.gitignore`.
264
+
265
+ ```bash
266
+ ragbox setup pageindex
267
+ ragbox setup pageindex --ref v0.1.0
268
+ ragbox setup pageindex --skip-install
269
+ ragbox setup pageindex --dir ../PageIndex --no-write-config
270
+ ```
271
+
272
+ Use `--json` for automation. Use `--no-gitignore` if your project manages generated local tooling another way.
273
+
274
+ ### `ragbox init`
275
+
276
+ Creates a `ragbox.config.json` file without installing PageIndex. Use this when you want to hand-edit paths or manage PageIndex yourself.
277
+
278
+ ```bash
279
+ ragbox init
280
+ ragbox init --docs-dir ./content --output-dir ./.idx
281
+ ragbox init --output ./configs/ragbox.config.json --force
282
+ ```
283
+
284
+ ### `ragbox index <folder>`
285
+
286
+ Builds or updates the local index for a Markdown/MDX folder. Run this before `query` or `serve`.
287
+
288
+ ```bash
289
+ ragbox index ./docs
290
+ ragbox index ./docs --output-dir ./.ragbox-index
291
+ ragbox index ./docs --output-dir ./.ragbox-index --json
292
+ ragbox index ./docs --output-dir /var/lib/ragbox/docs-index --concurrency 2
293
+ ragbox index ./docs --pageindex-python /opt/venvs/pageindex/bin/python
294
+ ragbox index ./docs --base-url https://api.openai.com/v1 --model gpt-4o-mini
295
+ ```
296
+
297
+ `index` scans `**/*.md` and `**/*.mdx`, hashes files, re-indexes new/modified/failed files, skips unchanged ready files, and removes deleted files from the manifest.
298
+
299
+ If any document fails, normal output keeps the counts on stdout and prints failed document paths plus PageIndex errors on stderr.
300
+
301
+ Use `--json` to print a versioned machine-readable result with output paths, counts, and failed document details:
302
+
303
+ ```json
304
+ {
305
+ "version": 1,
306
+ "command": "index",
307
+ "rootDir": "/repo/docs",
308
+ "outputDir": "/repo/.ragbox-index",
309
+ "manifestPath": "/repo/.ragbox-index/manifest.json",
310
+ "rootTreePath": "/repo/.ragbox-index/root-tree.json",
311
+ "generatedAt": "2026-01-01T00:00:00.000Z",
312
+ "counts": {
313
+ "total": 12,
314
+ "ready": 12,
315
+ "failed": 0,
316
+ "added": 12,
317
+ "modified": 0,
318
+ "retryFailed": 0,
319
+ "unchanged": 0,
320
+ "deleted": 0
321
+ },
322
+ "failures": []
323
+ }
324
+ ```
325
+
326
+ ### `ragbox inspect [target]`
327
+
328
+ Shows what is inside an index, including document status and counts. Use it when an index exists but you want to see what was actually indexed.
329
+
330
+ ```bash
331
+ ragbox inspect ./.ragbox-index
332
+ ragbox inspect --source ragbox
333
+ ragbox inspect --all-sources --json
334
+ ```
335
+
336
+ ### `ragbox status [target]`
337
+
338
+ Checks whether an index is ready to query. This is useful in CI, deploy scripts, and smoke checks.
339
+
340
+ ```bash
341
+ ragbox status ./.ragbox-index
342
+ ragbox status --all-sources
343
+ ragbox status --json
344
+ ```
345
+
346
+ ### `ragbox doctor [target]`
347
+
348
+ Checks the local setup: config, PageIndex CLI path, LLM settings, API key presence, and index validity. It does not call the network.
349
+
350
+ ```bash
351
+ ragbox doctor
352
+ ragbox doctor --source ragbox --json
353
+ ragbox doctor --all-sources
354
+ ```
355
+
356
+ ### `ragbox query [target] <question>`
357
+
358
+ Answers a question from either a docs folder with a default `.pageindex` index, or an existing ragbox output directory.
359
+
360
+ ```bash
361
+ ragbox query ./docs "How do I configure authentication?"
362
+ ragbox query ./.ragbox-index "What are the deployment steps?"
363
+ ragbox query ./docs/.pageindex "How do I configure authentication?"
364
+ ragbox query ./.ragbox-index "How do I configure authentication?" --model gpt-4o-mini --api-key sk-...
365
+ ragbox query ./.ragbox-index "How do I configure authentication?" --json
366
+ ragbox query ./.ragbox-index "How do I configure authentication?" --trace
367
+ ragbox trace query ./.ragbox-index "How do I configure authentication?"
368
+ ragbox query "What are the deployment steps?"
369
+ ragbox query --source ragbox,icharts "How do these projects handle runtime workflows?"
370
+ ragbox query --all-sources "What are the deployment steps?"
371
+ ```
372
+
373
+ Use the same `--base-url` value that you use for indexing. It should normally be the OpenAI-compatible root, such as `https://api.openai.com/v1`; `query` also accepts a full `/chat/completions` URL for proxy setups that require it.
374
+
375
+ When passing an explicit target, it can be:
376
+
377
+ - a docs folder containing `.pageindex/manifest.json` and `.pageindex/root-tree.json`
378
+ - an output directory containing:
379
+
380
+ ```text
381
+ manifest.json
382
+ root-tree.json
383
+ indexes/
384
+ ```
385
+
386
+ `query` reads `root-tree.json`, asks the LLM to choose likely documents, reads their PageIndex JSON, strips `text` fields before node selection, then extracts the selected node text for the final answer.
387
+
388
+ For multiple configured sources, `ragbox query "..."` queries all sources by default. Pass comma-separated names with `--source` to limit the search, or use `--all-sources` when you want the global behavior to be explicit. Multi-source query runs the normal structured query flow per source, then asks the LLM to synthesize one final answer from the selected source excerpts. Source references are prefixed with the source name, for example `ragbox:start-command.md#n1`.
389
+
390
+ Use `--json` to print a versioned result contract. Single-source queries return `QueryResult`; multi-source queries return a result with a fused `answer`, per-source `results`, prefixed `sources`, `warnings`, and `timingsMs`.
391
+
392
+ Single-source `QueryResult` fields:
393
+
394
+ - `answer`: final answer text
395
+ - `contextBytes` and `contextTokens`: size of the final answer context; tokens are estimated
396
+ - `selectedDocuments`: document ids selected from `root-tree.json`, including `selectionReason` and optional `skipReason`
397
+ - `selectedNodes`: PageIndex nodes selected per document, including `selectionReason`, optional `skipReason`, and `textBytes`
398
+ - `sources`: source references and extracted node text used as answer context
399
+ - `warnings`: unavailable documents, missing nodes, or empty context
400
+ - `timingsMs`: resolve, selection, and answer timings
401
+ - `trace`: only present with `--trace` or `ragbox trace query`; includes raw document/node selection LLM responses, prompt/response byte counts, context size, and non-fatal failure records
402
+
403
+ Fatal query errors include the stage that failed, for example `Query failed during select-documents: ...`.
404
+
405
+ ### `ragbox start [folder]`
406
+
407
+ Runs the complete local service loop: index first, watch for future changes, and serve the HTTP query API.
408
+
409
+ ```bash
410
+ ragbox start
411
+ ragbox start --auth-token dev-token
412
+ ragbox start --host 127.0.0.1 --port 8787 --jsonl
413
+ ragbox start --source ragbox
414
+ ragbox start --all-sources
415
+ ragbox start ./docs --output-dir ./.ragbox-index
416
+ ```
417
+
418
+ Use `start` after `ragbox setup pageindex` when you want one foreground process for local development, an internal service, or a container. It waits for the initial index run before starting HTTP `serve`, then reloads the serve index snapshot after successful watch updates.
419
+
420
+ With multiple configured sources, `ragbox start` starts all sources by default. Use `--source ragbox,icharts` to limit the running sources, or `--all-sources` to make the global behavior explicit.
421
+
422
+ `start` does not create or edit `ragbox.config.json`; run `ragbox setup pageindex` for the default local setup, or `ragbox init` when you want to manage PageIndex yourself.
423
+
424
+ ### `ragbox serve [target]`
425
+
426
+ Starts a foreground HTTP server for external systems. Index first with `ragbox index`, or keep the index fresh with `ragbox watch`.
427
+
428
+ ```bash
429
+ ragbox serve ./.ragbox-index \
430
+ --host 127.0.0.1 \
431
+ --port 8787 \
432
+ --auth-token dev-token
433
+ ```
434
+
435
+ For multiple configured sources, serve the config instead of a single target:
436
+
437
+ ```bash
438
+ ragbox serve --config ./ragbox.config.json --host 0.0.0.0 --port 8787
439
+ ```
440
+
441
+ Public HTTP contract:
442
+
443
+ - `GET /`: public service entrypoint with health summary and endpoint list.
444
+ - `GET /health`: public readiness endpoint for load balancers, Kubernetes, systemd, and smoke checks. Returns 200 when all known indexes are query-ready, otherwise 503.
445
+ - `GET /indexes`: returns the current validated index snapshot. Requires `Authorization: Bearer <token>` when a token is configured.
446
+ - `POST /query`: answers from one target, selected sources, or all configured sources. Requires auth when configured.
447
+ - `POST /reload`: re-reads config/source targets and refreshes the server-side validation snapshot. Requires auth when configured.
448
+
449
+ Single-index requests:
450
+
451
+ ```bash
452
+ curl http://127.0.0.1:8787/
453
+ curl http://127.0.0.1:8787/health
454
+
455
+ curl -H "Authorization: Bearer dev-token" \
456
+ http://127.0.0.1:8787/indexes
457
+
458
+ curl -X POST http://127.0.0.1:8787/query \
459
+ -H "Authorization: Bearer dev-token" \
460
+ -H "Content-Type: application/json" \
461
+ -d '{"question":"How do I configure authentication?","trace":true}'
462
+ ```
463
+
464
+ Multi-source requests:
465
+
466
+ ```bash
467
+ curl -X POST http://localhost:8787/query \
468
+ -H "Content-Type: application/json" \
469
+ -d '{"source":"ragbox","question":"What does ragbox start do?"}'
470
+
471
+ curl -X POST http://localhost:8787/query \
472
+ -H "Content-Type: application/json" \
473
+ -d '{"source":["ragbox","icharts"],"question":"How do these projects handle runtime workflows?"}'
474
+
475
+ curl -X POST http://localhost:8787/query \
476
+ -H "Content-Type: application/json" \
477
+ -d '{"allSources":true,"question":"What documentation topics are available?"}'
478
+
479
+ curl -X POST http://localhost:8787/reload
480
+ ```
481
+
482
+ `serve` is designed for local services, internal services, container sidecars, and docs backends. Do not expose `.ragbox-index` as static files, because it can contain source document text. Browser widgets should call your own backend first; the backend can enforce user auth, rate limits, and audit logging before forwarding requests to `ragbox serve`. In production, bind to localhost or an internal network address and configure `--auth-token` or `RAGBOX_SERVE_TOKEN`.
483
+
484
+ ### `ragbox watch <folder>`
485
+
486
+ Runs an initial index and keeps it updated.
487
+
488
+ ```bash
489
+ ragbox watch ./docs
490
+ ragbox watch ./docs --output-dir ./.ragbox-index
491
+ ragbox watch ./docs --output-dir /var/lib/ragbox/docs-index --concurrency 2
492
+ ragbox watch ./docs --base-url https://api.openai.com/v1 --model gpt-4o-mini
493
+ ragbox watch ./docs --output-dir ./.ragbox-index --jsonl
494
+ ragbox watch ./docs \
495
+ --output-dir /var/lib/ragbox/docs-index \
496
+ --staging \
497
+ --retry-attempts 3 \
498
+ --retry-delay-ms 2000 \
499
+ --lock-file /var/run/ragbox/docs.lock \
500
+ --health-file /var/run/ragbox/docs-health.json \
501
+ --jsonl
502
+ ```
503
+
504
+ Watch mode listens for Markdown/MDX add, change, and unlink events. It ignores `node_modules`, `.git`, `.pageindex`, `dist`, `build`, and a custom output directory when it is inside the watched root.
505
+
506
+ Use `--jsonl` to stream versioned JSON Lines events for integrations. The stream includes `watch-start`, `watch-lock-acquired`, `watch-file-event`, `watch-index-start`, `watch-index-retry`, `watch-index-partial-failure`, `watch-output-promoted`, `watch-index-done`, `watch-index-failed`, `watch-health`, `watch-webhook-failed`, `watch-lock-released`, `watch-stop`, and `index-progress` events.
507
+
508
+ Production watch options:
509
+
510
+ - `--retry-attempts` and `--retry-delay-ms` retry thrown index errors and runs that leave failed documents.
511
+ - `--lock-file` creates an exclusive lock while watch is running. A second watcher exits if the lock already exists.
512
+ - `--staging` indexes into a staging directory and only promotes it after a clean run with zero failed documents. The default staging directory is `<outputDir>.staging`; keep it on the same filesystem as `outputDir` for rename-based promotion.
513
+ - `--health-file` writes a readiness JSON file with `status`, `ok`, `pid`, `lastSuccessAt`, `lastFailureAt`, and latest counts.
514
+ - `--webhook` POSTs every watch event as JSON. Webhook delivery failures are reported as `watch-webhook-failed` events and do not stop watch.
515
+ - `--debounce-ms` controls how long watch waits after file changes before reindexing.
516
+
517
+ `ragbox watch` intentionally runs in the foreground, which works well as a systemd service or container process. Use your supervisor's restart policy instead of shell-level daemonization.
518
+
519
+ ## Output
520
+
521
+ Default output:
522
+
523
+ ```text
524
+ docs/.pageindex/
525
+ manifest.json
526
+ root-tree.json
527
+ indexes/
528
+ <stable-doc-id>.pageindex.json
529
+ state/
530
+ file-state.json
531
+ ```
532
+
533
+ Custom output:
534
+
535
+ ```bash
536
+ ragbox index ./docs --output-dir ./.ragbox-index
537
+ ragbox query ./.ragbox-index "..."
538
+ ```
539
+
540
+ The output directory can contain source document text. Do not serve it publicly if your docs are private.
541
+
542
+ ## Production
543
+
544
+ Common patterns:
545
+
546
+ - Run `ragbox start` when one foreground process should index, watch, and serve.
547
+ - Index during deploy, then serve/query the completed output directory with `ragbox serve` or SDK calls.
548
+ - Run `ragbox watch` as a background service if docs change outside deploys.
549
+ - For long-running watch, prefer `--jsonl`, `--lock-file`, `--health-file`, `--retry-attempts`, and `--staging`.
550
+ - Store the output directory outside the source tree, for example `/var/lib/ragbox/docs-index`.
551
+ - Mount or copy the completed output directory to every app replica that needs querying.
552
+ - Keep API keys in a private server config, environment variables, or your secret manager. Do not commit real keys.
553
+ - Use `RAGBOX_SERVE_TOKEN` or `--auth-token` when `serve` is reachable beyond localhost.
554
+ - Start with `--concurrency 1`; raise it only after checking PageIndex and API rate limits.
555
+
556
+ Example private server config:
557
+
558
+ ```json
559
+ {
560
+ "version": 1,
561
+ "pageIndex": {
562
+ "cli": "/opt/PageIndex/run_pageindex.py",
563
+ "python": "/opt/pageindex-venv/bin/python"
564
+ },
565
+ "llm": {
566
+ "baseUrl": "https://api.openai.com/v1",
567
+ "model": "gpt-4o-mini",
568
+ "apiKey": "sk-..."
569
+ },
570
+ "docs": {
571
+ "rootDir": "/srv/app/docs",
572
+ "outputDir": "/var/lib/ragbox/docs-index"
573
+ }
574
+ }
575
+ ```
576
+
577
+ ```bash
578
+ ragbox --config ./ragbox.config.prod.json index --concurrency 2
579
+ ragbox --config ./ragbox.config.prod.json query "How do I configure authentication?"
580
+ ```
581
+
582
+ ### Run In The Background
583
+
584
+ `ragbox start` intentionally runs in the foreground. For a server, run it under a process supervisor so it survives terminal closes, SSH disconnects, and crashes.
585
+
586
+ For quick testing, `nohup` is enough:
587
+
588
+ ```bash
589
+ nohup ragbox --config ./ragbox.config.prod.json start > ragbox.log 2>&1 &
590
+ ```
591
+
592
+ For Linux servers, prefer `systemd`:
593
+
594
+ ```ini
595
+ [Unit]
596
+ Description=ragbox service
597
+ After=network.target
598
+
599
+ [Service]
600
+ WorkingDirectory=/srv/ragbox
601
+ ExecStart=/usr/local/bin/ragbox --config ./ragbox.config.prod.json start
602
+ Restart=always
603
+ RestartSec=5
604
+ Environment=NODE_ENV=production
605
+
606
+ [Install]
607
+ WantedBy=multi-user.target
608
+ ```
609
+
610
+ ```bash
611
+ sudo systemctl enable ragbox
612
+ sudo systemctl start ragbox
613
+ sudo systemctl status ragbox
614
+ ```
615
+
616
+ Node-oriented deployments can use `pm2`:
617
+
618
+ ```bash
619
+ pm2 start "ragbox --config ./ragbox.config.prod.json start" --name ragbox
620
+ pm2 save
621
+ pm2 startup
622
+ ```
623
+
624
+ Containers should keep `ragbox start` as the foreground command and use the platform restart policy, such as Docker `--restart unless-stopped` or Kubernetes `restartPolicy`.
625
+
626
+ ## Use ragbox from Node.js
627
+
628
+ Use the SDK when another Node.js service should create indexes, query docs, validate indexes, or run `serve` programmatically.
629
+
630
+ ```js
631
+ const {
632
+ createIndex,
633
+ inspectIndex,
634
+ queryIndex,
635
+ startServe,
636
+ validateIndex,
637
+ watchIndex
638
+ } = require("@bndynet/ragbox");
639
+
640
+ await createIndex("/srv/app/docs", {
641
+ configPath: "./ragbox.config.json",
642
+ outputDir: "/var/lib/ragbox/docs-index",
643
+ pageIndexCli: "/opt/PageIndex/run_pageindex.py"
644
+ });
645
+
646
+ const result = await queryIndex(
647
+ "/var/lib/ragbox/docs-index",
648
+ "How do I configure authentication?"
649
+ );
650
+
651
+ console.log(result.answer);
652
+ console.log(result.sources);
653
+
654
+ const validation = await validateIndex("/var/lib/ragbox/docs-index");
655
+ console.log(validation.ok);
656
+
657
+ const server = await startServe({
658
+ target: "/var/lib/ragbox/docs-index",
659
+ port: 8787,
660
+ authToken: process.env.RAGBOX_SERVE_TOKEN
661
+ });
662
+ console.log(server.url);
663
+ await server.close();
664
+
665
+ const inspect = await inspectIndex("/var/lib/ragbox/docs-index");
666
+ console.log(inspect.counts);
667
+
668
+ const watcher = await watchIndex("/srv/app/docs", {
669
+ outputDir: "/var/lib/ragbox/docs-index",
670
+ pageIndexCli: "/opt/PageIndex/run_pageindex.py",
671
+ onEvent: (event) => console.log(event)
672
+ });
673
+ await watcher.ready;
674
+ await watcher.close();
675
+ ```
676
+
677
+ Custom LLM client:
678
+
679
+ ```js
680
+ const { queryIndex, startServe } = require("@bndynet/ragbox");
681
+
682
+ const llmClient = {
683
+ async chatCompletion(request) {
684
+ // request.messages, request.model, request.temperature
685
+ return await callYourModelGateway(request);
686
+ }
687
+ };
688
+
689
+ const result = await queryIndex(
690
+ "/var/lib/ragbox/docs-index",
691
+ "How do I configure authentication?",
692
+ {
693
+ llmClient,
694
+ model: "internal-docs-model"
695
+ }
696
+ );
697
+
698
+ const server = await startServe({
699
+ target: "/var/lib/ragbox/docs-index",
700
+ llmClient,
701
+ model: "internal-docs-model",
702
+ port: 8787
703
+ });
704
+ ```
705
+
706
+ `llmClient` is a thin SDK-only provider boundary for direct query-time chat completions. It is useful for local models, model gateways, retries, timeouts, logging, and tests. `ragbox` does not load provider plugins from config files; CLI commands still use the OpenAI-compatible settings from flags, config, and environment variables.
707
+
708
+ The package root exports the stable product SDK API. Lower-level helpers are still available under `advanced` for custom integrations:
709
+
710
+ ```js
711
+ const { advanced } = require("@bndynet/ragbox");
712
+
713
+ const location = await advanced.resolveQueryIndexLocation("/var/lib/ragbox/docs-index");
714
+ ```
715
+
716
+ ## What Happens During Query
717
+
718
+ At a high level, `ragbox` keeps the structure of your docs instead of flattening everything into anonymous chunks:
719
+
720
+ - each Markdown/MDX file becomes a structured PageIndex tree
721
+ - the docs folder gets a small index manifest
722
+ - a query first selects likely documents, then likely sections inside those documents
723
+ - the final answer is generated only from the selected section text
724
+
725
+ This is why `--trace` can show which documents and nodes were selected. It is also why the basic flow does not require a vector database.
726
+
727
+ ## Compared With Vector DB RAG
728
+
729
+ Traditional vector RAG usually chunks documents, embeds chunks, and retrieves by vector similarity. `ragbox` preserves the source document hierarchy and lets the LLM select over that structure.
730
+
731
+ | Area | Vector DB RAG | `ragbox` |
732
+ | --- | --- | --- |
733
+ | Index unit | Text chunks | Markdown/MDX file plus PageIndex nodes |
734
+ | Retrieval signal | Embedding similarity | LLM selection over document and node trees |
735
+ | Storage | Vector database plus document store | Local JSON files under the output directory |
736
+ | Context shape | Flat retrieved chunks | Structured nodes with file paths and node ids |
737
+ | Strength | Fast fuzzy recall across large collections | Preserves document hierarchy and source references |
738
+ | Tradeoff | Requires embedding/index infrastructure | Depends on PageIndex quality and LLM selection |
739
+
740
+ The two approaches can also be combined: use vector search for broad candidate recall, then use PageIndex trees for structured filtering, context packing, and citations.
741
+
742
+ ## Troubleshooting
743
+
744
+ - `PAGEINDEX_CLI is required to run PageIndex`: run `ragbox setup pageindex`, or set `PAGEINDEX_CLI=/path/to/run_pageindex.py`.
745
+ - `OPENAI_API_KEY is required for query`: add `llm.apiKey` to a private `ragbox.config.json`, set `OPENAI_API_KEY`, or pass `--api-key`.
746
+ - `Expected a docs folder... or a ragbox output directory`: pass either the docs folder with `.pageindex/`, or the output directory itself.
747
+ - `PageIndex completed but no generated JSON result was found`: by default, ragbox reads the JSON that PageIndex writes into `results/`. If you use a custom wrapper that only writes to an explicit output path, set `PAGEINDEX_OUTPUT_ARG` or `pageIndex.outputArg` to its output-path flag.
748
+
749
+ ## Limitations
750
+
751
+ - PageIndex must be installed/configured locally; `ragbox setup pageindex` can prepare the default local checkout and virtual environment.
752
+ - Query quality depends on PageIndex JSON shape and the configured LLM.
753
+ - The basic flow uses tree selection, not vector search.
754
+
755
+ ## For Contributors
756
+
757
+ ```bash
758
+ npm install
759
+ npm run build
760
+ npm run ragbox -- --help
761
+ ```
762
+
763
+ ### Examples
764
+
765
+ Runnable local fixtures and smoke-test commands live in [`examples/README.md`](./examples/README.md). Use that guide when you want to test indexing, query, multi-source config, or the `start` service loop with real PageIndex and LLM settings.