brainiac-cli 0.20.0__tar.gz → 0.20.2__tar.gz

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 (113) hide show
  1. {brainiac_cli-0.20.0/src/brainiac_cli.egg-info → brainiac_cli-0.20.2}/PKG-INFO +1 -1
  2. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/pyproject.toml +1 -1
  3. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_version.py +1 -1
  4. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/core.py +18 -0
  5. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/rerank.py +75 -5
  6. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2/src/brainiac_cli.egg-info}/PKG-INFO +1 -1
  7. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/LICENSE +0 -0
  8. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/MANIFEST.in +0 -0
  9. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/README.md +0 -0
  10. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/setup.cfg +0 -0
  11. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/__init__.py +0 -0
  12. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/__main__.py +0 -0
  13. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/AGENTS.md +0 -0
  14. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/assets/graph-explorer-template.html +0 -0
  15. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/brand/brand-guide.md +0 -0
  16. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/cos/auto-archive.md +0 -0
  17. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/cos/drafts.md +0 -0
  18. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/cos/ingest.md +0 -0
  19. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/cos/priorities.md +0 -0
  20. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/keywords/glossary.md +0 -0
  21. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/people/roster.md +0 -0
  22. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/overlay/template/voice/voice-profile.md +0 -0
  23. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/routines/manifest.json +0 -0
  24. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/brain-brief-mac.plist +0 -0
  25. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/brain-brief.sh +0 -0
  26. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/brain-synthesis-mac.plist +0 -0
  27. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/brain-synthesis.sh +0 -0
  28. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/brainiac-alerts.sh +0 -0
  29. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/install-brief-mac.sh +0 -0
  30. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/install-brief-windows.ps1 +0 -0
  31. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/register_tasks.py +0 -0
  32. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/vm-boundary-probe.sh +0 -0
  33. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/scripts/vm-selftest.sh +0 -0
  34. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/company.md +0 -0
  35. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/concept.md +0 -0
  36. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/daily.md +0 -0
  37. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/decision.md +0 -0
  38. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/meeting.md +0 -0
  39. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/person.md +0 -0
  40. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/project.md +0 -0
  41. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/templates/state-moc.md +0 -0
  42. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/tools/cos_browser_scan.mjs +0 -0
  43. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/tools/cos_contract.py +0 -0
  44. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/tools/cos_reconcile_metrics.py +0 -0
  45. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/_assets/tools/cos_retro.py +0 -0
  46. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/anchor.py +0 -0
  47. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/audit.py +0 -0
  48. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/autolink.py +0 -0
  49. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/backup.py +0 -0
  50. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/brief.py +0 -0
  51. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/capture.py +0 -0
  52. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/chunk.py +0 -0
  53. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/classification.py +0 -0
  54. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/cli.py +0 -0
  55. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/config.py +0 -0
  56. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/connect.py +0 -0
  57. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/context.py +0 -0
  58. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/conventions.py +0 -0
  59. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/cos.py +0 -0
  60. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/cos_chips.py +0 -0
  61. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/cos_corpus.py +0 -0
  62. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/cos_deploy.py +0 -0
  63. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/cos_runverify.py +0 -0
  64. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/dbretry.py +0 -0
  65. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/doctor.py +0 -0
  66. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/egress.py +0 -0
  67. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/embed.py +0 -0
  68. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/encryption.py +0 -0
  69. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/frontmatter.py +0 -0
  70. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/golden_probe.py +0 -0
  71. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/graph.py +0 -0
  72. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/graphify.py +0 -0
  73. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/graphreport.py +0 -0
  74. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/healthreport.py +0 -0
  75. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/inbox.py +0 -0
  76. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/index.py +0 -0
  77. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/__init__.py +0 -0
  78. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/__init__.py +0 -0
  79. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/base.py +0 -0
  80. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/docx.py +0 -0
  81. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/email.py +0 -0
  82. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/html.py +0 -0
  83. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/image.py +0 -0
  84. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/pdf.py +0 -0
  85. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/pptx.py +0 -0
  86. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/tables.py +0 -0
  87. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/text.py +0 -0
  88. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/xlsx.py +0 -0
  89. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/handlers/zip.py +0 -0
  90. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/pipeline.py +0 -0
  91. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/ingest/transcript.py +0 -0
  92. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/init.py +0 -0
  93. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/lock.py +0 -0
  94. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/maintenance.py +0 -0
  95. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/mcp_adapter.py +0 -0
  96. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/multihop.py +0 -0
  97. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/notes.py +0 -0
  98. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/overlay.py +0 -0
  99. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/progress.py +0 -0
  100. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/projection.py +0 -0
  101. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/provenance.py +0 -0
  102. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/querylog.py +0 -0
  103. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/retro.py +0 -0
  104. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/snapshot.py +0 -0
  105. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/spine.py +0 -0
  106. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/update.py +0 -0
  107. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/vectors.py +0 -0
  108. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brain/versionlink.py +0 -0
  109. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brainiac_cli.egg-info/SOURCES.txt +0 -0
  110. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brainiac_cli.egg-info/dependency_links.txt +0 -0
  111. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brainiac_cli.egg-info/entry_points.txt +0 -0
  112. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brainiac_cli.egg-info/requires.txt +0 -0
  113. {brainiac_cli-0.20.0 → brainiac_cli-0.20.2}/src/brainiac_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brainiac-cli
