secondbrain-py 0.2.1__py3-none-any.whl

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 (273) hide show
  1. brain/__init__.py +0 -0
  2. brain/__main__.py +18 -0
  3. brain/_capture_command.py +445 -0
  4. brain/_compose.py +52 -0
  5. brain/activity.py +206 -0
  6. brain/ask.py +631 -0
  7. brain/audio.py +591 -0
  8. brain/backfill/__init__.py +12 -0
  9. brain/backfill/search_extras.py +141 -0
  10. brain/backfill/source_rows.py +101 -0
  11. brain/bin/__init__.py +1 -0
  12. brain/bin/_launcher.py +107 -0
  13. brain/bin/down.py +8 -0
  14. brain/bin/launchd.py +268 -0
  15. brain/bin/monitor.py +570 -0
  16. brain/bin/rebuild.py +8 -0
  17. brain/bin/status.py +8 -0
  18. brain/bin/up.py +8 -0
  19. brain/brief.py +272 -0
  20. brain/capture.py +49 -0
  21. brain/chat.py +293 -0
  22. brain/cli.py +9760 -0
  23. brain/cli_claude.py +81 -0
  24. brain/cli_connect.py +285 -0
  25. brain/cli_demo.py +266 -0
  26. brain/config.py +1949 -0
  27. brain/connect.py +925 -0
  28. brain/db.py +540 -0
  29. brain/demo/__init__.py +452 -0
  30. brain/demo/corpus/manifest.json +403 -0
  31. brain/demo/embedder.py +74 -0
  32. brain/durations.py +84 -0
  33. brain/edit_session.py +156 -0
  34. brain/editor.py +67 -0
  35. brain/elicit/__init__.py +16 -0
  36. brain/elicit/detectors.py +250 -0
  37. brain/elicit/drafter.py +70 -0
  38. brain/elicit/queue.py +220 -0
  39. brain/elicit/schema.py +48 -0
  40. brain/elicit/session.py +445 -0
  41. brain/embedding_targets.py +54 -0
  42. brain/embeddings.py +424 -0
  43. brain/enrichment.py +808 -0
  44. brain/errors.py +357 -0
  45. brain/eval/__init__.py +129 -0
  46. brain/eval/answer_eval.py +281 -0
  47. brain/eval/baseline.py +265 -0
  48. brain/eval/concept_extraction.py +378 -0
  49. brain/eval/corpus.py +152 -0
  50. brain/eval/errors.py +19 -0
  51. brain/eval/graph_baseline.py +226 -0
  52. brain/eval/graph_retrieval.py +202 -0
  53. brain/eval/graph_runner.py +319 -0
  54. brain/eval/metrics.py +101 -0
  55. brain/eval/runner.py +223 -0
  56. brain/format.py +783 -0
  57. brain/gaps.py +390 -0
  58. brain/graph_rag/__init__.py +94 -0
  59. brain/graph_rag/_retrieval_common.py +113 -0
  60. brain/graph_rag/aggregates.py +303 -0
  61. brain/graph_rag/aliases/__init__.py +583 -0
  62. brain/graph_rag/backends/__init__.py +10 -0
  63. brain/graph_rag/backends/_age_helpers.py +473 -0
  64. brain/graph_rag/backends/age.py +782 -0
  65. brain/graph_rag/backends/base.py +272 -0
  66. brain/graph_rag/build.py +344 -0
  67. brain/graph_rag/communities.py +644 -0
  68. brain/graph_rag/communities_summary.py +437 -0
  69. brain/graph_rag/concepts.py +202 -0
  70. brain/graph_rag/cooccur.py +193 -0
  71. brain/graph_rag/cross_type.py +312 -0
  72. brain/graph_rag/extract.py +885 -0
  73. brain/graph_rag/fuse.py +371 -0
  74. brain/graph_rag/global_.py +412 -0
  75. brain/graph_rag/grouping.py +372 -0
  76. brain/graph_rag/person_resolver.py +167 -0
  77. brain/graph_rag/reconcile.py +792 -0
  78. brain/graph_rag/relational.py +353 -0
  79. brain/graph_rag/retrieve.py +526 -0
  80. brain/graph_rag/router.py +288 -0
  81. brain/graph_rag/schema.py +320 -0
  82. brain/graph_rag/sync.py +237 -0
  83. brain/graph_rag/tenancy.py +43 -0
  84. brain/graph_rag/themes.py +501 -0
  85. brain/graph_rag/weighting.py +202 -0
  86. brain/ingest/__init__.py +1926 -0
  87. brain/ingest/chunker.py +249 -0
  88. brain/ingest/docx.py +40 -0
  89. brain/ingest/gmail.py +621 -0
  90. brain/ingest/markdown.py +37 -0
  91. brain/ingest/pdf.py +61 -0
  92. brain/ingest/stdin.py +22 -0
  93. brain/ingest/sub_tokens.py +91 -0
  94. brain/ingest/text.py +16 -0
  95. brain/interactions.py +205 -0
  96. brain/maintenance.py +355 -0
  97. brain/mcp_server.py +3405 -0
  98. brain/migrations/001_init.sql +43 -0
  99. brain/migrations/002_qwen3_embedding.sql +17 -0
  100. brain/migrations/003_vault_model.sql +41 -0
  101. brain/migrations/004_relax_content_hash_uniqueness.sql +18 -0
  102. brain/migrations/005_derived_links.sql +67 -0
  103. brain/migrations/006_dedup_file_by_source_path.sql +25 -0
  104. brain/migrations/007_email_thread_and_draft.sql +15 -0
  105. brain/migrations/008_gmail_thread_unique.sql +11 -0
  106. brain/migrations/009_chunks_weighted_tsv.sql +28 -0
  107. brain/migrations/010_interactions.sql +30 -0
  108. brain/migrations/011_documents_summary.sql +23 -0
  109. brain/migrations/012_graphrag.sql +171 -0
  110. brain/migrations/013_graphrag_communities.sql +125 -0
  111. brain/migrations/014_graphrag_community_summary_hash.sql +33 -0
  112. brain/migrations/015_interactions_graph_targets.sql +89 -0
  113. brain/migrations/016_index_hygiene.sql +61 -0
  114. brain/migrations/017_elicit.sql +30 -0
  115. brain/migrations/018_review_gap_signal_kinds.sql +40 -0
  116. brain/migrations/019_search_queries.sql +35 -0
  117. brain/migrations/020_link_suggestions.sql +40 -0
  118. brain/migrations/021_timeline_doc_date.sql +34 -0
  119. brain/migrations/022_link_suggestions_undirected.sql +84 -0
  120. brain/migrations/023_search_queries_fts_count.sql +28 -0
  121. brain/quartz_overrides/__init__.py +8 -0
  122. brain/quartz_overrides/quartz/bootstrap-cli.mjs +65 -0
  123. brain/quartz_overrides/quartz/build.ts +568 -0
  124. brain/quartz_overrides/quartz/cli/args.js +152 -0
  125. brain/quartz_overrides/quartz/cli/build_partial_handler.js +544 -0
  126. brain/quartz_overrides/quartz/cli/handlers.js +636 -0
  127. brain/quartz_overrides/quartz/components/CommandPalette.tsx +172 -0
  128. brain/quartz_overrides/quartz/components/Explorer.tsx +198 -0
  129. brain/quartz_overrides/quartz/components/Footer.tsx +27 -0
  130. brain/quartz_overrides/quartz/components/Graph.tsx +468 -0
  131. brain/quartz_overrides/quartz/components/PageTitle.tsx +72 -0
  132. brain/quartz_overrides/quartz/components/RelatedDocs.tsx +38 -0
  133. brain/quartz_overrides/quartz/components/Search.tsx +161 -0
  134. brain/quartz_overrides/quartz/components/SummaryLede.tsx +72 -0
  135. brain/quartz_overrides/quartz/components/index.ts +92 -0
  136. brain/quartz_overrides/quartz/components/pages/TagContent.tsx +272 -0
  137. brain/quartz_overrides/quartz/components/scripts/commandPalette.inline.ts +665 -0
  138. brain/quartz_overrides/quartz/components/scripts/explorer.inline.ts +768 -0
  139. brain/quartz_overrides/quartz/components/scripts/graph.inline.ts +2302 -0
  140. brain/quartz_overrides/quartz/components/scripts/relatedDocs.inline.ts +163 -0
  141. brain/quartz_overrides/quartz/components/scripts/search.inline.ts +1011 -0
  142. brain/quartz_overrides/quartz/plugins/emitters/contentIndex.ts +546 -0
  143. brain/quartz_overrides/quartz/plugins/transformers/codeCopy.ts +94 -0
  144. brain/quartz_overrides/quartz/plugins/transformers/derivedFenceMark.ts +302 -0
  145. brain/quartz_overrides/quartz/plugins/transformers/emailThread.ts +148 -0
  146. brain/quartz_overrides/quartz/plugins/transformers/emptyDoorFilter.ts +213 -0
  147. brain/quartz_overrides/quartz/plugins/transformers/index.ts +114 -0
  148. brain/quartz_overrides/quartz/plugins/transformers/linkKindMark.ts +205 -0
  149. brain/quartz_overrides/quartz/plugins/transformers/linkSourceTag.ts +104 -0
  150. brain/quartz_overrides/quartz/plugins/transformers/relativeDate.ts +100 -0
  151. brain/quartz_overrides/quartz/plugins/transformers/reloadSignal.ts +131 -0
  152. brain/quartz_overrides/quartz/processors/parse.ts +371 -0
  153. brain/quartz_overrides/quartz/processors/parser_cache.ts +78 -0
  154. brain/quartz_overrides/quartz/static/brain-logo-dark.png +0 -0
  155. brain/quartz_overrides/quartz/static/brain-logo-light.png +0 -0
  156. brain/quartz_overrides/quartz/static/codeCopy.js +196 -0
  157. brain/quartz_overrides/quartz/static/emailThread.js +334 -0
  158. brain/quartz_overrides/quartz/static/favicon.ico +0 -0
  159. brain/quartz_overrides/quartz/static/icon.png +0 -0
  160. brain/quartz_overrides/quartz/static/linkSourceTag.js +104 -0
  161. brain/quartz_overrides/quartz/static/relativeDate.js +142 -0
  162. brain/quartz_overrides/quartz/static/reload.js +168 -0
  163. brain/quartz_overrides/quartz/styles/brain/_article.scss +252 -0
  164. brain/quartz_overrides/quartz/styles/brain/_atmosphere.scss +113 -0
  165. brain/quartz_overrides/quartz/styles/brain/_callouts.scss +180 -0
  166. brain/quartz_overrides/quartz/styles/brain/_cmdk.scss +7 -0
  167. brain/quartz_overrides/quartz/styles/brain/_code.scss +208 -0
  168. brain/quartz_overrides/quartz/styles/brain/_command_palette.scss +369 -0
  169. brain/quartz_overrides/quartz/styles/brain/_email_thread.scss +228 -0
  170. brain/quartz_overrides/quartz/styles/brain/_explorer.scss +142 -0
  171. brain/quartz_overrides/quartz/styles/brain/_home.scss +182 -0
  172. brain/quartz_overrides/quartz/styles/brain/_links.scss +322 -0
  173. brain/quartz_overrides/quartz/styles/brain/_marginalia.scss +117 -0
  174. brain/quartz_overrides/quartz/styles/brain/_motion.scss +175 -0
  175. brain/quartz_overrides/quartz/styles/brain/_people_hub.scss +100 -0
  176. brain/quartz_overrides/quartz/styles/brain/_related_docs.scss +137 -0
  177. brain/quartz_overrides/quartz/styles/brain/_search.scss +252 -0
  178. brain/quartz_overrides/quartz/styles/brain/_sidebar.scss +468 -0
  179. brain/quartz_overrides/quartz/styles/brain/_summary_lede.scss +56 -0
  180. brain/quartz_overrides/quartz/styles/brain/_surface.scss +43 -0
  181. brain/quartz_overrides/quartz/styles/brain/_tag_content.scss +118 -0
  182. brain/quartz_overrides/quartz/styles/brain/_tokens.scss +197 -0
  183. brain/quartz_overrides/quartz/styles/brain/_typography.scss +92 -0
  184. brain/quartz_overrides/quartz/styles/custom.scss +89 -0
  185. brain/quartz_overrides/quartz/styles/graph.scss +505 -0
  186. brain/quartz_overrides/quartz/util/ctx.ts +92 -0
  187. brain/quartz_overrides/quartz/util/fastpath_manifest.ts +608 -0
  188. brain/quartz_overrides/quartz/util/path.ts +358 -0
  189. brain/quartz_overrides/quartz/util/sourceIcons.ts +55 -0
  190. brain/quartz_overrides/quartz.config.ts +270 -0
  191. brain/quartz_overrides/quartz.layout.ts +314 -0
  192. brain/queries.py +1188 -0
  193. brain/rank_fusion.py +8 -0
  194. brain/resurface.py +210 -0
  195. brain/review/__init__.py +26 -0
  196. brain/review/emit.py +27 -0
  197. brain/review/queries.py +436 -0
  198. brain/review/render.py +196 -0
  199. brain/review/scans.py +355 -0
  200. brain/review/weekly.py +413 -0
  201. brain/search.py +704 -0
  202. brain/set_similarity.py +15 -0
  203. brain/setup.py +1205 -0
  204. brain/tags.py +56 -0
  205. brain/templates/Caddyfile.j2 +9 -0
  206. brain/templates/__init__.py +1 -0
  207. brain/templates/bin/__init__.py +1 -0
  208. brain/templates/bin/_brain-brief-fg.sh +25 -0
  209. brain/templates/bin/_brain-build-fg.sh +53 -0
  210. brain/templates/bin/_brain-watcher-fg.sh +65 -0
  211. brain/templates/bin/brain-down.sh +89 -0
  212. brain/templates/bin/brain-status.sh +83 -0
  213. brain/templates/bin/brain-up.sh +221 -0
  214. brain/templates/docker/age/Dockerfile +79 -0
  215. brain/templates/docker-compose.stock.yml.j2 +26 -0
  216. brain/templates/docker-compose.yml.j2 +34 -0
  217. brain/templates/env.example +190 -0
  218. brain/templates/launchd/__init__.py +1 -0
  219. brain/templates/launchd/com.brain.brief.plist.j2 +45 -0
  220. brain/templates/launchd/com.brain.build.plist.j2 +46 -0
  221. brain/templates/launchd/com.brain.watcher.plist.j2 +46 -0
  222. brain/templates/skill/SKILL.md +63 -0
  223. brain/templates/skill/__init__.py +1 -0
  224. brain/timeline.py +834 -0
  225. brain/todo.py +124 -0
  226. brain/uninstall.py +185 -0
  227. brain/vault/__init__.py +115 -0
  228. brain/vault/_atomic.py +25 -0
  229. brain/vault/daily_index.py +228 -0
  230. brain/vault/derived_links/__init__.py +50 -0
  231. brain/vault/derived_links/directory.py +683 -0
  232. brain/vault/derived_links/fence.py +408 -0
  233. brain/vault/derived_links/gws.py +64 -0
  234. brain/vault/derived_links/participants.py +143 -0
  235. brain/vault/derived_links/pass_runner.py +362 -0
  236. brain/vault/derived_links/rules.py +137 -0
  237. brain/vault/export.py +683 -0
  238. brain/vault/frontmatter.py +165 -0
  239. brain/vault/graph.py +620 -0
  240. brain/vault/graph_format.py +388 -0
  241. brain/vault/link_rewrite.py +235 -0
  242. brain/vault/links.py +260 -0
  243. brain/vault/note_builder.py +211 -0
  244. brain/vault/paths.py +55 -0
  245. brain/vault/quartz_overlay.py +236 -0
  246. brain/vault/rename.py +591 -0
  247. brain/vault/resolver.py +304 -0
  248. brain/vault/slug.py +127 -0
  249. brain/vault/sync.py +1513 -0
  250. brain/vault/sync_summaries.py +264 -0
  251. brain/vault/templates.py +145 -0
  252. brain/vault/watch.py +1052 -0
  253. brain/wiki/__init__.py +6 -0
  254. brain/wiki/_github_slugger.py +76 -0
  255. brain/wiki/_person_name.py +314 -0
  256. brain/wiki/build_homepage.py +541 -0
  257. brain/wiki/build_partial.py +273 -0
  258. brain/wiki/build_people.py +934 -0
  259. brain/wiki/build_related.py +758 -0
  260. brain/wiki/build_swap.py +585 -0
  261. brain/wiki/build_watcher.py +975 -0
  262. brain/wiki/edit_classifier.py +215 -0
  263. brain/wiki/errors.py +10 -0
  264. brain/wiki/fastpath_manifest.py +475 -0
  265. brain/wiki/fastpath_state.py +174 -0
  266. brain/wiki/install.py +296 -0
  267. brain/wiki/slug.py +111 -0
  268. secondbrain_py-0.2.1.dist-info/METADATA +195 -0
  269. secondbrain_py-0.2.1.dist-info/RECORD +273 -0
  270. secondbrain_py-0.2.1.dist-info/WHEEL +5 -0
  271. secondbrain_py-0.2.1.dist-info/entry_points.txt +11 -0
  272. secondbrain_py-0.2.1.dist-info/licenses/LICENSE +21 -0
  273. secondbrain_py-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,314 @@
