secondbrain-py 0.2.1__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 (574) hide show
  1. secondbrain_py-0.2.1/LICENSE +21 -0
  2. secondbrain_py-0.2.1/PKG-INFO +195 -0
  3. secondbrain_py-0.2.1/README.md +152 -0
  4. secondbrain_py-0.2.1/pyproject.toml +219 -0
  5. secondbrain_py-0.2.1/setup.cfg +4 -0
  6. secondbrain_py-0.2.1/src/brain/__init__.py +0 -0
  7. secondbrain_py-0.2.1/src/brain/__main__.py +18 -0
  8. secondbrain_py-0.2.1/src/brain/_capture_command.py +445 -0
  9. secondbrain_py-0.2.1/src/brain/_compose.py +52 -0
  10. secondbrain_py-0.2.1/src/brain/activity.py +206 -0
  11. secondbrain_py-0.2.1/src/brain/ask.py +631 -0
  12. secondbrain_py-0.2.1/src/brain/audio.py +591 -0
  13. secondbrain_py-0.2.1/src/brain/backfill/__init__.py +12 -0
  14. secondbrain_py-0.2.1/src/brain/backfill/search_extras.py +141 -0
  15. secondbrain_py-0.2.1/src/brain/backfill/source_rows.py +101 -0
  16. secondbrain_py-0.2.1/src/brain/bin/__init__.py +1 -0
  17. secondbrain_py-0.2.1/src/brain/bin/_launcher.py +107 -0
  18. secondbrain_py-0.2.1/src/brain/bin/down.py +8 -0
  19. secondbrain_py-0.2.1/src/brain/bin/launchd.py +268 -0
  20. secondbrain_py-0.2.1/src/brain/bin/monitor.py +570 -0
  21. secondbrain_py-0.2.1/src/brain/bin/rebuild.py +8 -0
  22. secondbrain_py-0.2.1/src/brain/bin/status.py +8 -0
  23. secondbrain_py-0.2.1/src/brain/bin/up.py +8 -0
  24. secondbrain_py-0.2.1/src/brain/brief.py +272 -0
  25. secondbrain_py-0.2.1/src/brain/capture.py +49 -0
  26. secondbrain_py-0.2.1/src/brain/chat.py +293 -0
  27. secondbrain_py-0.2.1/src/brain/cli.py +9760 -0
  28. secondbrain_py-0.2.1/src/brain/cli_claude.py +81 -0
  29. secondbrain_py-0.2.1/src/brain/cli_connect.py +285 -0
  30. secondbrain_py-0.2.1/src/brain/cli_demo.py +266 -0
  31. secondbrain_py-0.2.1/src/brain/config.py +1949 -0
  32. secondbrain_py-0.2.1/src/brain/connect.py +925 -0
  33. secondbrain_py-0.2.1/src/brain/db.py +540 -0
  34. secondbrain_py-0.2.1/src/brain/demo/__init__.py +452 -0
  35. secondbrain_py-0.2.1/src/brain/demo/corpus/manifest.json +403 -0
  36. secondbrain_py-0.2.1/src/brain/demo/embedder.py +74 -0
  37. secondbrain_py-0.2.1/src/brain/durations.py +84 -0
  38. secondbrain_py-0.2.1/src/brain/edit_session.py +156 -0
  39. secondbrain_py-0.2.1/src/brain/editor.py +67 -0
  40. secondbrain_py-0.2.1/src/brain/elicit/__init__.py +16 -0
  41. secondbrain_py-0.2.1/src/brain/elicit/detectors.py +250 -0
  42. secondbrain_py-0.2.1/src/brain/elicit/drafter.py +70 -0
  43. secondbrain_py-0.2.1/src/brain/elicit/queue.py +220 -0
  44. secondbrain_py-0.2.1/src/brain/elicit/schema.py +48 -0
  45. secondbrain_py-0.2.1/src/brain/elicit/session.py +445 -0
  46. secondbrain_py-0.2.1/src/brain/embedding_targets.py +54 -0
  47. secondbrain_py-0.2.1/src/brain/embeddings.py +424 -0
  48. secondbrain_py-0.2.1/src/brain/enrichment.py +808 -0
  49. secondbrain_py-0.2.1/src/brain/errors.py +357 -0
  50. secondbrain_py-0.2.1/src/brain/eval/__init__.py +129 -0
  51. secondbrain_py-0.2.1/src/brain/eval/answer_eval.py +281 -0
  52. secondbrain_py-0.2.1/src/brain/eval/baseline.py +265 -0
  53. secondbrain_py-0.2.1/src/brain/eval/concept_extraction.py +378 -0
  54. secondbrain_py-0.2.1/src/brain/eval/corpus.py +152 -0
  55. secondbrain_py-0.2.1/src/brain/eval/errors.py +19 -0
  56. secondbrain_py-0.2.1/src/brain/eval/graph_baseline.py +226 -0
  57. secondbrain_py-0.2.1/src/brain/eval/graph_retrieval.py +202 -0
  58. secondbrain_py-0.2.1/src/brain/eval/graph_runner.py +319 -0
  59. secondbrain_py-0.2.1/src/brain/eval/metrics.py +101 -0
  60. secondbrain_py-0.2.1/src/brain/eval/runner.py +223 -0
  61. secondbrain_py-0.2.1/src/brain/format.py +783 -0
  62. secondbrain_py-0.2.1/src/brain/gaps.py +390 -0
  63. secondbrain_py-0.2.1/src/brain/graph_rag/__init__.py +94 -0
  64. secondbrain_py-0.2.1/src/brain/graph_rag/_retrieval_common.py +113 -0
  65. secondbrain_py-0.2.1/src/brain/graph_rag/aggregates.py +303 -0
  66. secondbrain_py-0.2.1/src/brain/graph_rag/aliases/__init__.py +583 -0
  67. secondbrain_py-0.2.1/src/brain/graph_rag/backends/__init__.py +10 -0
  68. secondbrain_py-0.2.1/src/brain/graph_rag/backends/_age_helpers.py +473 -0
  69. secondbrain_py-0.2.1/src/brain/graph_rag/backends/age.py +782 -0
  70. secondbrain_py-0.2.1/src/brain/graph_rag/backends/base.py +272 -0
  71. secondbrain_py-0.2.1/src/brain/graph_rag/build.py +344 -0
  72. secondbrain_py-0.2.1/src/brain/graph_rag/communities.py +644 -0
  73. secondbrain_py-0.2.1/src/brain/graph_rag/communities_summary.py +437 -0
  74. secondbrain_py-0.2.1/src/brain/graph_rag/concepts.py +202 -0
  75. secondbrain_py-0.2.1/src/brain/graph_rag/cooccur.py +193 -0
  76. secondbrain_py-0.2.1/src/brain/graph_rag/cross_type.py +312 -0
  77. secondbrain_py-0.2.1/src/brain/graph_rag/extract.py +885 -0
  78. secondbrain_py-0.2.1/src/brain/graph_rag/fuse.py +371 -0
  79. secondbrain_py-0.2.1/src/brain/graph_rag/global_.py +412 -0
  80. secondbrain_py-0.2.1/src/brain/graph_rag/grouping.py +372 -0
  81. secondbrain_py-0.2.1/src/brain/graph_rag/person_resolver.py +167 -0
  82. secondbrain_py-0.2.1/src/brain/graph_rag/reconcile.py +792 -0
  83. secondbrain_py-0.2.1/src/brain/graph_rag/relational.py +353 -0
  84. secondbrain_py-0.2.1/src/brain/graph_rag/retrieve.py +526 -0
  85. secondbrain_py-0.2.1/src/brain/graph_rag/router.py +288 -0
  86. secondbrain_py-0.2.1/src/brain/graph_rag/schema.py +320 -0
  87. secondbrain_py-0.2.1/src/brain/graph_rag/sync.py +237 -0
  88. secondbrain_py-0.2.1/src/brain/graph_rag/tenancy.py +43 -0
  89. secondbrain_py-0.2.1/src/brain/graph_rag/themes.py +501 -0
  90. secondbrain_py-0.2.1/src/brain/graph_rag/weighting.py +202 -0
  91. secondbrain_py-0.2.1/src/brain/ingest/__init__.py +1926 -0
  92. secondbrain_py-0.2.1/src/brain/ingest/chunker.py +249 -0
  93. secondbrain_py-0.2.1/src/brain/ingest/docx.py +40 -0
  94. secondbrain_py-0.2.1/src/brain/ingest/gmail.py +621 -0
  95. secondbrain_py-0.2.1/src/brain/ingest/markdown.py +37 -0
  96. secondbrain_py-0.2.1/src/brain/ingest/pdf.py +61 -0
  97. secondbrain_py-0.2.1/src/brain/ingest/stdin.py +22 -0
  98. secondbrain_py-0.2.1/src/brain/ingest/sub_tokens.py +91 -0
  99. secondbrain_py-0.2.1/src/brain/ingest/text.py +16 -0
  100. secondbrain_py-0.2.1/src/brain/interactions.py +205 -0
  101. secondbrain_py-0.2.1/src/brain/maintenance.py +355 -0
  102. secondbrain_py-0.2.1/src/brain/mcp_server.py +3405 -0
  103. secondbrain_py-0.2.1/src/brain/migrations/001_init.sql +43 -0
  104. secondbrain_py-0.2.1/src/brain/migrations/002_qwen3_embedding.sql +17 -0
  105. secondbrain_py-0.2.1/src/brain/migrations/003_vault_model.sql +41 -0
  106. secondbrain_py-0.2.1/src/brain/migrations/004_relax_content_hash_uniqueness.sql +18 -0
  107. secondbrain_py-0.2.1/src/brain/migrations/005_derived_links.sql +67 -0
  108. secondbrain_py-0.2.1/src/brain/migrations/006_dedup_file_by_source_path.sql +25 -0
  109. secondbrain_py-0.2.1/src/brain/migrations/007_email_thread_and_draft.sql +15 -0
  110. secondbrain_py-0.2.1/src/brain/migrations/008_gmail_thread_unique.sql +11 -0
  111. secondbrain_py-0.2.1/src/brain/migrations/009_chunks_weighted_tsv.sql +28 -0
  112. secondbrain_py-0.2.1/src/brain/migrations/010_interactions.sql +30 -0
  113. secondbrain_py-0.2.1/src/brain/migrations/011_documents_summary.sql +23 -0
  114. secondbrain_py-0.2.1/src/brain/migrations/012_graphrag.sql +171 -0
  115. secondbrain_py-0.2.1/src/brain/migrations/013_graphrag_communities.sql +125 -0
  116. secondbrain_py-0.2.1/src/brain/migrations/014_graphrag_community_summary_hash.sql +33 -0
  117. secondbrain_py-0.2.1/src/brain/migrations/015_interactions_graph_targets.sql +89 -0
  118. secondbrain_py-0.2.1/src/brain/migrations/016_index_hygiene.sql +61 -0
  119. secondbrain_py-0.2.1/src/brain/migrations/017_elicit.sql +30 -0
  120. secondbrain_py-0.2.1/src/brain/migrations/018_review_gap_signal_kinds.sql +40 -0
  121. secondbrain_py-0.2.1/src/brain/migrations/019_search_queries.sql +35 -0
  122. secondbrain_py-0.2.1/src/brain/migrations/020_link_suggestions.sql +40 -0
  123. secondbrain_py-0.2.1/src/brain/migrations/021_timeline_doc_date.sql +34 -0
  124. secondbrain_py-0.2.1/src/brain/migrations/022_link_suggestions_undirected.sql +84 -0
  125. secondbrain_py-0.2.1/src/brain/migrations/023_search_queries_fts_count.sql +28 -0
  126. secondbrain_py-0.2.1/src/brain/quartz_overrides/__init__.py +8 -0
  127. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/bootstrap-cli.mjs +65 -0
  128. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/build.ts +568 -0
  129. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/cli/args.js +152 -0
  130. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/cli/build_partial_handler.js +544 -0
  131. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/cli/handlers.js +636 -0
  132. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/CommandPalette.tsx +172 -0
  133. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/Explorer.tsx +198 -0
  134. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/Footer.tsx +27 -0
  135. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/Graph.tsx +468 -0
  136. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/PageTitle.tsx +72 -0
  137. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/RelatedDocs.tsx +38 -0
  138. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/Search.tsx +161 -0
  139. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/SummaryLede.tsx +72 -0
  140. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/index.ts +92 -0
  141. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/pages/TagContent.tsx +272 -0
  142. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/scripts/commandPalette.inline.ts +665 -0
  143. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/scripts/explorer.inline.ts +768 -0
  144. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/scripts/graph.inline.ts +2302 -0
  145. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/scripts/relatedDocs.inline.ts +163 -0
  146. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/components/scripts/search.inline.ts +1011 -0
  147. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/emitters/contentIndex.ts +546 -0
  148. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/codeCopy.ts +94 -0
  149. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/derivedFenceMark.ts +302 -0
  150. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/emailThread.ts +148 -0
  151. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/emptyDoorFilter.ts +213 -0
  152. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/index.ts +114 -0
  153. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/linkKindMark.ts +205 -0
  154. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/linkSourceTag.ts +104 -0
  155. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/relativeDate.ts +100 -0
  156. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/plugins/transformers/reloadSignal.ts +131 -0
  157. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/processors/parse.ts +371 -0
  158. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/processors/parser_cache.ts +78 -0
  159. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/brain-logo-dark.png +0 -0
  160. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/brain-logo-light.png +0 -0
  161. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/codeCopy.js +196 -0
  162. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/emailThread.js +334 -0
  163. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/favicon.ico +0 -0
  164. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/icon.png +0 -0
  165. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/linkSourceTag.js +104 -0
  166. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/relativeDate.js +142 -0
  167. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/static/reload.js +168 -0
  168. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_article.scss +252 -0
  169. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_atmosphere.scss +113 -0
  170. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_callouts.scss +180 -0
  171. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_cmdk.scss +7 -0
  172. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_code.scss +208 -0
  173. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_command_palette.scss +369 -0
  174. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_email_thread.scss +228 -0
  175. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_explorer.scss +142 -0
  176. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_home.scss +182 -0
  177. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_links.scss +322 -0
  178. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_marginalia.scss +117 -0
  179. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_motion.scss +175 -0
  180. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_people_hub.scss +100 -0
  181. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_related_docs.scss +137 -0
  182. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_search.scss +252 -0
  183. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_sidebar.scss +468 -0
  184. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_summary_lede.scss +56 -0
  185. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_surface.scss +43 -0
  186. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_tag_content.scss +118 -0
  187. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_tokens.scss +197 -0
  188. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/brain/_typography.scss +92 -0
  189. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/custom.scss +89 -0
  190. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/styles/graph.scss +505 -0
  191. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/util/ctx.ts +92 -0
  192. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/util/fastpath_manifest.ts +608 -0
  193. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/util/path.ts +358 -0
  194. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz/util/sourceIcons.ts +55 -0
  195. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz.config.ts +270 -0
  196. secondbrain_py-0.2.1/src/brain/quartz_overrides/quartz.layout.ts +314 -0
  197. secondbrain_py-0.2.1/src/brain/queries.py +1188 -0
  198. secondbrain_py-0.2.1/src/brain/rank_fusion.py +8 -0
  199. secondbrain_py-0.2.1/src/brain/resurface.py +210 -0
  200. secondbrain_py-0.2.1/src/brain/review/__init__.py +26 -0
  201. secondbrain_py-0.2.1/src/brain/review/emit.py +27 -0
  202. secondbrain_py-0.2.1/src/brain/review/queries.py +436 -0
  203. secondbrain_py-0.2.1/src/brain/review/render.py +196 -0
  204. secondbrain_py-0.2.1/src/brain/review/scans.py +355 -0
  205. secondbrain_py-0.2.1/src/brain/review/weekly.py +413 -0
  206. secondbrain_py-0.2.1/src/brain/search.py +704 -0
  207. secondbrain_py-0.2.1/src/brain/set_similarity.py +15 -0
  208. secondbrain_py-0.2.1/src/brain/setup.py +1205 -0
  209. secondbrain_py-0.2.1/src/brain/tags.py +56 -0
  210. secondbrain_py-0.2.1/src/brain/templates/Caddyfile.j2 +9 -0
  211. secondbrain_py-0.2.1/src/brain/templates/__init__.py +1 -0
  212. secondbrain_py-0.2.1/src/brain/templates/bin/__init__.py +1 -0
  213. secondbrain_py-0.2.1/src/brain/templates/bin/_brain-brief-fg.sh +25 -0
  214. secondbrain_py-0.2.1/src/brain/templates/bin/_brain-build-fg.sh +53 -0
  215. secondbrain_py-0.2.1/src/brain/templates/bin/_brain-watcher-fg.sh +65 -0
  216. secondbrain_py-0.2.1/src/brain/templates/bin/brain-down.sh +89 -0
  217. secondbrain_py-0.2.1/src/brain/templates/bin/brain-status.sh +83 -0
  218. secondbrain_py-0.2.1/src/brain/templates/bin/brain-up.sh +221 -0
  219. secondbrain_py-0.2.1/src/brain/templates/docker/age/Dockerfile +79 -0
  220. secondbrain_py-0.2.1/src/brain/templates/docker-compose.stock.yml.j2 +26 -0
  221. secondbrain_py-0.2.1/src/brain/templates/docker-compose.yml.j2 +34 -0
  222. secondbrain_py-0.2.1/src/brain/templates/env.example +190 -0
  223. secondbrain_py-0.2.1/src/brain/templates/launchd/__init__.py +1 -0
  224. secondbrain_py-0.2.1/src/brain/templates/launchd/com.brain.brief.plist.j2 +45 -0
  225. secondbrain_py-0.2.1/src/brain/templates/launchd/com.brain.build.plist.j2 +46 -0
  226. secondbrain_py-0.2.1/src/brain/templates/launchd/com.brain.watcher.plist.j2 +46 -0
  227. secondbrain_py-0.2.1/src/brain/templates/skill/SKILL.md +63 -0
  228. secondbrain_py-0.2.1/src/brain/templates/skill/__init__.py +1 -0
  229. secondbrain_py-0.2.1/src/brain/timeline.py +834 -0
  230. secondbrain_py-0.2.1/src/brain/todo.py +124 -0
  231. secondbrain_py-0.2.1/src/brain/uninstall.py +185 -0
  232. secondbrain_py-0.2.1/src/brain/vault/__init__.py +115 -0
  233. secondbrain_py-0.2.1/src/brain/vault/_atomic.py +25 -0
  234. secondbrain_py-0.2.1/src/brain/vault/daily_index.py +228 -0
  235. secondbrain_py-0.2.1/src/brain/vault/derived_links/__init__.py +50 -0
  236. secondbrain_py-0.2.1/src/brain/vault/derived_links/directory.py +683 -0
  237. secondbrain_py-0.2.1/src/brain/vault/derived_links/fence.py +408 -0
  238. secondbrain_py-0.2.1/src/brain/vault/derived_links/gws.py +64 -0
  239. secondbrain_py-0.2.1/src/brain/vault/derived_links/participants.py +143 -0
  240. secondbrain_py-0.2.1/src/brain/vault/derived_links/pass_runner.py +362 -0
  241. secondbrain_py-0.2.1/src/brain/vault/derived_links/rules.py +137 -0
  242. secondbrain_py-0.2.1/src/brain/vault/export.py +683 -0
  243. secondbrain_py-0.2.1/src/brain/vault/frontmatter.py +165 -0
  244. secondbrain_py-0.2.1/src/brain/vault/graph.py +620 -0
  245. secondbrain_py-0.2.1/src/brain/vault/graph_format.py +388 -0
  246. secondbrain_py-0.2.1/src/brain/vault/link_rewrite.py +235 -0
  247. secondbrain_py-0.2.1/src/brain/vault/links.py +260 -0
  248. secondbrain_py-0.2.1/src/brain/vault/note_builder.py +211 -0
  249. secondbrain_py-0.2.1/src/brain/vault/paths.py +55 -0
  250. secondbrain_py-0.2.1/src/brain/vault/quartz_overlay.py +236 -0
  251. secondbrain_py-0.2.1/src/brain/vault/rename.py +591 -0
  252. secondbrain_py-0.2.1/src/brain/vault/resolver.py +304 -0
  253. secondbrain_py-0.2.1/src/brain/vault/slug.py +127 -0
  254. secondbrain_py-0.2.1/src/brain/vault/sync.py +1513 -0
  255. secondbrain_py-0.2.1/src/brain/vault/sync_summaries.py +264 -0
  256. secondbrain_py-0.2.1/src/brain/vault/templates.py +145 -0
  257. secondbrain_py-0.2.1/src/brain/vault/watch.py +1052 -0
  258. secondbrain_py-0.2.1/src/brain/wiki/__init__.py +6 -0
  259. secondbrain_py-0.2.1/src/brain/wiki/_github_slugger.py +76 -0
  260. secondbrain_py-0.2.1/src/brain/wiki/_person_name.py +314 -0
  261. secondbrain_py-0.2.1/src/brain/wiki/build_homepage.py +541 -0
  262. secondbrain_py-0.2.1/src/brain/wiki/build_partial.py +273 -0
  263. secondbrain_py-0.2.1/src/brain/wiki/build_people.py +934 -0
  264. secondbrain_py-0.2.1/src/brain/wiki/build_related.py +758 -0
  265. secondbrain_py-0.2.1/src/brain/wiki/build_swap.py +585 -0
  266. secondbrain_py-0.2.1/src/brain/wiki/build_watcher.py +975 -0
  267. secondbrain_py-0.2.1/src/brain/wiki/edit_classifier.py +215 -0
  268. secondbrain_py-0.2.1/src/brain/wiki/errors.py +10 -0
  269. secondbrain_py-0.2.1/src/brain/wiki/fastpath_manifest.py +475 -0
  270. secondbrain_py-0.2.1/src/brain/wiki/fastpath_state.py +174 -0
  271. secondbrain_py-0.2.1/src/brain/wiki/install.py +296 -0
  272. secondbrain_py-0.2.1/src/brain/wiki/slug.py +111 -0
  273. secondbrain_py-0.2.1/src/secondbrain_py.egg-info/PKG-INFO +195 -0
  274. secondbrain_py-0.2.1/src/secondbrain_py.egg-info/SOURCES.txt +572 -0
  275. secondbrain_py-0.2.1/src/secondbrain_py.egg-info/dependency_links.txt +1 -0
  276. secondbrain_py-0.2.1/src/secondbrain_py.egg-info/entry_points.txt +11 -0
  277. secondbrain_py-0.2.1/src/secondbrain_py.egg-info/requires.txt +26 -0
  278. secondbrain_py-0.2.1/src/secondbrain_py.egg-info/top_level.txt +1 -0
  279. secondbrain_py-0.2.1/tests/test_activity.py +195 -0
  280. secondbrain_py-0.2.1/tests/test_answer_eval.py +126 -0
  281. secondbrain_py-0.2.1/tests/test_apply_tags.py +136 -0
  282. secondbrain_py-0.2.1/tests/test_arctic_embedder.py +198 -0
  283. secondbrain_py-0.2.1/tests/test_ask.py +598 -0
  284. secondbrain_py-0.2.1/tests/test_audio.py +971 -0
  285. secondbrain_py-0.2.1/tests/test_backfill_email_columns.py +812 -0
  286. secondbrain_py-0.2.1/tests/test_backfill_search.py +259 -0
  287. secondbrain_py-0.2.1/tests/test_backfill_source_rows.py +258 -0
  288. secondbrain_py-0.2.1/tests/test_bin_launchd.py +275 -0
  289. secondbrain_py-0.2.1/tests/test_bin_launcher.py +270 -0
  290. secondbrain_py-0.2.1/tests/test_bin_monitor.py +301 -0
  291. secondbrain_py-0.2.1/tests/test_bin_scripts.py +1039 -0
  292. secondbrain_py-0.2.1/tests/test_body_hash.py +95 -0
  293. secondbrain_py-0.2.1/tests/test_brain_edit_syncs_chunks.py +80 -0
  294. secondbrain_py-0.2.1/tests/test_brain_recent_homepage.py +825 -0
  295. secondbrain_py-0.2.1/tests/test_brain_skills_sync.py +258 -0
  296. secondbrain_py-0.2.1/tests/test_brain_tag_syncs_chunks.py +110 -0
  297. secondbrain_py-0.2.1/tests/test_brief.py +394 -0
  298. secondbrain_py-0.2.1/tests/test_build_people.py +1623 -0
  299. secondbrain_py-0.2.1/tests/test_build_related.py +269 -0
  300. secondbrain_py-0.2.1/tests/test_build_related_idempotence.py +231 -0
  301. secondbrain_py-0.2.1/tests/test_build_related_schema.py +198 -0
  302. secondbrain_py-0.2.1/tests/test_build_related_signal.py +1119 -0
  303. secondbrain_py-0.2.1/tests/test_buildid_etag.py +445 -0
  304. secondbrain_py-0.2.1/tests/test_capture.py +68 -0
  305. secondbrain_py-0.2.1/tests/test_chat.py +426 -0
  306. secondbrain_py-0.2.1/tests/test_chunker.py +189 -0
  307. secondbrain_py-0.2.1/tests/test_claude_install_skill.py +154 -0
  308. secondbrain_py-0.2.1/tests/test_cli_analyze.py +124 -0
  309. secondbrain_py-0.2.1/tests/test_cli_ask.py +216 -0
  310. secondbrain_py-0.2.1/tests/test_cli_auto_analyze.py +263 -0
  311. secondbrain_py-0.2.1/tests/test_cli_backfill_normalize_tags.py +333 -0
  312. secondbrain_py-0.2.1/tests/test_cli_backlinks.py +259 -0
  313. secondbrain_py-0.2.1/tests/test_cli_capture.py +1097 -0
  314. secondbrain_py-0.2.1/tests/test_cli_daily.py +199 -0
  315. secondbrain_py-0.2.1/tests/test_cli_directory.py +333 -0
  316. secondbrain_py-0.2.1/tests/test_cli_doctor.py +920 -0
  317. secondbrain_py-0.2.1/tests/test_cli_edit.py +511 -0
  318. secondbrain_py-0.2.1/tests/test_cli_edit_editor.py +464 -0
  319. secondbrain_py-0.2.1/tests/test_cli_edit_vault_tier.py +191 -0
  320. secondbrain_py-0.2.1/tests/test_cli_enrich.py +425 -0
  321. secondbrain_py-0.2.1/tests/test_cli_eval.py +300 -0
  322. secondbrain_py-0.2.1/tests/test_cli_explain.py +338 -0
  323. secondbrain_py-0.2.1/tests/test_cli_filter_validation.py +59 -0
  324. secondbrain_py-0.2.1/tests/test_cli_graph.py +542 -0
  325. secondbrain_py-0.2.1/tests/test_cli_graphrag_entity_cap.py +196 -0
  326. secondbrain_py-0.2.1/tests/test_cli_graphrag_search.py +830 -0
  327. secondbrain_py-0.2.1/tests/test_cli_ingest.py +434 -0
  328. secondbrain_py-0.2.1/tests/test_cli_ingest_gmail.py +1340 -0
  329. secondbrain_py-0.2.1/tests/test_cli_ingest_stdin.py +639 -0
  330. secondbrain_py-0.2.1/tests/test_cli_init.py +279 -0
  331. secondbrain_py-0.2.1/tests/test_cli_links.py +304 -0
  332. secondbrain_py-0.2.1/tests/test_cli_note_new.py +540 -0
  333. secondbrain_py-0.2.1/tests/test_cli_note_rename.py +662 -0
  334. secondbrain_py-0.2.1/tests/test_cli_orphans.py +138 -0
  335. secondbrain_py-0.2.1/tests/test_cli_owner.py +248 -0
  336. secondbrain_py-0.2.1/tests/test_cli_people.py +407 -0
  337. secondbrain_py-0.2.1/tests/test_cli_prune_orphans.py +181 -0
  338. secondbrain_py-0.2.1/tests/test_cli_rate.py +337 -0
  339. secondbrain_py-0.2.1/tests/test_cli_reembed.py +488 -0
  340. secondbrain_py-0.2.1/tests/test_cli_relink_derived.py +616 -0
  341. secondbrain_py-0.2.1/tests/test_cli_resurface.py +140 -0
  342. secondbrain_py-0.2.1/tests/test_cli_review.py +100 -0
  343. secondbrain_py-0.2.1/tests/test_cli_review_scan.py +182 -0
  344. secondbrain_py-0.2.1/tests/test_cli_rm.py +332 -0
  345. secondbrain_py-0.2.1/tests/test_cli_search.py +315 -0
  346. secondbrain_py-0.2.1/tests/test_cli_setup.py +83 -0
  347. secondbrain_py-0.2.1/tests/test_cli_show_interaction.py +165 -0
  348. secondbrain_py-0.2.1/tests/test_cli_show_list.py +236 -0
  349. secondbrain_py-0.2.1/tests/test_cli_show_summary.py +97 -0
  350. secondbrain_py-0.2.1/tests/test_cli_smoke.py +27 -0
  351. secondbrain_py-0.2.1/tests/test_cli_status.py +97 -0
  352. secondbrain_py-0.2.1/tests/test_cli_tag.py +426 -0
  353. secondbrain_py-0.2.1/tests/test_cli_tag_auto.py +270 -0
  354. secondbrain_py-0.2.1/tests/test_cli_tag_rm.py +145 -0
  355. secondbrain_py-0.2.1/tests/test_cli_todo.py +165 -0
  356. secondbrain_py-0.2.1/tests/test_cli_vault_render.py +502 -0
  357. secondbrain_py-0.2.1/tests/test_cli_vault_sync.py +242 -0
  358. secondbrain_py-0.2.1/tests/test_cli_vault_watch.py +184 -0
  359. secondbrain_py-0.2.1/tests/test_collapse_gmail_threads.py +966 -0
  360. secondbrain_py-0.2.1/tests/test_compose_helper.py +71 -0
  361. secondbrain_py-0.2.1/tests/test_compose_no_raw_calls.py +84 -0
  362. secondbrain_py-0.2.1/tests/test_concept_extraction_metric.py +339 -0
  363. secondbrain_py-0.2.1/tests/test_config.py +1211 -0
  364. secondbrain_py-0.2.1/tests/test_config_audio_envvars.py +104 -0
  365. secondbrain_py-0.2.1/tests/test_config_enrich_envvars.py +166 -0
  366. secondbrain_py-0.2.1/tests/test_conftest_prod_guard.py +87 -0
  367. secondbrain_py-0.2.1/tests/test_connect.py +1739 -0
  368. secondbrain_py-0.2.1/tests/test_contentindex_slim.py +717 -0
  369. secondbrain_py-0.2.1/tests/test_daily_index.py +471 -0
  370. secondbrain_py-0.2.1/tests/test_database_url_isolation.py +140 -0
  371. secondbrain_py-0.2.1/tests/test_db.py +524 -0
  372. secondbrain_py-0.2.1/tests/test_db_age_bootstrap.py +460 -0
  373. secondbrain_py-0.2.1/tests/test_demo_cli.py +292 -0
  374. secondbrain_py-0.2.1/tests/test_demo_core.py +192 -0
  375. secondbrain_py-0.2.1/tests/test_demo_corpus.py +152 -0
  376. secondbrain_py-0.2.1/tests/test_demo_embedder.py +71 -0
  377. secondbrain_py-0.2.1/tests/test_demo_seed.py +140 -0
  378. secondbrain_py-0.2.1/tests/test_dev_dependency_pins.py +16 -0
  379. secondbrain_py-0.2.1/tests/test_docs_assets.py +160 -0
  380. secondbrain_py-0.2.1/tests/test_docs_assets_ask.py +129 -0
  381. secondbrain_py-0.2.1/tests/test_docs_assets_graphrag.py +153 -0
  382. secondbrain_py-0.2.1/tests/test_docs_assets_mcp.py +134 -0
  383. secondbrain_py-0.2.1/tests/test_docs_assets_proactivity.py +160 -0
  384. secondbrain_py-0.2.1/tests/test_docs_assets_wiki.py +186 -0
  385. secondbrain_py-0.2.1/tests/test_doctor_chunks_stats.py +104 -0
  386. secondbrain_py-0.2.1/tests/test_doctor_inbox.py +189 -0
  387. secondbrain_py-0.2.1/tests/test_doctor_npx_check.py +269 -0
  388. secondbrain_py-0.2.1/tests/test_draft_quarantine.py +416 -0
  389. secondbrain_py-0.2.1/tests/test_durations.py +107 -0
  390. secondbrain_py-0.2.1/tests/test_editor.py +120 -0
  391. secondbrain_py-0.2.1/tests/test_elicit_cli.py +306 -0
  392. secondbrain_py-0.2.1/tests/test_elicit_detectors.py +332 -0
  393. secondbrain_py-0.2.1/tests/test_elicit_drafter.py +231 -0
  394. secondbrain_py-0.2.1/tests/test_elicit_queue.py +627 -0
  395. secondbrain_py-0.2.1/tests/test_elicit_schema.py +57 -0
  396. secondbrain_py-0.2.1/tests/test_elicit_session.py +661 -0
  397. secondbrain_py-0.2.1/tests/test_email_columns.py +659 -0
  398. secondbrain_py-0.2.1/tests/test_embedding_smoke.py +201 -0
  399. secondbrain_py-0.2.1/tests/test_embeddings.py +113 -0
  400. secondbrain_py-0.2.1/tests/test_embeddings_none.py +292 -0
  401. secondbrain_py-0.2.1/tests/test_enrichment.py +709 -0
  402. secondbrain_py-0.2.1/tests/test_eval_answer_harness.py +133 -0
  403. secondbrain_py-0.2.1/tests/test_eval_baseline.py +338 -0
  404. secondbrain_py-0.2.1/tests/test_eval_corpus.py +333 -0
  405. secondbrain_py-0.2.1/tests/test_eval_fail_below.py +232 -0
  406. secondbrain_py-0.2.1/tests/test_eval_graph_baseline.py +290 -0
  407. secondbrain_py-0.2.1/tests/test_eval_harness_live.py +135 -0
  408. secondbrain_py-0.2.1/tests/test_eval_metrics.py +201 -0
  409. secondbrain_py-0.2.1/tests/test_eval_runner.py +243 -0
  410. secondbrain_py-0.2.1/tests/test_explorer_filter.py +339 -0
  411. secondbrain_py-0.2.1/tests/test_explorer_groupfn.py +445 -0
  412. secondbrain_py-0.2.1/tests/test_format.py +381 -0
  413. secondbrain_py-0.2.1/tests/test_gaps.py +700 -0
  414. secondbrain_py-0.2.1/tests/test_gmail_boilerplate.py +181 -0
  415. secondbrain_py-0.2.1/tests/test_gmail_slug.py +166 -0
  416. secondbrain_py-0.2.1/tests/test_gmail_thread.py +789 -0
  417. secondbrain_py-0.2.1/tests/test_gmail_thread_upsert.py +516 -0
  418. secondbrain_py-0.2.1/tests/test_graph_backend_age.py +999 -0
  419. secondbrain_py-0.2.1/tests/test_graph_backend_base.py +548 -0
  420. secondbrain_py-0.2.1/tests/test_graph_chip_toggle.py +472 -0
  421. secondbrain_py-0.2.1/tests/test_graph_format.py +851 -0
  422. secondbrain_py-0.2.1/tests/test_graph_label_placement.py +145 -0
  423. secondbrain_py-0.2.1/tests/test_graph_queries.py +678 -0
  424. secondbrain_py-0.2.1/tests/test_graph_retrieval_scorer.py +153 -0
  425. secondbrain_py-0.2.1/tests/test_graph_workbench_static.py +186 -0
  426. secondbrain_py-0.2.1/tests/test_graphrag_aliases.py +663 -0
  427. secondbrain_py-0.2.1/tests/test_graphrag_benchmark_fixture.py +266 -0
  428. secondbrain_py-0.2.1/tests/test_graphrag_benchmark_gate.py +800 -0
  429. secondbrain_py-0.2.1/tests/test_graphrag_build.py +1308 -0
  430. secondbrain_py-0.2.1/tests/test_graphrag_cli_mcp_parity.py +131 -0
  431. secondbrain_py-0.2.1/tests/test_graphrag_communities.py +502 -0
  432. secondbrain_py-0.2.1/tests/test_graphrag_communities_summary.py +656 -0
  433. secondbrain_py-0.2.1/tests/test_graphrag_concept_gate.py +203 -0
  434. secondbrain_py-0.2.1/tests/test_graphrag_concepts.py +917 -0
  435. secondbrain_py-0.2.1/tests/test_graphrag_cooccur.py +255 -0
  436. secondbrain_py-0.2.1/tests/test_graphrag_cross_type.py +635 -0
  437. secondbrain_py-0.2.1/tests/test_graphrag_extract.py +1151 -0
  438. secondbrain_py-0.2.1/tests/test_graphrag_fuse.py +616 -0
  439. secondbrain_py-0.2.1/tests/test_graphrag_global.py +690 -0
  440. secondbrain_py-0.2.1/tests/test_graphrag_grouping.py +385 -0
  441. secondbrain_py-0.2.1/tests/test_graphrag_listing.py +828 -0
  442. secondbrain_py-0.2.1/tests/test_graphrag_perf_t4_batching.py +726 -0
  443. secondbrain_py-0.2.1/tests/test_graphrag_reconcile.py +1142 -0
  444. secondbrain_py-0.2.1/tests/test_graphrag_retrieval_eval.py +345 -0
  445. secondbrain_py-0.2.1/tests/test_graphrag_retrieve.py +903 -0
  446. secondbrain_py-0.2.1/tests/test_graphrag_router.py +465 -0
  447. secondbrain_py-0.2.1/tests/test_graphrag_schema.py +329 -0
  448. secondbrain_py-0.2.1/tests/test_graphrag_sync_wiring.py +1139 -0
  449. secondbrain_py-0.2.1/tests/test_graphrag_tenancy.py +63 -0
  450. secondbrain_py-0.2.1/tests/test_graphrag_themes.py +1160 -0
  451. secondbrain_py-0.2.1/tests/test_graphrag_weighting.py +196 -0
  452. secondbrain_py-0.2.1/tests/test_import_hygiene.py +15 -0
  453. secondbrain_py-0.2.1/tests/test_ingest_chunks_search_columns.py +260 -0
  454. secondbrain_py-0.2.1/tests/test_ingest_docx.py +21 -0
  455. secondbrain_py-0.2.1/tests/test_ingest_enrich_hook.py +580 -0
  456. secondbrain_py-0.2.1/tests/test_ingest_gmail_drafts.py +587 -0
  457. secondbrain_py-0.2.1/tests/test_ingest_markdown.py +62 -0
  458. secondbrain_py-0.2.1/tests/test_ingest_pdf.py +35 -0
  459. secondbrain_py-0.2.1/tests/test_ingest_perf_t3.py +525 -0
  460. secondbrain_py-0.2.1/tests/test_ingest_pipeline.py +2037 -0
  461. secondbrain_py-0.2.1/tests/test_ingest_stdin_action_items.py +113 -0
  462. secondbrain_py-0.2.1/tests/test_ingest_text.py +13 -0
  463. secondbrain_py-0.2.1/tests/test_init_auto_runs_backfill.py +171 -0
  464. secondbrain_py-0.2.1/tests/test_install_sh.py +179 -0
  465. secondbrain_py-0.2.1/tests/test_interactions.py +390 -0
  466. secondbrain_py-0.2.1/tests/test_maintenance.py +376 -0
  467. secondbrain_py-0.2.1/tests/test_make_embedder.py +91 -0
  468. secondbrain_py-0.2.1/tests/test_mcp_ask.py +194 -0
  469. secondbrain_py-0.2.1/tests/test_mcp_brief.py +105 -0
  470. secondbrain_py-0.2.1/tests/test_mcp_capture.py +337 -0
  471. secondbrain_py-0.2.1/tests/test_mcp_connect.py +223 -0
  472. secondbrain_py-0.2.1/tests/test_mcp_gaps.py +109 -0
  473. secondbrain_py-0.2.1/tests/test_mcp_graphrag.py +1307 -0
  474. secondbrain_py-0.2.1/tests/test_mcp_limit_guard.py +114 -0
  475. secondbrain_py-0.2.1/tests/test_mcp_perf_t6.py +328 -0
  476. secondbrain_py-0.2.1/tests/test_mcp_rate.py +297 -0
  477. secondbrain_py-0.2.1/tests/test_mcp_resurface.py +160 -0
  478. secondbrain_py-0.2.1/tests/test_mcp_review.py +82 -0
  479. secondbrain_py-0.2.1/tests/test_mcp_review_scan.py +170 -0
  480. secondbrain_py-0.2.1/tests/test_mcp_search_filters.py +233 -0
  481. secondbrain_py-0.2.1/tests/test_mcp_server.py +1445 -0
  482. secondbrain_py-0.2.1/tests/test_mcp_server_protocol.py +126 -0
  483. secondbrain_py-0.2.1/tests/test_mcp_session_tracking.py +309 -0
  484. secondbrain_py-0.2.1/tests/test_mcp_show_summary.py +104 -0
  485. secondbrain_py-0.2.1/tests/test_mcp_vault_tools.py +1043 -0
  486. secondbrain_py-0.2.1/tests/test_migration_003.py +220 -0
  487. secondbrain_py-0.2.1/tests/test_migration_004.py +100 -0
  488. secondbrain_py-0.2.1/tests/test_migration_006.py +68 -0
  489. secondbrain_py-0.2.1/tests/test_migration_012.py +688 -0
  490. secondbrain_py-0.2.1/tests/test_migration_013.py +451 -0
  491. secondbrain_py-0.2.1/tests/test_migration_015.py +227 -0
  492. secondbrain_py-0.2.1/tests/test_migration_016.py +150 -0
  493. secondbrain_py-0.2.1/tests/test_none_backend_mcp.py +131 -0
  494. secondbrain_py-0.2.1/tests/test_packaging_demo.py +93 -0
  495. secondbrain_py-0.2.1/tests/test_packaging_entrypoints.py +138 -0
  496. secondbrain_py-0.2.1/tests/test_packaging_overlay.py +118 -0
  497. secondbrain_py-0.2.1/tests/test_packaging_templates.py +261 -0
  498. secondbrain_py-0.2.1/tests/test_person_name.py +280 -0
  499. secondbrain_py-0.2.1/tests/test_quartz_branding.py +47 -0
  500. secondbrain_py-0.2.1/tests/test_quartz_build_overlay_static.py +256 -0
  501. secondbrain_py-0.2.1/tests/test_quartz_command_palette_static.py +81 -0
  502. secondbrain_py-0.2.1/tests/test_quartz_contentindex_draft_filter.py +102 -0
  503. secondbrain_py-0.2.1/tests/test_quartz_e2e.py +866 -0
  504. secondbrain_py-0.2.1/tests/test_quartz_email_thread_static.py +537 -0
  505. secondbrain_py-0.2.1/tests/test_quartz_fastpath_manifest_static.py +376 -0
  506. secondbrain_py-0.2.1/tests/test_quartz_overlay.py +944 -0
  507. secondbrain_py-0.2.1/tests/test_quartz_overrides_parse.py +188 -0
  508. secondbrain_py-0.2.1/tests/test_quartz_parser_cache_static.py +494 -0
  509. secondbrain_py-0.2.1/tests/test_quartz_people_hub_static.py +133 -0
  510. secondbrain_py-0.2.1/tests/test_quartz_related_docs_static.py +127 -0
  511. secondbrain_py-0.2.1/tests/test_quartz_reload_static.py +58 -0
  512. secondbrain_py-0.2.1/tests/test_quartz_search_static.py +642 -0
  513. secondbrain_py-0.2.1/tests/test_quartz_sidebar_static.py +155 -0
  514. secondbrain_py-0.2.1/tests/test_quartz_tag_content_static.py +467 -0
  515. secondbrain_py-0.2.1/tests/test_quartz_tags_static.py +184 -0
  516. secondbrain_py-0.2.1/tests/test_queries.py +880 -0
  517. secondbrain_py-0.2.1/tests/test_queries_analyze.py +72 -0
  518. secondbrain_py-0.2.1/tests/test_queries_list_existing_tags.py +66 -0
  519. secondbrain_py-0.2.1/tests/test_queries_sync_chunk_metadata.py +153 -0
  520. secondbrain_py-0.2.1/tests/test_qwen3_embedder.py +185 -0
  521. secondbrain_py-0.2.1/tests/test_rank_fusion.py +72 -0
  522. secondbrain_py-0.2.1/tests/test_reembed_none_upgrade.py +108 -0
  523. secondbrain_py-0.2.1/tests/test_rename_helpers.py +68 -0
  524. secondbrain_py-0.2.1/tests/test_rename_plan.py +436 -0
  525. secondbrain_py-0.2.1/tests/test_resolve_person.py +247 -0
  526. secondbrain_py-0.2.1/tests/test_resolver.py +304 -0
  527. secondbrain_py-0.2.1/tests/test_resurface.py +452 -0
  528. secondbrain_py-0.2.1/tests/test_review.py +754 -0
  529. secondbrain_py-0.2.1/tests/test_review_emit.py +49 -0
  530. secondbrain_py-0.2.1/tests/test_review_render.py +145 -0
  531. secondbrain_py-0.2.1/tests/test_review_weekly.py +490 -0
  532. secondbrain_py-0.2.1/tests/test_search.py +227 -0
  533. secondbrain_py-0.2.1/tests/test_search_canary_queries.py +121 -0
  534. secondbrain_py-0.2.1/tests/test_search_compact_query_expansion.py +149 -0
  535. secondbrain_py-0.2.1/tests/test_search_diagnostics.py +100 -0
  536. secondbrain_py-0.2.1/tests/test_search_explain.py +272 -0
  537. secondbrain_py-0.2.1/tests/test_search_floor_default_excludes_known_bad.py +157 -0
  538. secondbrain_py-0.2.1/tests/test_search_metadata_filters.py +665 -0
  539. secondbrain_py-0.2.1/tests/test_search_nofilter_fastpath.py +161 -0
  540. secondbrain_py-0.2.1/tests/test_search_none_backend.py +196 -0
  541. secondbrain_py-0.2.1/tests/test_search_per_doc_cap.py +130 -0
  542. secondbrain_py-0.2.1/tests/test_search_query_embed_cache.py +131 -0
  543. secondbrain_py-0.2.1/tests/test_search_recency_boost.py +252 -0
  544. secondbrain_py-0.2.1/tests/test_search_size_budget.py +166 -0
  545. secondbrain_py-0.2.1/tests/test_search_snippet_context.py +247 -0
  546. secondbrain_py-0.2.1/tests/test_search_vector_floor.py +215 -0
  547. secondbrain_py-0.2.1/tests/test_set_similarity.py +46 -0
  548. secondbrain_py-0.2.1/tests/test_setup.py +1309 -0
  549. secondbrain_py-0.2.1/tests/test_sub_tokens.py +228 -0
  550. secondbrain_py-0.2.1/tests/test_summary_counts_cte.py +109 -0
  551. secondbrain_py-0.2.1/tests/test_sync_one_file.py +346 -0
  552. secondbrain_py-0.2.1/tests/test_t5_llm_keep_alive.py +460 -0
  553. secondbrain_py-0.2.1/tests/test_tags.py +133 -0
  554. secondbrain_py-0.2.1/tests/test_template_render.py +107 -0
  555. secondbrain_py-0.2.1/tests/test_timeline.py +1246 -0
  556. secondbrain_py-0.2.1/tests/test_todo_parse.py +55 -0
  557. secondbrain_py-0.2.1/tests/test_uninstall.py +236 -0
  558. secondbrain_py-0.2.1/tests/test_vault_atomic.py +96 -0
  559. secondbrain_py-0.2.1/tests/test_vault_export.py +1324 -0
  560. secondbrain_py-0.2.1/tests/test_vault_export_gmail_slug.py +196 -0
  561. secondbrain_py-0.2.1/tests/test_vault_frontmatter.py +368 -0
  562. secondbrain_py-0.2.1/tests/test_vault_init.py +132 -0
  563. secondbrain_py-0.2.1/tests/test_vault_link_rewrite.py +752 -0
  564. secondbrain_py-0.2.1/tests/test_vault_note_builder.py +358 -0
  565. secondbrain_py-0.2.1/tests/test_vault_paths.py +64 -0
  566. secondbrain_py-0.2.1/tests/test_vault_slug.py +67 -0
  567. secondbrain_py-0.2.1/tests/test_vault_sync.py +2321 -0
  568. secondbrain_py-0.2.1/tests/test_vault_sync_link_rewrite.py +433 -0
  569. secondbrain_py-0.2.1/tests/test_vault_sync_path_classification.py +257 -0
  570. secondbrain_py-0.2.1/tests/test_vault_sync_summaries.py +361 -0
  571. secondbrain_py-0.2.1/tests/test_vault_watcher.py +2460 -0
  572. secondbrain_py-0.2.1/tests/test_verify_fastpath_static.py +348 -0
  573. secondbrain_py-0.2.1/tests/test_wiki_install.py +328 -0
  574. secondbrain_py-0.2.1/tests/test_wiki_link_parser.py +275 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ali Sarkis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: secondbrain-py