3
- Version: 0.20.0
3
+ Version: 0.20.2
4
4
  Summary: Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index).
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.9
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
  # check. The IMPORT package stays `brain` and the console script stays
9
9
  # `brain` — only the distribution/project name changes.
10
10
  name = "brainiac-cli"
11
- version = "0.20.0"
11
+ version = "0.20.2"
12
12
  description = "Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index)."
13
13
  readme = "README.md"
14
14
  license = "Apache-2.0"
@@ -9,4 +9,4 @@ pip-installed host, importlib.metadata stays primary; brain/__init__.py reads
9
9
  this file only as the fallback before 0.0.0+unknown.
10
10
  """
11
11
 
12
- __version__ = "0.20.0"
12
+ __version__ = "0.20.2"
@@ -548,11 +548,29 @@ class BrainCore:
548
548
  t0 = time.monotonic()
549
549
  embedder.embed("warmup") # triggers the real load/download if needed
550
550
  elapsed = time.monotonic() - t0
551
+ # The RERANKER too, since 0.20.1: reranking is default-on (BR-03), and
552
+ # a search is no longer allowed to download its weights mid-query — it
553
+ # degrades to the unreranked order instead. Warmup is now the one place
554
+ # those weights are fetched, so warming only the embedder would leave a
555
+ # user permanently unreranked without ever saying why.
556
+ from .rerank import warm_reranker_weights
557
+
558
+ rerank_info: dict[str, Any]
559
+ try:
560
+ progress_note("warmup: resolving the reranker...",
561
+ json_mode=json_mode, verb="warmup")
562
+ rerank_info = dict(warm_reranker_weights())
563
+ except Exception as exc:
564
+ # Never fail the embedder warm because the optional precision
565
+ # booster could not be fetched — report it and move on.
566
+ rerank_info = {"downloaded": False, "cached": False,
567
+ "error": f"{type(exc).__name__}: {exc}"}
551
568
  progress_note(f"warmup: ready in {elapsed:.1f}s", json_mode=json_mode, verb="warmup")
552
569
  return {
553
570
  "model_id": embedder.model_id,
554
571
  "already_cached": bool(was_cached),
555
572
  "elapsed_s": round(elapsed, 2),
573
+ "reranker": rerank_info,
556
574
  }
557
575
 
558
576
  def drafts_dir(self) -> Path:
@@ -306,6 +306,44 @@ OPEN_DEFAULT_RERANKER_ONNX = "onnx/model.onnx"
306
306
  OPEN_DEFAULT_RERANKER_MODEL_ID = "Alibaba-NLP/gte-multilingual-reranker-base"
307
307
 
308
308
 
309
+ def _reranker_weights_cached(hf_repo: str, onnx_file: str) -> bool:
310
+ """Are this reranker's weights already in the local HF cache?
311
+
312
+ Offline-only probe: `local_files_only=True` never opens a socket, so this
313
+ is safe to call on every search. Any failure (not cached, no hub package,
314
+ unreadable cache) answers False — the caller degrades to identity.
315
+ """
316
+ try:
317
+ from huggingface_hub import snapshot_download
318
+
319
+ snapshot_download(
320
+ hf_repo,
321
+ allow_patterns=[onnx_file, onnx_file + "_data", "tokenizer*", "*.json"],
322
+ local_files_only=True,
323
+ )
324
+ return True
325
+ except Exception:
326
+ return False
327
+
328
+
329
+ def warm_reranker_weights() -> dict[str, object]:
330
+ """Download the reranker weights — the ONE place allowed to use the network
331
+ for them. Called by `brain warmup` beside the embedder warm, so a user who
332
+ warms up still gets reranking; a user who does not gets the unreranked
333
+ order instead of a surprise download mid-query."""
334
+ repo = OPEN_DEFAULT_RERANKER_REPO
335
+ onnx_file = OPEN_DEFAULT_RERANKER_ONNX
336
+ if _reranker_weights_cached(repo, onnx_file):
337
+ return {"repo": repo, "downloaded": False, "cached": True}
338
+ from huggingface_hub import snapshot_download
339
+
340
+ snapshot_download(
341
+ repo,
342
+ allow_patterns=[onnx_file, onnx_file + "_data", "tokenizer*", "*.json"],
343
+ )
344
+ return {"repo": repo, "downloaded": True, "cached": True}
345
+
346
+
309
347
  class OnnxReranker:
310
348
  """Any HuggingFace ONNX cross-encoder reranker loaded DIRECTLY via ONNX