1
+ // Sample Quartz v4 layout for brain vaults.
2
+ //
3
+ // This file is a TEMPLATE. Copy it into your Quartz workspace as
4
+ // `<vault>/.quartz/quartz.layout.ts` after cloning Quartz with
5
+ // `git clone https://github.com/jackyzha0/quartz.git <vault>/.quartz`.
6
+ // It does NOT compile or run from the brain repo itself; the imports
7
+ // below resolve against the dependencies Quartz pulls into the cloned
8
+ // workspace via `npm install`, not against any package brain ships.
9
+ //
10
+ // Tested against Quartz v4.5.x (April 2026). If a future Quartz version
11
+ // renames a component or its option shape, pull the latest layout from
12
+ // https://quartz.jzhao.xyz/ and re-apply the brain-specific tweaks
13
+ // flagged below with `// brain:` comments.
14
+ //
15
+ // The brain customizations layer cleanly on top of stock Quartz: the
16
+ // graph component is moved into the right sidebar as a *local* graph
17
+ // only, while the global graph stays reachable via Quartz's built-in
18
+ // Cmd/Ctrl+G modal (wired up by `shortcutHandler` in graph.inline.ts).
19
+ // Several option keys below are brain-only extensions to Quartz's
20
+ // `D3Config` — those are clearly marked so a future maintainer (or
21
+ // somebody running a stock Quartz build) knows they are not upstream.
22
+
23
+ import { PageLayout, SharedLayout } from "./quartz/cfg"
24
+ import * as Component from "./quartz/components"
25
+ import { FileTrieNode } from "./quartz/util/fileTrie"
26
+
27
+ // brain (People Hub, 2026-05-07): pin the `people/` directory to the
28
+ // top of the Explorer tree so Ali can reach the per-person hub pages
29
+ // from anywhere on the site in one click. Mirrors the upstream sort
30
+ // rule (folders before files, then alpha) but with a deterministic
31
+ // override for the `people` slug-segment that bumps it ahead of every
32
+ // other folder. Not a contractual schema field — Quartz options accept
33
+ // any function as `sortFn`, and the inline script serializes it via
34
+ // `.toString()` for client-side execution. We pass the same function
35
+ // to every Explorer slot in the layout (default content + list
36
+ // pages) so the pin behavior is consistent across page types.
37
+ const PINNED_EXPLORER_FOLDER_SLUG = "people"
38
+
39
+ // NOTE: this comparator is serialized via `.toString()` and re-evaluated
40
+ // in the browser, where module-level identifiers are not in scope. The
41
+ // pinned slug literal must therefore be inlined inside the function
42
+ // body — keep `PINNED_EXPLORER_FOLDER_SLUG` in sync with the literals
43
+ // below (the static test in `tests/test_quartz_people_hub_static.py`
44
+ // pins both halves).
45
+ function explorerSortPinningPeople(a: FileTrieNode, b: FileTrieNode): number {
46
+ // Pin `people/` ahead of every other folder. The slug-segment is the
47
+ // last path-component of the trie node; a pinned folder always wins
48
+ // over any non-pinned sibling regardless of type. When neither is the
49
+ // pinned folder, fall through to upstream's "folders first, alpha"
50
+ // rule so the rest of the tree behaves identically to stock Quartz.
51
+ if (a.isFolder && a.slugSegment === "people") return -1
52
+ if (b.isFolder && b.slugSegment === "people") return 1
53
+ if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) {
54
+ return a.displayName.localeCompare(b.displayName, undefined, {
55
+ numeric: true,
56
+ sensitivity: "base",
57
+ })
58
+ }
59
+ return !a.isFolder && b.isFolder ? 1 : -1
60
+ }
61
+
62
+ // components shared across all pages
63
+ //
64
+ // brain: Lane C redesign — `CommandPalette` lives in `afterBody` so
65
+ // the modal markup ships with every page exactly once (the script
66
+ // listener at `Cmd/Ctrl+P` is then reachable from any route). The
67
+ // component is hidden by default (sets the `hidden` attribute on its
68
+ // root `<div>`) and only revealed when the inline script removes the
69
+ // attribute on a Cmd-P press. See
70
+ // `quartz/components/CommandPalette.tsx` for the markup and
71
+ // `quartz/components/scripts/commandPalette.inline.ts` for the
72
+ // runtime open/close + fuzzy search logic.
73
+ export const sharedPageComponents: SharedLayout = {
74
+ head: Component.Head(),
75
+ header: [],
76
+ afterBody: [Component.CommandPalette()],
77
+ // brain: single GitHub link to the repo. Was previously a placeholder
78
+ // pair of "GitHub: #" + "Source: #" — both pointed nowhere and were
79
+ // redundant against each other.
80
+ footer: Component.Footer({
81
+ links: { GitHub: "https://github.com/mshtawythug/second-brain" },
82
+ }),
83
+ }
84
+
85
+ // components for pages that display a single page (e.g. a single note)
86
+ export const defaultContentPageLayout: PageLayout = {
87
+ beforeBody: [
88
+ Component.ConditionalRender({
89
+ component: Component.Breadcrumbs(),
90
+ condition: (page) => page.fileData.slug !== "index",
91
+ }),
92
+ Component.ArticleTitle(),
93
+ Component.ContentMeta(),
94
+ Component.TagList(),
95
+ // brain (Wave Q2-SUMMARY-WIKI): render the Q1-D auto-summary as a
96
+ // TL;DR block above the article body. Sits below the meta strip
97
+ // (title, tags, dates) and above Breadcrumbs's natural reading
98
+ // position — once the reader has identified the page, the lede
99
+ // gives them the gist before the body. Renders `null` when
100
+ // `fileData.frontmatter.summary` is missing or non-string, so
101
+ // unenriched docs never see an empty aside.
102
+ Component.SummaryLede(),
103
+ ],
104
+ left: [
105
+ Component.PageTitle(),
106
+ Component.MobileOnly(Component.Spacer()),
107
+ Component.Flex({
108
+ components: [
109
+ {
110
+ Component: Component.Search(),
111
+ grow: true,
112
+ },
113
+ { Component: Component.Darkmode() },
114
+ { Component: Component.ReaderMode() },
115
+ ],
116
+ }),
117
+ Component.Explorer({ sortFn: explorerSortPinningPeople }),
118
+ ],
119
+ right: [
120
+ // brain: render the local graph inline in the right sidebar so it is
121
+ // always visible while reading. The global graph is intentionally
122
+ // omitted from this layout — Quartz still wires up the Cmd/Ctrl+G
123
+ // modal via `shortcutHandler` in graph.inline.ts, which opens the
124
+ // global graph on demand.
125
+ Component.Graph({
126
+ localGraph: {
127
+ depth: 1,
128
+ scale: 1.1,
129
+ focusOnHover: true,
130
+ enableRadial: false,
131
+ // brain-extension: SHOW orphans — ingested transcripts (krisp
132
+ // especially) often have no wiki-links and would otherwise vanish
133
+ // from view, undercounting the corpus.
134
+ hideOrphans: false,
135
+ // brain-extension: collapse #tag nodes into chips on the side of
136
+ // the graph instead of rendering them as first-class nodes that
137
+ // pull every tagged doc into a hairball.
138
+ hideTagNodes: true,
139
+ // brain-extension: dashed/translucent styling for derived edges
140
+ // (the `_ingested/` fence Phase D writes), so they read as
141
+ // softer "evidence" links rather than authored wiki-links.
142
+ derivedEdgeStyle: { dash: [4, 3], width: 0.5, alpha: 0.4 },
143
+ // brain-extension: scale node radius by recency of last edit so
144
+ // freshly-touched notes pop visually.
145
+ recencySizing: true,
146
+ // brain-extension: in-graph search box that filters visible
147
+ // nodes by title substring.
148
+ searchEnabled: true,
149
+ // brain-extension: tier/source chips are deliberately empty for
150
+ // the local (sidebar) graph. At depth=1 there are usually only a
151
+ // handful of nodes — slicing 5 nodes by tier or source nearly
152
+ // always empties the view, and the filters eat 60+ vertical
153
+ // pixels of sidebar space that's better spent on the canvas.
154
+ // The full filter chip rail still appears in the global modal
155
+ // graph below, where it actually slices a useful number of
156
+ // nodes.
157
+ filterChips: [],
158
+ // brain-extension: looser label cap for the sidebar panel — at
159
+ // depth=1 there are typically only a handful of nodes, so 30
160
+ // chars fits a full short-thread reply ("Apr 28 — Re: Ali Sarkis
161
+ // × vendor-ev") without crowding. The fullscreen modal (Graph.tsx
162
+ // override) and the global graph (defaulted to 10) both keep
163
+ // the tighter cap since their dense canvases would otherwise
164
+ // wall-of-text.
165
+ labelMaxLength: 30,
166
+ },
167
+ globalGraph: {
168
+ depth: -1,
169
+ scale: 0.9,
170
+ // brain-extension: corpus-scale Obsidian-grade tunings — even
171
+ // bigger spread than the local-fullscreen modal because the
172
+ // node count is ~30× higher (1000+ docs vs ~30 neighbours at
173
+ // depth=1). Without this the central cluster compresses into
174
+ // an unreadable blob.
175
+ repelForce: 4.5,
176
+ linkDistance: 280,
177
+ centerForce: 0.05,
178
+ focusOnHover: true,
179
+ enableRadial: true,
180
+ // brain-extension: hide orphans (degree-0 nodes after the chip
181
+ // + tag passes) by default — at corpus scale the floating
182
+ // unconnected dots add visual noise without conveying
183
+ // structure. Users who want to see them can flip the
184
+ // "Show unconnected" chip in the controls rail; the toggle
185
+ // persists across SPA navigation within the session.
186
+ hideOrphans: true,
187
+ // brain-extension: collapse #tag nodes into chips so a single
188
+ // popular tag does not pull every tagged doc into the center.
189
+ hideTagNodes: true,
190
+ // brain-extension: dashed/translucent styling for derived edges
191
+ // (the `_ingested/` fence Phase D writes), so they read as
192
+ // softer "evidence" links rather than authored wiki-links.
193
+ derivedEdgeStyle: { dash: [4, 3], width: 0.5, alpha: 0.4 },
194
+ // brain-extension: in-graph search box that filters visible
195
+ // nodes by title substring. Note: recencySizing is intentionally
196
+ // omitted here — at depth: -1 the radius variance reads as
197
+ // noise rather than signal.
198
+ searchEnabled: true,
199
+ // brain-extension: filter chips wired to frontmatter facets;
200
+ // tier = vault-tier (a/b/c), source = ingest source (krisp,
201
+ // slack, gmail, manual).
202
+ filterChips: ["tier", "source"],
203
+ // brain-extension: 2× node radius — matches the fullscreen-local
204
+ // modal's sizing so the brain-customized globe view reads with
205
+ // comfortable, glance-sized dots. The dot-grid (stock-mode) view
206
+ // strips this back to 1× via the stockMode override in
207
+ // graph.inline.ts so that affordance keeps stock-Quartz visuals.
208
+ nodeRadiusMultiplier: 2,
209
+ // brain-extension: same steeper degree → radius curve as the
210
+ // local-fullscreen view so corpus-level hubs (COMPANY_REDACTED,
211
+ // COMPANY_REDACTED Hub, COMPANY_REDACTED) visibly dominate vs leaves.
212
+ nodeRadiusGrowthExponent: 0.85,
213
+ // brain-extension: fade wiki edges to 25% — slightly fainter
214
+ // than local-fullscreen because at 1000+ nodes the edge density
215
+ // is much higher and would otherwise dominate the canvas.
216
+ wikiEdgeBaseAlpha: 0.25,
217
+ // brain-extension: bump opacityScale so labels stay visible at
218
+ // the wide-spread fit zoom (which lands at k < 1 and would
219
+ // otherwise clamp every label to alpha 0).
220
+ opacityScale: 6,
221
+ // brain-extension: bump label size from the 0.6 default to 1.0
222
+ // — at 80vw × 80vh the canvas has plenty of room and the sidebar
223
+ // panel's small-text constraint doesn't apply. Matches the
224
+ // local-fullscreen modal's fontSize override in Graph.tsx so the
225
+ // two fullscreen views read with consistent typography.
226
+ fontSize: 1.0,
227
+ // brain-extension: any node with ≥ 12 incident links skips
228
+ // truncation in the global view. Was 25 — too restrictive
229
+ // (COMPANY_REDACTED Hub, Interview Prep, COMPANY_REDACTED only had ~10–20 links
230
+ // each, so they got truncated despite being clearly hubs).
231
+ // Lower threshold lets the structural anchors of the corpus
232
+ // read at full length without flooding the canvas with text.
233
+ hubLabelThreshold: 12,
234
+ // brain-extension: non-hub leaf labels in the global view show
235
+ // up to 20 chars (was 10, default). At depth=-1 the cluster is
236
+ // already broken into named regions by the hub labels above, so
237
+ // a longer leaf cap helps disambiguate adjacent nodes (e.g.
238
+ // "Re: VP of Engineerin…" vs "Re: VP of Engineering — Eve…")
239
+ // without restoring the wall-of-text problem.
240
+ labelMaxLength: 20,
241
+ // brain-extension: lift the radius ceiling further than the
242
+ // local-fullscreen view (25 → 30) because at corpus scale the
243
+ // dynamic range between leaves (1 link) and mega-hubs (200+
244
+ // links) is much wider — letting hubs render to ~60px gives
245
+ // the visual hierarchy room to breathe.
246
+ nodeRadiusCeiling: 30,
247
+ // brain-extension: 2× hub-label fontSize — slightly more
248
+ // dramatic than local-fullscreen's 1.7× because at depth=-1
249
+ // there are many more leaves and the size delta needs to be
250
+ // bigger to read as a distinct tier.
251
+ hubLabelFontMultiplier: 2.0,
252
+ },
253
+ workbenchGraph: {
254
+ depth: -1,
255
+ scale: 0.9,
256
+ repelForce: 4.5,
257
+ linkDistance: 280,
258
+ centerForce: 0.05,
259
+ focusOnHover: true,
260
+ enableRadial: true,
261
+ hideOrphans: false,
262
+ hideTagNodes: true,
263
+ derivedEdgeStyle: { dash: [4, 3], width: 0.5, alpha: 0.4 },
264
+ searchEnabled: true,
265
+ filterChips: ["tier", "source"],
266
+ diagnosticWorkbench: true,
267
+ nodeRadiusMultiplier: 2,
268
+ nodeRadiusGrowthExponent: 0.85,
269
+ wikiEdgeBaseAlpha: 0.25,
270
+ opacityScale: 6,
271
+ fontSize: 1.0,
272
+ hubLabelThreshold: 8,
273
+ labelMaxLength: 24,
274
+ nodeRadiusCeiling: 30,
275
+ hubLabelFontMultiplier: 1.8,
276
+ },
277
+ }),
278
+ // brain: ToC sits directly under the graph (page-utility outranks
279
+ // exploration). Stock Quartz styles the ToC as a flex column with
280
+ // `flex: 0 0.5 auto` and a self-scrolling `<ul>` — when RelatedDocs
281
+ // ran above it the related list (often 12+ rows on hub pages) ate
282
+ // the available column height and squeezed the ToC's inner list to
283
+ // ~0px, making the entries unreachable. Putting the ToC first lets
284
+ // it claim its natural height before the related list grows.
285
+ Component.DesktopOnly(Component.TableOfContents()),
286
+ Component.RelatedDocs(),
287
+ Component.Backlinks(),
288
+ ],
289
+ }
290
+
291
+ // brain: the list-page layout is what Quartz's tag-page and folder-page
292
+ // emitters import (`quartz/plugins/emitters/{tagPage,folderPage}.tsx`).
293
+ // Without this export the build fails before producing a single page.
294
+ // Mirrors upstream's structure: same left sidebar (search/explorer/
295
+ // darkmode), no right sidebar (the local graph is meaningless on
296
+ // aggregate index pages).
297
+ export const defaultListPageLayout: PageLayout = {
298
+ beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()],
299
+ left: [
300
+ Component.PageTitle(),
301
+ Component.MobileOnly(Component.Spacer()),
302
+ Component.Flex({
303
+ components: [
304
+ {
305
+ Component: Component.Search(),
306
+ grow: true,
307
+ },
308
+ { Component: Component.Darkmode() },
309
+ ],
310
+ }),
311
+ Component.Explorer({ sortFn: explorerSortPinningPeople }),
312
+ ],
313
+ right: [],
314
+ }