3
+ Version: 0.2.1
4
+ Summary: Local personal knowledge base with hybrid search, queryable by Claude
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/mshtawythug/second-brain
7
+ Project-URL: Repository, https://github.com/mshtawythug/second-brain
8
+ Project-URL: Issues, https://github.com/mshtawythug/second-brain/issues
9
+ Keywords: second-brain,knowledge-base,rag,pgvector,hybrid-search,mcp,ollama,local-first
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Environment :: Console
13
+ Classifier: Topic :: Text Processing :: Indexing
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: psycopg[binary]>=3.2
18
+ Requires-Dist: pgvector>=0.3
19
+ Requires-Dist: httpx>=0.27
20
+ Requires-Dist: pypdf>=5.0
21
+ Requires-Dist: pdfplumber>=0.11
22
+ Requires-Dist: python-docx>=1.1
23
+ Requires-Dist: markdown-it-py>=3.0
24
+ Requires-Dist: typer>=0.13
25
+ Requires-Dist: rich>=13.9
26
+ Requires-Dist: python-dotenv>=1.0
27
+ Requires-Dist: tiktoken>=0.8
28
+ Requires-Dist: mcp<2.0,>=1.0
29
+ Requires-Dist: voyageai>=0.3
30
+ Requires-Dist: pyyaml>=6.0
31
+ Requires-Dist: watchdog>=4.0
32
+ Requires-Dist: networkx>=3.2
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=8.3; extra == "dev"
35
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
36
+ Requires-Dist: coverage<7.13; extra == "dev"
37
+ Requires-Dist: pytest-mock>=3.14; extra == "dev"
38
+ Requires-Dist: ruff>=0.7; extra == "dev"
39
+ Requires-Dist: mypy>=1.13; extra == "dev"
40
+ Requires-Dist: reportlab>=4.0; extra == "dev"
41
+ Requires-Dist: types-PyYAML>=6.0; extra == "dev"
42
+ Dynamic: license-file
43
+
44
+ <!-- mcp-name: io.github.mshtawythug/second-brain -->
45
+
46
+ # Second Brain
47
+
48
+ Local, queryable knowledge base and note vault with hybrid search and an entity-graph layer — searchable by any AI coding agent or assistant from any conversation.
49
+
50
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
51
+ [![CI](https://github.com/mshtawythug/second-brain/actions/workflows/eval.yml/badge.svg)](https://github.com/mshtawythug/second-brain/actions/workflows/eval.yml)
52
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
53
+
54
+ Stores career docs, interview prep, Krisp transcripts, Slack threads, Gmail, and authored Markdown notes in Postgres + pgvector. Any agent reaches all of it through the `brain` CLI or the bundled `brain-mcp` MCP server — no re-pasting context into every chat.
55
+
56
+ The everyday loop — capture a note, search it back, read the top hit, check the corpus:
57
+
58
+ ![brain daily workflow](docs/assets/usage.gif)
59
+
60
+ ## Token savings
61
+
62
+ Querying `brain` returns a ranked snippet instead of dumping whole threads and files into an agent's context, so a lookup costs a fraction of the tokens a direct MCP or file read would:
63
+
64
+ | Source | Direct read (MCP / `Read` tool) | Via `brain` (search + optional `show`) | Savings |
65
+ |---|---|---|---|
66
+ | **Gmail thread** | 15–50k (metadata + full threads with quoted replies / headers) | ~2–4k (snippets + one targeted `brain show`) | **~5–15×** |
67
+ | **Krisp transcript** | 25–75k (search + full transcripts across candidates) | ~6–16k (search + one relevant transcript) | **~4–10×** |
68
+ | **Long PDF / DOCX (30+ pages)** | 15–25k (read the whole file) | ~1–9k (one snippet + targeted `show`) | **~5–15×** |
69
+
70
+ Brain stores pre-extracted, quote-stripped bodies and hybrid-ranks *before* fetching, so only the passage that matched enters context. See the [full per-source breakdown](docs/configuration.md#token-economics).
71
+
72
+ ## See it in 60 seconds
73
+
74
+ Install the CLI, then run the offline demo — a throwaway Postgres seeded with a synthetic *Larkspur* compliance corpus. No Ollama, no personal data, no model downloads:
75
+
76
+ ```bash
77
+ pipx install secondbrain-py
78
+ # or, with uv:
79
+ uv tool install secondbrain-py
80
+ # or, pin the git tag (no PyPI needed):
81
+ pipx install git+https://github.com/mshtawythug/second-brain.git@v0.2.1
82
+
83
+ brain demo # spins up a sandbox Postgres, seeds 22 docs, runs a hero query
84
+ ```
85
+
86
+ ![brain demo](docs/assets/demo.gif)
87
+
88
+ _(IDs and scores are per-run; the seeded corpus and its ranking are deterministic — the top hit is always the "Compliance Horror Stories" note.)_
89
+
90
+ Try these next:
91
+
92
+ ```bash
93
+ brain demo query "SOC 2 evidence request" # a targeted follow-up query
94
+ brain demo query "vendor risk" --source gmail # narrow by source
95
+ brain show <id> # read the top hit in full (in your own brain)
96
+ brain demo teardown # remove the sandbox when done
97
+ ```
98
+
99
+ `brain demo` needs only Docker; `brain demo teardown` destroys the sandbox.
100
+
101
+ Already ran the demo? You have `brain` installed — jump straight to `brain setup --profile …` below.
102
+
103
+ ## Quick start
104
+
105
+ Full install — the `brain` CLI plus the runtime (Postgres, and optionally Ollama / graph / wiki):
106
+
107
+ ```bash
108
+ curl -fsSL https://raw.githubusercontent.com/mshtawythug/second-brain/v0.2.1/install.sh | bash
109
+ ```
110
+
111
+ The installer pipx-installs `brain` from the `v0.2.1` tag, then runs `brain setup` to provision `$BRAIN_HOME`, start the Postgres container, and (optionally) install the wiki + Claude Code skill. Choose how much to stand up with `--profile`:
112
+
113
+ | Profile | Search | Extra dependencies beyond the core |
114
+ |---|---|---|
115
+ | `minimal` | FTS-only (`BRAIN_EMBEDDER=none`) | None — core only (no Ollama, no models). |
116
+ | `standard` *(default)* | Hybrid (FTS + vector) | + Ollama + one ~1 GB embedding model (`snowflake-arctic-embed2`). |
117
+ | `full` | Hybrid + GraphRAG + wiki | + Apache AGE image, concept-extraction LLM, Quartz/Caddy wiki, and (opt-in) launchd daemons via `--daemons`. |
118
+
119
+ ```bash
120
+ brain setup --profile minimal # Docker-only, FTS search — fastest to stand up
121
+ brain setup --profile standard # default: local hybrid search
122
+ brain setup --profile full --daemons
123
+ ```
124
+
125
+ **Prerequisites (core):** Git, Python 3.11+, and a running Docker (Desktop or Engine) — the Postgres + pgvector database runs in a container on port 55432.
126
+
127
+ **Optional extras** (only if you want more than FTS-only search):
128
+
129
+ - **[Ollama](https://ollama.com/)** — local, free embeddings + LLM enrichment. To upgrade a `minimal` (FTS-only) brain to hybrid search: install Ollama, then `ollama pull snowflake-arctic-embed2`, set `BRAIN_EMBEDDER=arctic` in `.env`, and run `brain init && brain reembed`.
130
+ - **Node.js 18+ and [Caddy](https://caddyserver.com/)** — only for the rendered [wiki](docs/vault-and-wiki.md).
131
+ - **`gws` CLI** — only for Gmail ingest and Google-backed directory linking.
132
+
133
+ Prefer to drive every step yourself, or hacking on the code? See [Installing from source](docs/configuration.md#installing-from-source-manual).
134
+
135
+ ## Core usage
136
+
137
+ ```bash
138
+ brain ingest ~/Documents/resume.pdf --tag career # ingest a file (TXT / MD / PDF / DOCX)
139
+ brain ingest-dir ~/Documents/career # recursive, idempotent by content hash
140
+ brain search "what did I tell my manager about the migration" # hybrid FTS + vector search
141
+ brain show <id-prefix> # full document body (6+ hex prefix)
142
+ brain list --source gmail --limit 20 # browse by source
143
+ brain tag <id-prefix> +interview +career -old-tag # add (+name) / remove (-name) tags
144
+ ```
145
+
146
+ Add `--json` to `search` / `show` / `list` for machine-readable output, and `--fts-only` to `search` to skip the embedding call. The full command surface — Gmail ingest, enrichment, tacit-knowledge elicitation, GraphRAG, the proactivity/synthesis commands, and vault authoring — lives in the [CLI reference](docs/cli-reference.md).
147
+
148
+ ## Claude integrations
149
+
150
+ `brain` and the bundled `brain-mcp` server are harness-agnostic — any agent that runs a shell command or speaks MCP can query the corpus.
151
+
152
+ Register the MCP server once, then just ask — the agent searches the brain and answers from it, no context pasted in:
153
+
154
+ ![Claude answering a question from the brain over the brain-mcp MCP server](docs/assets/mcp.gif)
155
+
156
+ **Claude Code** — register the MCP server (or symlink the [skills](docs/configuration.md#claude-code-consult-brain-skill)):
157
+
158
+ ```bash
159
+ claude mcp add brain -- brain-mcp
160
+ ```
161
+
162
+ **Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json` (replace `/Users/you` with your home directory):
163
+
164
+ ```json
165
+ {
166
+ "mcpServers": {
167
+ "brain": {
168
+ "command": "/Users/you/workspace/second-brain/.venv/bin/brain-mcp",
169
+ "env": {
170
+ "DATABASE_URL": "postgresql://brain:brain@localhost:55432/second_brain",
171
+ "BRAIN_EMBEDDER": "arctic"
172
+ }
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ `uvx secondbrain-py` also launches the MCP server. Full walkthrough (symlink, smoke-test, troubleshooting): [docs/guides/claude-desktop-setup.md](docs/guides/claude-desktop-setup.md).
179
+
180
+ ## How it works
181
+
182
+ **Hybrid search.** Every document is chunked, embedded, and indexed for Postgres full-text search. A query runs both legs — lexical `tsvector` ranking and vector cosine similarity — and fuses them with [Reciprocal Rank Fusion](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf) (k=60), then applies a recency boost and metadata filters. Lexical alone misses paraphrases ("what did I say about X"); vector alone misses exact names (a coworker, a former employer); RRF gets both in one ranked list without tuning weights. Set `BRAIN_EMBEDDER=none` for an FTS-only brain with no embedding dependency at all.
183
+
184
+ **GraphRAG.** Alongside search, brain builds an entity graph of the people and concepts that co-occur across the corpus ([Apache AGE](https://age.apache.org/) inside the same Postgres) and retrieves over that structure — answering "what themes come up in my conversations with X" or "which clusters of people and topics dominate my notes" by traversing relationships instead of matching text. It runs alongside plain search, not instead of it. See [docs/graphrag.md](docs/graphrag.md).
185
+
186
+ ## Documentation
187
+
188
+ - [docs/](docs/README.md) — full documentation index
189
+ - [CLI reference](docs/cli-reference.md) — every command beyond the core five
190
+ - [GraphRAG](docs/graphrag.md) — entity-graph retrieval (themes, patterns, connections)
191
+ - [Vault and Wiki](docs/vault-and-wiki.md) — the two-tier note vault + optional rendered wiki
192
+ - [Configuration](docs/configuration.md) — tech stack, tuning knobs, integrations, embedder backends, uninstall
193
+ - [CONTRIBUTING.md](CONTRIBUTING.md) — dev setup, codebase layout, running the tests
194
+ - [CHANGELOG.md](CHANGELOG.md) — release history
195
+ - [LICENSE](LICENSE) — MIT
@@ -0,0 +1,152 @@
1
+ <!-- mcp-name: io.github.mshtawythug/second-brain -->
2
+
3
+ # Second Brain
4
+
5
+ Local, queryable knowledge base and note vault with hybrid search and an entity-graph layer — searchable by any AI coding agent or assistant from any conversation.
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+ [![CI](https://github.com/mshtawythug/second-brain/actions/workflows/eval.yml/badge.svg)](https://github.com/mshtawythug/second-brain/actions/workflows/eval.yml)
9
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
10
+
11
+ Stores career docs, interview prep, Krisp transcripts, Slack threads, Gmail, and authored Markdown notes in Postgres + pgvector. Any agent reaches all of it through the `brain` CLI or the bundled `brain-mcp` MCP server — no re-pasting context into every chat.
12
+
13
+ The everyday loop — capture a note, search it back, read the top hit, check the corpus:
14
+
15
+ ![brain daily workflow](docs/assets/usage.gif)
16
+
17
+ ## Token savings
18
+
19
+ Querying `brain` returns a ranked snippet instead of dumping whole threads and files into an agent's context, so a lookup costs a fraction of the tokens a direct MCP or file read would:
20
+
21
+ | Source | Direct read (MCP / `Read` tool) | Via `brain` (search + optional `show`) | Savings |
22
+ |---|---|---|---|
23
+ | **Gmail thread** | 15–50k (metadata + full threads with quoted replies / headers) | ~2–4k (snippets + one targeted `brain show`) | **~5–15×** |
24
+ | **Krisp transcript** | 25–75k (search + full transcripts across candidates) | ~6–16k (search + one relevant transcript) | **~4–10×** |
25
+ | **Long PDF / DOCX (30+ pages)** | 15–25k (read the whole file) | ~1–9k (one snippet + targeted `show`) | **~5–15×** |
26
+
27
+ Brain stores pre-extracted, quote-stripped bodies and hybrid-ranks *before* fetching, so only the passage that matched enters context. See the [full per-source breakdown](docs/configuration.md#token-economics).
28
+
29
+ ## See it in 60 seconds
30
+
31
+ Install the CLI, then run the offline demo — a throwaway Postgres seeded with a synthetic *Larkspur* compliance corpus. No Ollama, no personal data, no model downloads:
32
+
33
+ ```bash
34
+ pipx install secondbrain-py
35
+ # or, with uv:
36
+ uv tool install secondbrain-py
37
+ # or, pin the git tag (no PyPI needed):
38
+ pipx install git+https://github.com/mshtawythug/second-brain.git@v0.2.1
39
+
40
+ brain demo # spins up a sandbox Postgres, seeds 22 docs, runs a hero query
41
+ ```
42
+
43
+ ![brain demo](docs/assets/demo.gif)
44
+
45
+ _(IDs and scores are per-run; the seeded corpus and its ranking are deterministic — the top hit is always the "Compliance Horror Stories" note.)_
46
+
47
+ Try these next:
48
+
49
+ ```bash
50
+ brain demo query "SOC 2 evidence request" # a targeted follow-up query
51
+ brain demo query "vendor risk" --source gmail # narrow by source
52
+ brain show <id> # read the top hit in full (in your own brain)
53
+ brain demo teardown # remove the sandbox when done
54
+ ```
55
+
56
+ `brain demo` needs only Docker; `brain demo teardown` destroys the sandbox.
57
+
58
+ Already ran the demo? You have `brain` installed — jump straight to `brain setup --profile …` below.
59
+
60
+ ## Quick start
61
+
62
+ Full install — the `brain` CLI plus the runtime (Postgres, and optionally Ollama / graph / wiki):
63
+
64
+ ```bash
65
+ curl -fsSL https://raw.githubusercontent.com/mshtawythug/second-brain/v0.2.1/install.sh | bash
66
+ ```
67
+
68
+ The installer pipx-installs `brain` from the `v0.2.1` tag, then runs `brain setup` to provision `$BRAIN_HOME`, start the Postgres container, and (optionally) install the wiki + Claude Code skill. Choose how much to stand up with `--profile`:
69
+
70
+ | Profile | Search | Extra dependencies beyond the core |
71
+ |---|---|---|
72
+ | `minimal` | FTS-only (`BRAIN_EMBEDDER=none`) | None — core only (no Ollama, no models). |
73
+ | `standard` *(default)* | Hybrid (FTS + vector) | + Ollama + one ~1 GB embedding model (`snowflake-arctic-embed2`). |
74
+ | `full` | Hybrid + GraphRAG + wiki | + Apache AGE image, concept-extraction LLM, Quartz/Caddy wiki, and (opt-in) launchd daemons via `--daemons`. |
75
+
76
+ ```bash
77
+ brain setup --profile minimal # Docker-only, FTS search — fastest to stand up
78
+ brain setup --profile standard # default: local hybrid search
79
+ brain setup --profile full --daemons
80
+ ```
81
+
82
+ **Prerequisites (core):** Git, Python 3.11+, and a running Docker (Desktop or Engine) — the Postgres + pgvector database runs in a container on port 55432.
83
+
84
+ **Optional extras** (only if you want more than FTS-only search):
85
+
86
+ - **[Ollama](https://ollama.com/)** — local, free embeddings + LLM enrichment. To upgrade a `minimal` (FTS-only) brain to hybrid search: install Ollama, then `ollama pull snowflake-arctic-embed2`, set `BRAIN_EMBEDDER=arctic` in `.env`, and run `brain init && brain reembed`.
87
+ - **Node.js 18+ and [Caddy](https://caddyserver.com/)** — only for the rendered [wiki](docs/vault-and-wiki.md).
88
+ - **`gws` CLI** — only for Gmail ingest and Google-backed directory linking.
89
+
90
+ Prefer to drive every step yourself, or hacking on the code? See [Installing from source](docs/configuration.md#installing-from-source-manual).
91
+
92
+ ## Core usage
93
+
94
+ ```bash
95
+ brain ingest ~/Documents/resume.pdf --tag career # ingest a file (TXT / MD / PDF / DOCX)
96
+ brain ingest-dir ~/Documents/career # recursive, idempotent by content hash
97
+ brain search "what did I tell my manager about the migration" # hybrid FTS + vector search
98
+ brain show <id-prefix> # full document body (6+ hex prefix)
99
+ brain list --source gmail --limit 20 # browse by source
100
+ brain tag <id-prefix> +interview +career -old-tag # add (+name) / remove (-name) tags
101
+ ```
102
+
103
+ Add `--json` to `search` / `show` / `list` for machine-readable output, and `--fts-only` to `search` to skip the embedding call. The full command surface — Gmail ingest, enrichment, tacit-knowledge elicitation, GraphRAG, the proactivity/synthesis commands, and vault authoring — lives in the [CLI reference](docs/cli-reference.md).
104
+
105
+ ## Claude integrations
106
+
107
+ `brain` and the bundled `brain-mcp` server are harness-agnostic — any agent that runs a shell command or speaks MCP can query the corpus.
108
+
109
+ Register the MCP server once, then just ask — the agent searches the brain and answers from it, no context pasted in:
110
+
111
+ ![Claude answering a question from the brain over the brain-mcp MCP server](docs/assets/mcp.gif)
112
+
113
+ **Claude Code** — register the MCP server (or symlink the [skills](docs/configuration.md#claude-code-consult-brain-skill)):
114
+
115
+ ```bash
116
+ claude mcp add brain -- brain-mcp
117
+ ```
118
+
119
+ **Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json` (replace `/Users/you` with your home directory):
120
+
121
+ ```json
122
+ {
123
+ "mcpServers": {
124
+ "brain": {
125
+ "command": "/Users/you/workspace/second-brain/.venv/bin/brain-mcp",
126
+ "env": {
127
+ "DATABASE_URL": "postgresql://brain:brain@localhost:55432/second_brain",
128
+ "BRAIN_EMBEDDER": "arctic"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ `uvx secondbrain-py` also launches the MCP server. Full walkthrough (symlink, smoke-test, troubleshooting): [docs/guides/claude-desktop-setup.md](docs/guides/claude-desktop-setup.md).
136
+
137
+ ## How it works
138
+
139
+ **Hybrid search.** Every document is chunked, embedded, and indexed for Postgres full-text search. A query runs both legs — lexical `tsvector` ranking and vector cosine similarity — and fuses them with [Reciprocal Rank Fusion](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf) (k=60), then applies a recency boost and metadata filters. Lexical alone misses paraphrases ("what did I say about X"); vector alone misses exact names (a coworker, a former employer); RRF gets both in one ranked list without tuning weights. Set `BRAIN_EMBEDDER=none` for an FTS-only brain with no embedding dependency at all.
140
+
141
+ **GraphRAG.** Alongside search, brain builds an entity graph of the people and concepts that co-occur across the corpus ([Apache AGE](https://age.apache.org/) inside the same Postgres) and retrieves over that structure — answering "what themes come up in my conversations with X" or "which clusters of people and topics dominate my notes" by traversing relationships instead of matching text. It runs alongside plain search, not instead of it. See [docs/graphrag.md](docs/graphrag.md).
142
+
143
+ ## Documentation
144
+
145
+ - [docs/](docs/README.md) — full documentation index
146
+ - [CLI reference](docs/cli-reference.md) — every command beyond the core five
147
+ - [GraphRAG](docs/graphrag.md) — entity-graph retrieval (themes, patterns, connections)
148
+ - [Vault and Wiki](docs/vault-and-wiki.md) — the two-tier note vault + optional rendered wiki
149
+ - [Configuration](docs/configuration.md) — tech stack, tuning knobs, integrations, embedder backends, uninstall
150
+ - [CONTRIBUTING.md](CONTRIBUTING.md) — dev setup, codebase layout, running the tests
151
+ - [CHANGELOG.md](CHANGELOG.md) — release history
152
+ - [LICENSE](LICENSE) — MIT
@@ -0,0 +1,219 @@
1
+ [project]
2
+ name = "secondbrain-py"
3
+ version = "0.2.1"
4
+ description = "Local personal knowledge base with hybrid search, queryable by Claude"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.11"
9
+ keywords = [
10
+ "second-brain",
11
+ "knowledge-base",
12
+ "rag",
13
+ "pgvector",
14
+ "hybrid-search",
15
+ "mcp",
16
+ "ollama",
17
+ "local-first",
18
+ ]
19
+ # NOTE: no `License ::` trove classifier here — the license is declared via the
20
+ # PEP 639 SPDX expression (`license = "MIT"` + `license-files`) above. setuptools
21
+ # >= 77 rejects a `License ::` classifier alongside an SPDX license expression
22
+ # ("License classifiers have been superseded by license expressions"), so the
23
+ # classifier would break the build. PyPI derives the license from the expression.
24
+ classifiers = [
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Environment :: Console",
28
+ "Topic :: Text Processing :: Indexing",
29
+ ]
30
+ dependencies = [
31
+ "psycopg[binary]>=3.2",
32
+ "pgvector>=0.3",
33
+ "httpx>=0.27",
34
+ "pypdf>=5.0",
35
+ "pdfplumber>=0.11",
36
+ "python-docx>=1.1",
37
+ "markdown-it-py>=3.0",
38
+ "typer>=0.13",
39
+ "rich>=13.9",
40
+ "python-dotenv>=1.0",
41
+ "tiktoken>=0.8",
42
+ "mcp>=1.0,<2.0",
43
+ "voyageai>=0.3",
44
+ "pyyaml>=6.0",
45
+ "watchdog>=4.0",
46
+ "networkx>=3.2",
47
+ ]
48
+
49
+ [project.optional-dependencies]
50
+ dev = ["pytest>=8.3", "pytest-cov>=5.0", "coverage<7.13", "pytest-mock>=3.14", "ruff>=0.7", "mypy>=1.13", "reportlab>=4.0", "types-PyYAML>=6.0"]
51
+
52
+ [project.scripts]
53
+ brain = "brain.cli:app"
54
+ brain-mcp = "brain.mcp_server:main"
55
+ # Alias so `uvx secondbrain-py` launches the MCP server (uvx matches the console
56
+ # script to the normalized distribution name; matches server.json's uvx
57
+ # runtimeHint for the MCP registry; the human CLI remains `brain`).
58
+ secondbrain-py = "brain.mcp_server:main"
59
+ brain-up = "brain.bin.up:main"
60
+ brain-down = "brain.bin.down:main"
61
+ brain-status = "brain.bin.status:main"
62
+ brain-rebuild = "brain.bin.rebuild:main"
63
+ brain-install-launchd = "brain.bin.launchd:install_main"
64
+ brain-uninstall-launchd = "brain.bin.launchd:uninstall_main"
65
+ brain-monitor = "brain.bin.monitor:cli_main"
66
+
67
+ [project.urls]
68
+ Homepage = "https://github.com/mshtawythug/second-brain"
69
+ Repository = "https://github.com/mshtawythug/second-brain"
70
+ Issues = "https://github.com/mshtawythug/second-brain/issues"
71
+
72
+ [build-system]
73
+ requires = ["setuptools>=68"]
74
+ build-backend = "setuptools.build_meta"
75
+
76
+ [tool.setuptools.packages.find]
77
+ where = ["src"]
78
+
79
+ [tool.setuptools.package-data]
80
+ # Include only the specific asset extensions used by the Quartz overlay tree.
81
+ # Explicit patterns rather than "**/*" so .pyc bytecode and __pycache__ dirs
82
+ # are never shipped into the wheel.
83
+ # Root-level files: quartz.config.ts, quartz.layout.ts (*.ts covers them)
84
+ # Nested files under quartz/: TS/TSX components, JS/MJS CLI scripts, SCSS
85
+ # stylesheets, and PNG/ICO branding assets.
86
+ "brain.quartz_overrides" = [
87
+ "*.ts",
88
+ "**/*.ts",
89
+ "**/*.tsx",
90
+ "**/*.js",
91
+ "**/*.mjs",
92
+ "**/*.scss",
93
+ "**/*.png",
94
+ "**/*.ico",
95
+ ]
96
+ # Templates shipped with the brain package for use by the installer.
97
+ # Explicit extension patterns (not "**/*") to avoid shipping bytecode.
98
+ # brain.templates root: docker-compose.yml.j2, Caddyfile.j2, env.example
99
+ # brain.templates.docker.age: pinned Dockerfile (PG16 + pgvector + AGE), a plain
100
+ # data subdir (no __init__.py) materialized into $BRAIN_HOME by `brain setup`
101
+ # brain.templates.bin: shell launcher/helper scripts
102
+ # brain.templates.launchd: launchd plist Jinja2 templates
103
+ # brain.templates.skill: SKILL.md prose for Claude Code skill setup
104
+ "brain.templates" = ["*.j2", "env.example", "docker/age/Dockerfile"]
105
+ "brain.templates.bin" = ["*.sh"]
106
+ "brain.templates.launchd" = ["*.j2"]
107
+ "brain.templates.skill" = ["*.md"]
108
+ # brain.demo: the synthetic `brain demo` corpus manifest (a plain data subdir
109
+ # under corpus/, no __init__.py) shipped so the zero-Ollama taste test works on
110
+ # pipx/wheel installs. Explicit "corpus/*.json" (not "**/*") avoids bytecode.
111
+ "brain.demo" = ["corpus/*.json"]
112
+ # brain/migrations: the numbered SQL schema migrations `brain init` applies in
113
+ # name order (discovered by db.migrations_dir()). They live INSIDE the package —
114
+ # migrations/ under src/brain/, NOT the repo root — so wheel / pip installs
115
+ # bundle them; without this `brain init` globs an empty dir and never creates the
116
+ # schema. Explicit "migrations/*.sql" (not "**/*") ships only the SQL.
117
+ "brain" = ["migrations/*.sql"]
118
+
119
+ [tool.setuptools.exclude-package-data]
120
+ # Strip bytecode caches that Python creates on-disk when the package is imported
121
+ # during a dev install — they are local artefacts and must not appear in wheels.
122
+ "brain.quartz_overrides" = ["__pycache__/*", "*.pyc"]
123
+ "brain.templates" = ["__pycache__/*", "*.pyc"]
124
+ "brain.templates.bin" = ["__pycache__/*", "*.pyc"]
125
+ "brain.templates.launchd" = ["__pycache__/*", "*.pyc"]
126
+ "brain.templates.skill" = ["__pycache__/*", "*.pyc"]
127
+ "brain.demo" = ["__pycache__/*", "*.pyc"]
128
+
129
+ [tool.pytest.ini_options]
130
+ testpaths = ["tests"]
131
+ addopts = "-ra --strict-markers --cov=brain --cov-report=term-missing --cov-fail-under=85 -m 'not eval and not benchmark and not e2e and not phase3'"
132
+ markers = [
133
+ # P3.5 — frontend integration harness. Tests under this marker shell
134
+ # out to `npx quartz build` and serve the artifact over HTTP (or rsync the
135
+ # live vault for the FastPath T0 perf benchmarks), so they require a Node
136
+ # toolchain + the live brain Quartz workspace at `~/brain-vault/.quartz/`.
137
+ # EXCLUDED from the default suite (see the ``addopts`` -m filter, alongside
138
+ # ``eval`` / ``benchmark``): they are non-hermetic (need a live vault, and
139
+ # the FastPath benchmarks rsync it — racing the live build daemon) and far
140
+ # too slow for every local run. Opt IN with `-m e2e`; CI runs them in a
141
+ # dedicated workflow.
142
+ "e2e: end-to-end Quartz build + serve test (requires npx + live workspace)",
143
+ # Phase D — search-ranking-fix. Tests under this marker connect to the
144
+ # live local Postgres (`second_brain` database) and to a real Ollama
145
+ # instance to embed a known-bad query and measure cosine similarity to
146
+ # a known-bad doc. Used to tune ``DEFAULT_VECTOR_SIM_FLOOR`` and to
147
+ # canary-check the post-fix corpus. Skipped on hosts without those
148
+ # services; opt out via `-m "not live_db"`.
149
+ "live_db: requires live local Postgres + Ollama (Phase D verification)",
150
+ # Wave Q1-B — Eval harness. Tests under this marker run the 20-query
151
+ # golden corpus against the live local Postgres + Ollama, scoring
152
+ # nDCG@5 / MRR / Recall@20. Excluded from the default suite; opt-IN
153
+ # via `-m eval`. Skips cleanly when Postgres or Ollama is unreachable.
154
+ "eval: live golden-corpus run; gated, requires explicit -m eval invocation",
155
+ # Wave G1-d / G2 — GraphRAG benchmark perf gate. Tests under this marker
156
+ # load the full-scale synthetic graph (50k entities / 500k CO_OCCURS / 1M
157
+ # mentions / 10 tenants — tests/graphrag/benchmark_fixture.py) and measure
158
+ # P95 traversal/themes latency. EXCLUDED from the default suite (see
159
+ # ``addopts`` -m filter) because the load is far too slow for every run;
160
+ # G2's perf gate opts IN via ``pytest -m benchmark``. The default suite
161
+ # exercises the SAME generator via the tiny ≈50-entity smoke instead.
162
+ "benchmark: GraphRAG full-scale perf gate; requires explicit -m benchmark invocation",
163
+ # brain-rebuild advisory-lock + real-DB tests. These need the test Postgres
164
+ # container (port 5434) to be up but do NOT require Ollama. Included in the
165
+ # default suite (not excluded by the addopts -m filter) because the test DB
166
+ # is required for most other tests anyway; marked for easy targeted runs via
167
+ # ``pytest -m integration``.
168
+ "integration: requires the test Postgres container (port 5434, db second_brain_test)",
169
+ # Plan 05 — `brain timeline` migration-021 roundtrip. The only test that
170
+ # requires the optional generated ``documents.doc_date`` column (Phase 3).
171
+ # EXCLUDED from the default suite (see the ``addopts`` -m filter, alongside
172
+ # ``eval`` / ``benchmark``) so v1/v2 CI passes without migration 021 applied;
173
+ # opt IN with `-m phase3`.
174
+ "phase3: requires the optional migration-021 doc_date column (brain timeline Phase 3)",
175
+ # Wave 6.1 — test-DB reset strategy opt-out. The per-test ``test_db`` fixture
176
+ # normally does a cheap ``TRUNCATE`` reset on top of a schema migrated ONCE per
177
+ # session (conftest ``_truncate_reset``). Tests that mutate the *schema* itself
178
+ # (DROP/ALTER/CREATE on tables, indexes, extensions; ``ensure_embedding_column``
179
+ # resizes; ``finalize_embedding_index`` NOT NULL/index; re-running migrations;
180
+ # own-connection ``DROP SCHEMA``) must carry this marker: the fixture then falls
181
+ # back to the full ``DROP SCHEMA`` + migrate reset for that test AND an autouse
182
+ # teardown re-establishes the migrated-once baseline afterwards, so the next
183
+ # (TRUNCATE-only) test is not poisoned by the leaked schema mutation. INCLUDED
184
+ # in the default suite — it is a routing hint, not an exclusion filter.
185
+ "fresh_schema: needs a full drop+migrate reset (mutates schema, not just data)",
186
+ ]
187
+
188
+ [tool.ruff]
189
+ line-length = 100
190
+ target-version = "py311"
191
+
192
+ [tool.ruff.lint]
193
+ select = ["E", "F", "I", "UP", "B", "SIM"]
194
+
195
+ [tool.ruff.lint.flake8-bugbear]
196
+ # Typer uses typer.Argument/Option/Typer as defaults — the standard idiom.
197
+ extend-immutable-calls = ["typer.Argument", "typer.Option", "typer.Typer"]
198
+
199
+ [tool.mypy]
200
+ python_version = "3.11"
201
+ mypy_path = "src"
202
+ explicit_package_bases = true
203
+ strict = true
204
+
205
+ [[tool.mypy.overrides]]
206
+ module = ["pgvector.*", "pdfplumber.*", "pypdf.*", "markdown_it.*", "docx.*", "tiktoken.*", "reportlab.*", "voyageai.*", "watchdog.*", "networkx.*"]
207
+ ignore_missing_imports = true
208
+
209
+ # numpy (transitive via networkx) ships PEP 695 `type X = ...` aliases in its
210
+ # bundled stubs, which are 3.12+ syntax. With our `python_version = "3.11"`
211
+ # target, mypy rejects that syntax in `numpy/__init__.pyi` and halts before it
212
+ # ever reaches brain code ("errors prevented further checking"). We never import
213
+ # numpy directly, so skip following into it entirely — keeps the 3.11 target for
214
+ # our own code while unblocking the gate. `follow_imports_for_stubs` makes the
215
+ # skip apply to the `.pyi` too (not just runtime modules).
216
+ [[tool.mypy.overrides]]
217
+ module = ["numpy", "numpy.*"]
218
+ follow_imports = "skip"
219
+ follow_imports_for_stubs = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,18 @@
1
+ """Enable ``python -m brain [command]`` invocation of the brain CLI.
2
+
3
+ This module is the standard entry-point for Python's ``-m`` flag:
4
+
5
+ python -m brain init
6
+ python -m brain doctor
7
+ python -m brain search "..."
8
+
9
+ It delegates directly to the Typer app in :mod:`brain.cli`, which
10
+ processes ``sys.argv`` and dispatches to the appropriate subcommand.
11
+ ``brain setup`` uses this path (via ``sys.executable``) to invoke ``brain
12
+ init`` and ``brain doctor`` inside the same virtualenv that is running the
13
+ installer, without relying on the ``brain`` console-script being on ``PATH``.
14
+ """
15
+
16
+ from brain.cli import app
17
+
18
+ app()