311
349
  Runtime — no fastembed-catalog dependency, no PyTorch at runtime.
@@ -334,14 +372,34 @@ class OnnxReranker:
334
372
  self._in_names: list[str] | None = None
335
373
 
336
374
  @staticmethod
337
- def available() -> bool:
375
+ def available(*, hf_repo: str | None = None, onnx_file: str | None = None) -> bool:
376
+ """Usable RIGHT NOW, WITHOUT the network.
377
+
378
+ This used to answer "are onnxruntime and tokenizers importable?", which
379
+ made `get_reranker("auto")` hand back a reranker whose `_ensure()` then
380
+ went and DOWNLOADED the cross-encoder mid-search. Once BR-03 made
381
+ reranking default-on, that turned every first `brain search` on a cold
382
+ machine into a model download — on a path that has no business touching
383
+ the network, including `BRAIN_EMBEDDER=hash` (which asks for no model at
384
+ all) and the Cowork VM (which has no HF egress). Measured 2026-08-07:
385
+ the distribution-matrix "offline retrieval smoke (no network)" job
386
+ downloaded 6 files on both macOS and Windows.
387
+
388
+ So availability now also requires the weights to be in the local cache.
389
+ Absent, this returns False, `get_reranker("auto")` returns NoopReranker,
390
+ and RET-02's skippable contract degrades retrieval to the unreranked
391
+ order cleanly — no exception, no per-query warning, no network. The one
392
+ sanctioned way to fetch the weights is `brain warmup`.
393
+ """
338
394
  try:
339
395
  import onnxruntime # noqa: F401
340
396
  import tokenizers # noqa: F401
341
-
342
- return True
343
397
  except Exception:
344
398
  return False
399
+ if os.environ.get("BRAIN_RERANKER_ONNX_DIR"):
400
+ return True
401
+ return _reranker_weights_cached(hf_repo or OPEN_DEFAULT_RERANKER_REPO,
402
+ onnx_file or OPEN_DEFAULT_RERANKER_ONNX)
345
403
 
346
404
  def _ensure(self):
347
405
  if self._sess is None:
@@ -361,6 +419,12 @@ class OnnxReranker:
361
419
  else:
362
420
  from huggingface_hub import snapshot_download
363
421
 
422
+ # local_files_only: belt AND braces. `available()` already
423
+ # refuses to hand out this reranker uncached, but a caller
424
+ # can construct OnnxReranker directly (tests, an explicit
425
+ # BRAIN_RERANKER_PREFER=onnx), and a search must never open
426
+ # a socket. Uncached => raises => RET-02 degrades to the
427
+ # unreranked order. `brain warmup` is the download path.
364
428
  base = snapshot_download(
365
429
  self._hf_repo,
366
430
  allow_patterns=[
@@ -369,6 +433,7 @@ class OnnxReranker:
369
433
  "tokenizer*",
370
434
  "*.json",
371
435
  ],
436
+ local_files_only=True,
372
437
  )
373
438
  onnx_path = os.path.join(base, self._onnx_file)
374
439
  so = ort.SessionOptions()
@@ -471,8 +536,13 @@ def get_reranker(prefer: str = "noop") -> Reranker:
471
536
  # replaces the CC-BY-NC jina-reranker-v2). Preferred over the fastembed path.
472
537
  if OnnxReranker.available():
473
538
  return OnnxReranker()
474
- if GteReranker.available():
475
- return GteReranker()
539
+ # NOT GteReranker here any more (0.20.1). Its `available()` answers "is
540
+ # fastembed importable?", so auto used to fall through to it whenever the
541
+ # open ONNX weights were uncached — and it would then download from
542
+ # fastembed's own catalogue mid-search, which is the very thing this
543
+ # release stops. It is also the CC-BY-NC jina path, which auto should
544
+ # never reach for on its own. Still selectable deliberately, with
545
+ # `BRAIN_RERANKER_PREFER=gte` or `get_reranker("gte")`.
476
546
  return NoopReranker()
477
547
 
478
548
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brainiac-cli
3
- Version: 0.20.0
3
+ Version: 0.20.2
4
4
  Summary: Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index).
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.9
File without changes
File without changes
File without changes
File without changes