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.
- brain/__init__.py +0 -0
- brain/__main__.py +18 -0
- brain/_capture_command.py +445 -0
- brain/_compose.py +52 -0
- brain/activity.py +206 -0
- brain/ask.py +631 -0
- brain/audio.py +591 -0
- brain/backfill/__init__.py +12 -0
- brain/backfill/search_extras.py +141 -0
- brain/backfill/source_rows.py +101 -0
- brain/bin/__init__.py +1 -0
- brain/bin/_launcher.py +107 -0
- brain/bin/down.py +8 -0
- brain/bin/launchd.py +268 -0
- brain/bin/monitor.py +570 -0
- brain/bin/rebuild.py +8 -0
- brain/bin/status.py +8 -0
- brain/bin/up.py +8 -0
- brain/brief.py +272 -0
- brain/capture.py +49 -0
- brain/chat.py +293 -0
- brain/cli.py +9760 -0
- brain/cli_claude.py +81 -0
- brain/cli_connect.py +285 -0
- brain/cli_demo.py +266 -0
- brain/config.py +1949 -0
- brain/connect.py +925 -0
- brain/db.py +540 -0
- brain/demo/__init__.py +452 -0
- brain/demo/corpus/manifest.json +403 -0
- brain/demo/embedder.py +74 -0
- brain/durations.py +84 -0
- brain/edit_session.py +156 -0
- brain/editor.py +67 -0
- brain/elicit/__init__.py +16 -0
- brain/elicit/detectors.py +250 -0
- brain/elicit/drafter.py +70 -0
- brain/elicit/queue.py +220 -0
- brain/elicit/schema.py +48 -0
- brain/elicit/session.py +445 -0
- brain/embedding_targets.py +54 -0
- brain/embeddings.py +424 -0
- brain/enrichment.py +808 -0
- brain/errors.py +357 -0
- brain/eval/__init__.py +129 -0
- brain/eval/answer_eval.py +281 -0
- brain/eval/baseline.py +265 -0
- brain/eval/concept_extraction.py +378 -0
- brain/eval/corpus.py +152 -0
- brain/eval/errors.py +19 -0
- brain/eval/graph_baseline.py +226 -0
- brain/eval/graph_retrieval.py +202 -0
- brain/eval/graph_runner.py +319 -0
- brain/eval/metrics.py +101 -0
- brain/eval/runner.py +223 -0
- brain/format.py +783 -0
- brain/gaps.py +390 -0
- brain/graph_rag/__init__.py +94 -0
- brain/graph_rag/_retrieval_common.py +113 -0
- brain/graph_rag/aggregates.py +303 -0
- brain/graph_rag/aliases/__init__.py +583 -0
- brain/graph_rag/backends/__init__.py +10 -0
- brain/graph_rag/backends/_age_helpers.py +473 -0
- brain/graph_rag/backends/age.py +782 -0
- brain/graph_rag/backends/base.py +272 -0
- brain/graph_rag/build.py +344 -0
- brain/graph_rag/communities.py +644 -0
- brain/graph_rag/communities_summary.py +437 -0
- brain/graph_rag/concepts.py +202 -0
- brain/graph_rag/cooccur.py +193 -0
- brain/graph_rag/cross_type.py +312 -0
- brain/graph_rag/extract.py +885 -0
- brain/graph_rag/fuse.py +371 -0
- brain/graph_rag/global_.py +412 -0
- brain/graph_rag/grouping.py +372 -0
- brain/graph_rag/person_resolver.py +167 -0
- brain/graph_rag/reconcile.py +792 -0
- brain/graph_rag/relational.py +353 -0
- brain/graph_rag/retrieve.py +526 -0
- brain/graph_rag/router.py +288 -0
- brain/graph_rag/schema.py +320 -0
- brain/graph_rag/sync.py +237 -0
- brain/graph_rag/tenancy.py +43 -0
- brain/graph_rag/themes.py +501 -0
- brain/graph_rag/weighting.py +202 -0
- brain/ingest/__init__.py +1926 -0
- brain/ingest/chunker.py +249 -0
- brain/ingest/docx.py +40 -0
- brain/ingest/gmail.py +621 -0
- brain/ingest/markdown.py +37 -0
- brain/ingest/pdf.py +61 -0
- brain/ingest/stdin.py +22 -0
- brain/ingest/sub_tokens.py +91 -0
- brain/ingest/text.py +16 -0
- brain/interactions.py +205 -0
- brain/maintenance.py +355 -0
- brain/mcp_server.py +3405 -0
- brain/migrations/001_init.sql +43 -0
- brain/migrations/002_qwen3_embedding.sql +17 -0
- brain/migrations/003_vault_model.sql +41 -0
- brain/migrations/004_relax_content_hash_uniqueness.sql +18 -0
- brain/migrations/005_derived_links.sql +67 -0
- brain/migrations/006_dedup_file_by_source_path.sql +25 -0
- brain/migrations/007_email_thread_and_draft.sql +15 -0
- brain/migrations/008_gmail_thread_unique.sql +11 -0
- brain/migrations/009_chunks_weighted_tsv.sql +28 -0
- brain/migrations/010_interactions.sql +30 -0
- brain/migrations/011_documents_summary.sql +23 -0
- brain/migrations/012_graphrag.sql +171 -0
- brain/migrations/013_graphrag_communities.sql +125 -0
- brain/migrations/014_graphrag_community_summary_hash.sql +33 -0
- brain/migrations/015_interactions_graph_targets.sql +89 -0
- brain/migrations/016_index_hygiene.sql +61 -0
- brain/migrations/017_elicit.sql +30 -0
- brain/migrations/018_review_gap_signal_kinds.sql +40 -0
- brain/migrations/019_search_queries.sql +35 -0
- brain/migrations/020_link_suggestions.sql +40 -0
- brain/migrations/021_timeline_doc_date.sql +34 -0
- brain/migrations/022_link_suggestions_undirected.sql +84 -0
- brain/migrations/023_search_queries_fts_count.sql +28 -0
- brain/quartz_overrides/__init__.py +8 -0
- brain/quartz_overrides/quartz/bootstrap-cli.mjs +65 -0
- brain/quartz_overrides/quartz/build.ts +568 -0
- brain/quartz_overrides/quartz/cli/args.js +152 -0
- brain/quartz_overrides/quartz/cli/build_partial_handler.js +544 -0
- brain/quartz_overrides/quartz/cli/handlers.js +636 -0
- brain/quartz_overrides/quartz/components/CommandPalette.tsx +172 -0
- brain/quartz_overrides/quartz/components/Explorer.tsx +198 -0
- brain/quartz_overrides/quartz/components/Footer.tsx +27 -0
- brain/quartz_overrides/quartz/components/Graph.tsx +468 -0
- brain/quartz_overrides/quartz/components/PageTitle.tsx +72 -0
- brain/quartz_overrides/quartz/components/RelatedDocs.tsx +38 -0
- brain/quartz_overrides/quartz/components/Search.tsx +161 -0
- brain/quartz_overrides/quartz/components/SummaryLede.tsx +72 -0
- brain/quartz_overrides/quartz/components/index.ts +92 -0
- brain/quartz_overrides/quartz/components/pages/TagContent.tsx +272 -0
- brain/quartz_overrides/quartz/components/scripts/commandPalette.inline.ts +665 -0
- brain/quartz_overrides/quartz/components/scripts/explorer.inline.ts +768 -0
- brain/quartz_overrides/quartz/components/scripts/graph.inline.ts +2302 -0
- brain/quartz_overrides/quartz/components/scripts/relatedDocs.inline.ts +163 -0
- brain/quartz_overrides/quartz/components/scripts/search.inline.ts +1011 -0
- brain/quartz_overrides/quartz/plugins/emitters/contentIndex.ts +546 -0
- brain/quartz_overrides/quartz/plugins/transformers/codeCopy.ts +94 -0
- brain/quartz_overrides/quartz/plugins/transformers/derivedFenceMark.ts +302 -0
- brain/quartz_overrides/quartz/plugins/transformers/emailThread.ts +148 -0
- brain/quartz_overrides/quartz/plugins/transformers/emptyDoorFilter.ts +213 -0
- brain/quartz_overrides/quartz/plugins/transformers/index.ts +114 -0
- brain/quartz_overrides/quartz/plugins/transformers/linkKindMark.ts +205 -0
- brain/quartz_overrides/quartz/plugins/transformers/linkSourceTag.ts +104 -0
- brain/quartz_overrides/quartz/plugins/transformers/relativeDate.ts +100 -0
- brain/quartz_overrides/quartz/plugins/transformers/reloadSignal.ts +131 -0
- brain/quartz_overrides/quartz/processors/parse.ts +371 -0
- brain/quartz_overrides/quartz/processors/parser_cache.ts +78 -0
- brain/quartz_overrides/quartz/static/brain-logo-dark.png +0 -0
- brain/quartz_overrides/quartz/static/brain-logo-light.png +0 -0
- brain/quartz_overrides/quartz/static/codeCopy.js +196 -0
- brain/quartz_overrides/quartz/static/emailThread.js +334 -0
- brain/quartz_overrides/quartz/static/favicon.ico +0 -0
- brain/quartz_overrides/quartz/static/icon.png +0 -0
- brain/quartz_overrides/quartz/static/linkSourceTag.js +104 -0
- brain/quartz_overrides/quartz/static/relativeDate.js +142 -0
- brain/quartz_overrides/quartz/static/reload.js +168 -0
- brain/quartz_overrides/quartz/styles/brain/_article.scss +252 -0
- brain/quartz_overrides/quartz/styles/brain/_atmosphere.scss +113 -0
- brain/quartz_overrides/quartz/styles/brain/_callouts.scss +180 -0
- brain/quartz_overrides/quartz/styles/brain/_cmdk.scss +7 -0
- brain/quartz_overrides/quartz/styles/brain/_code.scss +208 -0
- brain/quartz_overrides/quartz/styles/brain/_command_palette.scss +369 -0
- brain/quartz_overrides/quartz/styles/brain/_email_thread.scss +228 -0
- brain/quartz_overrides/quartz/styles/brain/_explorer.scss +142 -0
- brain/quartz_overrides/quartz/styles/brain/_home.scss +182 -0
- brain/quartz_overrides/quartz/styles/brain/_links.scss +322 -0
- brain/quartz_overrides/quartz/styles/brain/_marginalia.scss +117 -0
- brain/quartz_overrides/quartz/styles/brain/_motion.scss +175 -0
- brain/quartz_overrides/quartz/styles/brain/_people_hub.scss +100 -0
- brain/quartz_overrides/quartz/styles/brain/_related_docs.scss +137 -0
- brain/quartz_overrides/quartz/styles/brain/_search.scss +252 -0
- brain/quartz_overrides/quartz/styles/brain/_sidebar.scss +468 -0
- brain/quartz_overrides/quartz/styles/brain/_summary_lede.scss +56 -0
- brain/quartz_overrides/quartz/styles/brain/_surface.scss +43 -0
- brain/quartz_overrides/quartz/styles/brain/_tag_content.scss +118 -0
- brain/quartz_overrides/quartz/styles/brain/_tokens.scss +197 -0
- brain/quartz_overrides/quartz/styles/brain/_typography.scss +92 -0
- brain/quartz_overrides/quartz/styles/custom.scss +89 -0
- brain/quartz_overrides/quartz/styles/graph.scss +505 -0
- brain/quartz_overrides/quartz/util/ctx.ts +92 -0
- brain/quartz_overrides/quartz/util/fastpath_manifest.ts +608 -0
- brain/quartz_overrides/quartz/util/path.ts +358 -0
- brain/quartz_overrides/quartz/util/sourceIcons.ts +55 -0
- brain/quartz_overrides/quartz.config.ts +270 -0
- brain/quartz_overrides/quartz.layout.ts +314 -0
- brain/queries.py +1188 -0
- brain/rank_fusion.py +8 -0
- brain/resurface.py +210 -0
- brain/review/__init__.py +26 -0
- brain/review/emit.py +27 -0
- brain/review/queries.py +436 -0
- brain/review/render.py +196 -0
- brain/review/scans.py +355 -0
- brain/review/weekly.py +413 -0
- brain/search.py +704 -0
- brain/set_similarity.py +15 -0
- brain/setup.py +1205 -0
- brain/tags.py +56 -0
- brain/templates/Caddyfile.j2 +9 -0
- brain/templates/__init__.py +1 -0
- brain/templates/bin/__init__.py +1 -0
- brain/templates/bin/_brain-brief-fg.sh +25 -0
- brain/templates/bin/_brain-build-fg.sh +53 -0
- brain/templates/bin/_brain-watcher-fg.sh +65 -0
- brain/templates/bin/brain-down.sh +89 -0
- brain/templates/bin/brain-status.sh +83 -0
- brain/templates/bin/brain-up.sh +221 -0
- brain/templates/docker/age/Dockerfile +79 -0
- brain/templates/docker-compose.stock.yml.j2 +26 -0
- brain/templates/docker-compose.yml.j2 +34 -0
- brain/templates/env.example +190 -0
- brain/templates/launchd/__init__.py +1 -0
- brain/templates/launchd/com.brain.brief.plist.j2 +45 -0
- brain/templates/launchd/com.brain.build.plist.j2 +46 -0
- brain/templates/launchd/com.brain.watcher.plist.j2 +46 -0
- brain/templates/skill/SKILL.md +63 -0
- brain/templates/skill/__init__.py +1 -0
- brain/timeline.py +834 -0
- brain/todo.py +124 -0
- brain/uninstall.py +185 -0
- brain/vault/__init__.py +115 -0
- brain/vault/_atomic.py +25 -0
- brain/vault/daily_index.py +228 -0
- brain/vault/derived_links/__init__.py +50 -0
- brain/vault/derived_links/directory.py +683 -0
- brain/vault/derived_links/fence.py +408 -0
- brain/vault/derived_links/gws.py +64 -0
- brain/vault/derived_links/participants.py +143 -0
- brain/vault/derived_links/pass_runner.py +362 -0
- brain/vault/derived_links/rules.py +137 -0
- brain/vault/export.py +683 -0
- brain/vault/frontmatter.py +165 -0
- brain/vault/graph.py +620 -0
- brain/vault/graph_format.py +388 -0
- brain/vault/link_rewrite.py +235 -0
- brain/vault/links.py +260 -0
- brain/vault/note_builder.py +211 -0
- brain/vault/paths.py +55 -0
- brain/vault/quartz_overlay.py +236 -0
- brain/vault/rename.py +591 -0
- brain/vault/resolver.py +304 -0
- brain/vault/slug.py +127 -0
- brain/vault/sync.py +1513 -0
- brain/vault/sync_summaries.py +264 -0
- brain/vault/templates.py +145 -0
- brain/vault/watch.py +1052 -0
- brain/wiki/__init__.py +6 -0
- brain/wiki/_github_slugger.py +76 -0
- brain/wiki/_person_name.py +314 -0
- brain/wiki/build_homepage.py +541 -0
- brain/wiki/build_partial.py +273 -0
- brain/wiki/build_people.py +934 -0
- brain/wiki/build_related.py +758 -0
- brain/wiki/build_swap.py +585 -0
- brain/wiki/build_watcher.py +975 -0
- brain/wiki/edit_classifier.py +215 -0
- brain/wiki/errors.py +10 -0
- brain/wiki/fastpath_manifest.py +475 -0
- brain/wiki/fastpath_state.py +174 -0
- brain/wiki/install.py +296 -0
- brain/wiki/slug.py +111 -0
- secondbrain_py-0.2.1.dist-info/METADATA +195 -0
- secondbrain_py-0.2.1.dist-info/RECORD +273 -0
- secondbrain_py-0.2.1.dist-info/WHEEL +5 -0
- secondbrain_py-0.2.1.dist-info/entry_points.txt +11 -0
- secondbrain_py-0.2.1.dist-info/licenses/LICENSE +21 -0
- secondbrain_py-0.2.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Custom Postgres image for second-brain GraphRAG (task G0-1).
|
|
2
|
+
# PostgreSQL 16 + pgvector (vector) + pgcrypto (contrib) + Apache AGE (openCypher graph).
|
|
3
|
+
#
|
|
4
|
+
# Canonical, packaged source of truth for the AGE image. The repo-root
|
|
5
|
+
# docker-compose.yml does NOT build this — prod stays on stock
|
|
6
|
+
# `pgvector/pgvector:pg16` until the gated AGE cut-over. This image is built only
|
|
7
|
+
# by docker-compose.age-test.yml (the port-5434 test instance, build context
|
|
8
|
+
# ./src/brain/templates/docker/age) and by the rendered $BRAIN_HOME compose:
|
|
9
|
+
# `brain setup` materializes a copy into $BRAIN_HOME/docker/age/Dockerfile so the
|
|
10
|
+
# generated compose can build it there.
|
|
11
|
+
#
|
|
12
|
+
# Why a custom image:
|
|
13
|
+
# - stock `pgvector/pgvector:pg16` has pgvector + pgcrypto but NOT Apache AGE
|
|
14
|
+
# - stock `apache/age:PG16` has AGE but NOT our exact pgvector setup
|
|
15
|
+
# so we start from the pgvector image (keeps the running DB's pgvector ABI/data
|
|
16
|
+
# layout identical) and compile AGE from a pinned release tag against the SAME
|
|
17
|
+
# PG16 server headers, so the resulting .so/.control/.sql match the server exactly.
|
|
18
|
+
#
|
|
19
|
+
# Pins (immutable):
|
|
20
|
+
# - Base: pgvector/pgvector:0.8.2-pg16 (PG16 + pgvector 0.8.2; matches running DB)
|
|
21
|
+
# - AGE : release tag PG16/v1.5.0-rc0 (commit 0048900f372d4dfd5c236f78b8a8453bcdbb458e)
|
|
22
|
+
# NOTE: upstream Apache AGE has NO GA PG16 tag. `PG16/v1.5.0-rc0` is the
|
|
23
|
+
# latest released PG16 tag (the only newer one is `PG16/v1.6.0-rc0`). It is
|
|
24
|
+
# a release candidate, labelled honestly as "1.5.0-rc0" everywhere — not GA.
|
|
25
|
+
#
|
|
26
|
+
# Apache AGE does NOT require `shared_preload_libraries=age` for the per-session
|
|
27
|
+
# `LOAD 'age';` bootstrap used by `brain init` / `connect`. It can be enabled
|
|
28
|
+
# optionally for performance (see docs/specs/2026-05-20-graphrag-age-image.md).
|
|
29
|
+
|
|
30
|
+
FROM pgvector/pgvector:0.8.2-pg16
|
|
31
|
+
|
|
32
|
+
# Pinned Apache AGE source. AGE_COMMIT is the immutable checkout; AGE_REF is the
|
|
33
|
+
# release tag it must resolve to — verified at build time so the build FAILS if the
|
|
34
|
+
# tag ever moves off the pinned commit (drift guard). Override via --build-arg to
|
|
35
|
+
# upgrade (bump BOTH the ref and the commit together).
|
|
36
|
+
ARG AGE_REPO=https://github.com/apache/age.git
|
|
37
|
+
ARG AGE_REF=PG16/v1.5.0-rc0
|
|
38
|
+
ARG AGE_COMMIT=0048900f372d4dfd5c236f78b8a8453bcdbb458e
|
|
39
|
+
|
|
40
|
+
# Build AGE from source against the image's PG16, then drop all build deps so the
|
|
41
|
+
# final image only carries the compiled extension artifacts (lean image).
|
|
42
|
+
RUN set -eux; \
|
|
43
|
+
apt-mark hold locales; \
|
|
44
|
+
apt-get update; \
|
|
45
|
+
apt-get install -y --no-install-recommends \
|
|
46
|
+
build-essential \
|
|
47
|
+
git \
|
|
48
|
+
ca-certificates \
|
|
49
|
+
postgresql-server-dev-16 \
|
|
50
|
+
bison \
|
|
51
|
+
flex \
|
|
52
|
+
libreadline-dev \
|
|
53
|
+
zlib1g-dev; \
|
|
54
|
+
git clone "$AGE_REPO" /tmp/age; \
|
|
55
|
+
# drift guard: the pinned tag MUST resolve to the pinned commit
|
|
56
|
+
test "$(git -C /tmp/age rev-list -n 1 "$AGE_REF")" = "$AGE_COMMIT"; \
|
|
57
|
+
git -C /tmp/age checkout "$AGE_COMMIT"; \
|
|
58
|
+
make -C /tmp/age PG_CONFIG="$(command -v pg_config)"; \
|
|
59
|
+
make -C /tmp/age PG_CONFIG="$(command -v pg_config)" install; \
|
|
60
|
+
# sanity: AGE control file must land where PG16 expects extensions
|
|
61
|
+
test -f "$(pg_config --sharedir)/extension/age.control"; \
|
|
62
|
+
rm -rf /tmp/age; \
|
|
63
|
+
apt-get purge -y --auto-remove \
|
|
64
|
+
build-essential \
|
|
65
|
+
git \
|
|
66
|
+
postgresql-server-dev-16 \
|
|
67
|
+
bison \
|
|
68
|
+
flex \
|
|
69
|
+
libreadline-dev \
|
|
70
|
+
zlib1g-dev; \
|
|
71
|
+
apt-mark unhold locales; \
|
|
72
|
+
rm -rf /var/lib/apt/lists/*
|
|
73
|
+
|
|
74
|
+
LABEL org.opencontainers.image.title="second-brain-pg16-age-pgvector" \
|
|
75
|
+
org.opencontainers.image.description="PostgreSQL 16 + pgvector 0.8.2 + pgcrypto + Apache AGE 1.5.0-rc0 for second-brain GraphRAG" \
|
|
76
|
+
org.opencontainers.image.base.name="pgvector/pgvector:0.8.2-pg16" \
|
|
77
|
+
brain.age.ref="PG16/v1.5.0-rc0" \
|
|
78
|
+
brain.age.commit="0048900f372d4dfd5c236f78b8a8453bcdbb458e" \
|
|
79
|
+
brain.pgvector.version="0.8.2"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Jinja variables: brain_home, pg_port, compose_project, container_name
|
|
2
|
+
# Stock pgvector compose — the FTS/hybrid twin of the committed root
|
|
3
|
+
# docker-compose.yml, with NO AGE build stanza. Used by `brain setup --profile
|
|
4
|
+
# minimal|standard`; the AGE image (docker-compose.yml.j2) is full-profile only.
|
|
5
|
+
name: {{ compose_project }}
|
|
6
|
+
services:
|
|
7
|
+
postgres:
|
|
8
|
+
image: pgvector/pgvector:pg16
|
|
9
|
+
container_name: {{ container_name }}
|
|
10
|
+
# shared_buffers 512MB: the working set exceeds the stock 128MB default,
|
|
11
|
+
# forcing cold FTS re-reads from disk. Applied as a `postgres -c` flag
|
|
12
|
+
# (no custom postgresql.conf). Matches the committed root compose.
|
|
13
|
+
command: postgres -c shared_buffers=512MB
|
|
14
|
+
environment:
|
|
15
|
+
POSTGRES_USER: brain
|
|
16
|
+
POSTGRES_PASSWORD: brain
|
|
17
|
+
POSTGRES_DB: second_brain
|
|
18
|
+
ports:
|
|
19
|
+
- "{{ pg_port }}:5432"
|
|
20
|
+
volumes:
|
|
21
|
+
- {{ brain_home }}/data/postgres:/var/lib/postgresql/data
|
|
22
|
+
healthcheck:
|
|
23
|
+
test: ["CMD-SHELL", "pg_isready -U brain -d second_brain"]
|
|
24
|
+
interval: 5s
|
|
25
|
+
timeout: 3s
|
|
26
|
+
retries: 10
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Jinja variables: brain_home, pg_port, compose_project, container_name
|
|
2
|
+
name: {{ compose_project }}
|
|
3
|
+
services:
|
|
4
|
+
postgres:
|
|
5
|
+
# Custom PG16 image: pgvector 0.8.2 + pgcrypto + Apache AGE 1.5.0-rc0 (GraphRAG).
|
|
6
|
+
# `image:` points at the prebuilt multi-arch image on GHCR, so a fresh install
|
|
7
|
+
# can `docker compose pull` it instead of compiling AGE from C source (slow +
|
|
8
|
+
# fragile on Apple Silicon). The `build:` stanza is a LOCAL FALLBACK: `brain
|
|
9
|
+
# setup` materializes the packaged Dockerfile into
|
|
10
|
+
# {{ brain_home }}/docker/age/Dockerfile, so `docker compose up --build`
|
|
11
|
+
# resolves and compiles locally when the registry image is unavailable.
|
|
12
|
+
build:
|
|
13
|
+
context: {{ brain_home }}/docker/age
|
|
14
|
+
dockerfile: Dockerfile
|
|
15
|
+
image: ghcr.io/mshtawythug/second-brain-age:pg16-v1.5.0-rc0-pgv0.8.2
|
|
16
|
+
container_name: {{ container_name }}
|
|
17
|
+
# shared_buffers 512MB: the working set exceeds the stock 128MB default,
|
|
18
|
+
# forcing cold FTS re-reads from disk. Applied as a `postgres -c` flag (no
|
|
19
|
+
# custom postgresql.conf). Matches the stock template + committed root
|
|
20
|
+
# compose; the heavier full profile (graph + FTS + vector) benefits most.
|
|
21
|
+
command: postgres -c shared_buffers=512MB
|
|
22
|
+
environment:
|
|
23
|
+
POSTGRES_USER: brain
|
|
24
|
+
POSTGRES_PASSWORD: brain
|
|
25
|
+
POSTGRES_DB: second_brain
|
|
26
|
+
ports:
|
|
27
|
+
- "{{ pg_port }}:5432"
|
|
28
|
+
volumes:
|
|
29
|
+
- {{ brain_home }}/data/postgres:/var/lib/postgresql/data
|
|
30
|
+
healthcheck:
|
|
31
|
+
test: ["CMD-SHELL", "pg_isready -U brain -d second_brain"]
|
|
32
|
+
interval: 5s
|
|
33
|
+
timeout: 3s
|
|
34
|
+
retries: 10
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Embedder backend: arctic (default, free, local) | voyage (paid SaaS)
|
|
2
|
+
# | qwen3 (free, local, China-origin)
|
|
3
|
+
BRAIN_EMBEDDER=arctic
|
|
4
|
+
|
|
5
|
+
# Ollama (required for arctic + qwen3; install: brew install ollama && brew services start ollama)
|
|
6
|
+
# For arctic: ollama pull snowflake-arctic-embed2
|
|
7
|
+
# For qwen3: ollama pull qwen3-embedding:8b
|
|
8
|
+
OLLAMA_HOST=http://localhost:11434
|
|
9
|
+
QWEN3_MODEL=qwen3-embedding:8b
|
|
10
|
+
|
|
11
|
+
# Voyage AI (required only when BRAIN_EMBEDDER=voyage)
|
|
12
|
+
# VOYAGE_API_KEY=
|
|
13
|
+
|
|
14
|
+
# Local Postgres (Docker)
|
|
15
|
+
# DATABASE_URL → prod on the stock pgvector image, port 55432
|
|
16
|
+
# (docker-compose.yml, ./data/postgres bind-mount). `brain setup` substitutes
|
|
17
|
+
# the chosen --port into the {{ pg_port }} placeholder below (default 55432);
|
|
18
|
+
# the same value is rendered into docker-compose.yml so the two never drift.
|
|
19
|
+
# The Apache AGE cutover of the prod container is gated — see
|
|
20
|
+
# docs/specs/2026-05-20-graphrag-age-image.md.
|
|
21
|
+
# TEST_DATABASE_URL → the SEPARATE Apache-AGE test instance on port 5434
|
|
22
|
+
# (docker-compose.age-test.yml, named volume), so the suite runs against the
|
|
23
|
+
# PG16 + pgvector 0.8.2 + pgcrypto + Apache AGE 1.5.0-rc0 superset image.
|
|
24
|
+
# Start it: docker compose -f docker-compose.age-test.yml up -d --build
|
|
25
|
+
DATABASE_URL=postgresql://brain:brain@localhost:{{ pg_port }}/second_brain
|
|
26
|
+
TEST_DATABASE_URL=postgresql://brain:brain@localhost:5434/second_brain_test
|
|
27
|
+
|
|
28
|
+
# Vault folder (default: ~/brain-vault). Override to point elsewhere — e.g.
|
|
29
|
+
# ~/Documents/brain-vault for iCloud-friendly sync on macOS.
|
|
30
|
+
# BRAIN_VAULT_PATH=
|
|
31
|
+
|
|
32
|
+
# Owner email — used by the email-thread reading mode (P4.4) to power the
|
|
33
|
+
# "Show only my replies" filter on `_ingested/gmail/<thread>/` pages. The
|
|
34
|
+
# Quartz build reads this at build time and bakes it into rendered pages
|
|
35
|
+
# as `window.BRAIN_USER_EMAIL`. Leave unset to render the toggle without
|
|
36
|
+
# a user identity (the filter matches nothing).
|
|
37
|
+
# BRAIN_USER_EMAIL=you@example.com
|
|
38
|
+
|
|
39
|
+
# Comma-separated list of identifiers (emails AND/OR display names) that
|
|
40
|
+
# count as the corpus owner. Stripped from participant_keys before
|
|
41
|
+
# derived-edge rules R2 (shared_participant) and R3 (same_day_participant)
|
|
42
|
+
# evaluate, so a meeting/email isn't linked to every other doc the owner
|
|
43
|
+
# is on. Both forms accepted; matching is case-insensitive (entries are
|
|
44
|
+
# trimmed + lowercased at load time). Leave unset for the default
|
|
45
|
+
# behaviour (no stripping).
|
|
46
|
+
# Example: BRAIN_OWNER_PARTICIPANTS="Ali Sarkis,redacted@example.com,redacted@example.com"
|
|
47
|
+
# BRAIN_OWNER_PARTICIPANTS=
|
|
48
|
+
|
|
49
|
+
# Recency boost half-life in days. After RRF, each document's score is
|
|
50
|
+
# multiplied by 0.5 ** (age_days / halflife_days) where age_days comes from
|
|
51
|
+
# coalesce(sent_at, ingested_at). Default 180 days. Set to a very large value
|
|
52
|
+
# (e.g. 999999) to effectively disable the boost. Must be a positive float.
|
|
53
|
+
# BRAIN_RECENCY_HALFLIFE_DAYS=180
|
|
54
|
+
|
|
55
|
+
# Snippet-context expansion budget (tokens). After the best-matching chunk is
|
|
56
|
+
# identified, this many tokens of neighboring-chunk context are stitched
|
|
57
|
+
# around it to give richer reading context. Default 200. Set to 0 to use the
|
|
58
|
+
# legacy single-chunk snippet. Must be a non-negative integer.
|
|
59
|
+
# BRAIN_SNIPPET_CONTEXT_TOKENS=200
|
|
60
|
+
|
|
61
|
+
# Enrichment model (Ollama) for auto-summary + auto-tags. Default
|
|
62
|
+
# llama3.1:8b. Override for higher quality (gemma3:27b — ~60s/doc on M1 Pro,
|
|
63
|
+
# best summarization in the non-Chinese open-weight space) or higher speed
|
|
64
|
+
# (llama3.2:3b — ~4s/doc, looser tags). Switching models causes
|
|
65
|
+
# `brain enrich --backfill` to re-enrich all docs whose summary_model no
|
|
66
|
+
# longer matches the current setting.
|
|
67
|
+
# BRAIN_ENRICH_MODEL=llama3.1:8b
|
|
68
|
+
|
|
69
|
+
# Enrichment HTTP timeout in seconds. Default 60. Raise when running a
|
|
70
|
+
# larger model (gemma3:27b / phi4:14b / mistral-small) — cold-load + long
|
|
71
|
+
# inputs can exceed 60s on Apple Silicon.
|
|
72
|
+
# BRAIN_ENRICH_TIMEOUT_SECONDS=60
|
|
73
|
+
|
|
74
|
+
# Minimum input tokens before a doc is enriched. Docs shorter than this
|
|
75
|
+
# skip enrichment (a 1-paragraph note doesn't benefit from a summary).
|
|
76
|
+
# Default 50. Set to 0 to enrich every doc.
|
|
77
|
+
# BRAIN_ENRICH_MIN_TOKENS=50
|
|
78
|
+
|
|
79
|
+
# Maximum input tokens fed to the enricher. Long docs are head-truncated.
|
|
80
|
+
# Default 4000. Lower to speed up the backfill at the cost of summary
|
|
81
|
+
# fidelity on long docs.
|
|
82
|
+
# BRAIN_ENRICH_MAX_INPUT_TOKENS=4000
|
|
83
|
+
|
|
84
|
+
# --- GraphRAG (Apache AGE entity graph) --------------------------------------
|
|
85
|
+
# Default-ON entity-graph sync alongside the vector/hybrid search. `brain setup`
|
|
86
|
+
# provisions a Postgres image that ships Apache AGE; the committed
|
|
87
|
+
# docker-compose.yml in the repo root stays on stock pgvector and operators flip
|
|
88
|
+
# to AGE via a local docker-compose.override.yml — see
|
|
89
|
+
# docs/specs/2026-05-20-graphrag-age-image.md. On a stock pgvector DB the graph
|
|
90
|
+
# stack auto-degrades to a no-op (init prints "graph skipped — AGE not
|
|
91
|
+
# available"; ingest's graph sync is best-effort and never raises). Names match
|
|
92
|
+
# the design spec §10.
|
|
93
|
+
|
|
94
|
+
# Enable the people-aspect graph sync hook. When true AND the DB ships Apache
|
|
95
|
+
# AGE, every ingest/edit/delete keeps the people graph in lock-step with the
|
|
96
|
+
# documents table; on a stock pgvector DB the sync is a best-effort no-op
|
|
97
|
+
# (silent no-op when AGE is absent; logged + dropped if AGE is present but reconcile raises). Accepts 1/true/yes/on or 0/false/no/off.
|
|
98
|
+
# Default true (the brain setup template provisions an AGE-capable image).
|
|
99
|
+
# Set to false to disable graph sync at ingest time.
|
|
100
|
+
# BRAIN_GRAPH_ENABLED=true
|
|
101
|
+
|
|
102
|
+
# Tenant id stamped on every graph row/vertex/edge and every query. Single-user
|
|
103
|
+
# local deployments leave this at the default. Default "default".
|
|
104
|
+
# BRAIN_GRAPH_TENANT=default
|
|
105
|
+
|
|
106
|
+
# Co-occurrence sliding-window radius (inclusive, unit-agnostic). For the people
|
|
107
|
+
# aspect every participant shares one notional position, so any window >= 1
|
|
108
|
+
# yields the complete graph over a document's persons. Positive integer.
|
|
109
|
+
# Default 3.
|
|
110
|
+
# BRAIN_GRAPH_COOCCUR_WINDOW=3
|
|
111
|
+
|
|
112
|
+
# Per-document entity cap — bounds the O(pairs) co-occurrence work on an
|
|
113
|
+
# entity-dense document. A positive integer, or "none"/"unlimited" to disable
|
|
114
|
+
# the cap. Default 40.
|
|
115
|
+
# BRAIN_GRAPH_MAX_ENTITIES_PER_DOC=40
|
|
116
|
+
|
|
117
|
+
# Generic-entity document-frequency ratio. An entity appearing in more than
|
|
118
|
+
# round(ratio * tenant_corpus_N) documents is treated as generic and its edges
|
|
119
|
+
# are suppressed at derive time. A float in (0.0, 1.0]. Changing it forces a
|
|
120
|
+
# corpus-wide re-derive — run `brain graphrag refresh`. Default 0.30.
|
|
121
|
+
# BRAIN_GRAPH_GENERIC_DF=0.30
|
|
122
|
+
|
|
123
|
+
# --- GraphRAG concept extraction + retrieval ---------------------------------
|
|
124
|
+
# Names match the design spec §10. The concept extractor v2 passed its eval
|
|
125
|
+
# gate (f1 ~0.88 on the local eval set) so the aspect is default-ON.
|
|
126
|
+
|
|
127
|
+
# Enable the concept aspect (LLM entity extraction over topics/projects/orgs/
|
|
128
|
+
# tools) alongside the always-on people aspect. Requires
|
|
129
|
+
# BRAIN_GRAPH_EXTRACT_MODEL to be pullable via `ollama pull <name>` (default
|
|
130
|
+
# llama3.1:8b — ~4.7 GB). Set to false to disable concept extraction (people
|
|
131
|
+
# aspect still works without an LLM). Default true.
|
|
132
|
+
# BRAIN_GRAPH_CONCEPTS=true
|
|
133
|
+
|
|
134
|
+
# Ollama model for the concept entity extractor. Any model pullable via
|
|
135
|
+
# `ollama pull <name>` that supports JSON-mode output. Default llama3.1:8b.
|
|
136
|
+
# BRAIN_GRAPH_EXTRACT_MODEL=llama3.1:8b
|
|
137
|
+
|
|
138
|
+
# Bounded traversal radius for local/themes retrieval (variable-length hops).
|
|
139
|
+
# Positive integer. Default 2.
|
|
140
|
+
# BRAIN_GRAPH_DEPTH=2
|
|
141
|
+
|
|
142
|
+
# Frontier cap — max entities reached per seed during traversal. Positive
|
|
143
|
+
# integer. Default 200.
|
|
144
|
+
# BRAIN_GRAPH_FRONTIER_CAP=200
|
|
145
|
+
|
|
146
|
+
# Per-node expansion fan-out cap during traversal. Positive integer. Default 50.
|
|
147
|
+
# BRAIN_GRAPH_MAX_DEGREE=50
|
|
148
|
+
|
|
149
|
+
# Minimum normalized-lift edge weight admitted into a traversal. A float in
|
|
150
|
+
# [0.0, 1.0]; 0.0 admits every edge. Default 0.20.
|
|
151
|
+
# BRAIN_GRAPH_MIN_EDGE_WEIGHT=0.20
|
|
152
|
+
|
|
153
|
+
# Number of ranked theme groups returned by "themes with X". Positive integer.
|
|
154
|
+
# Default 5.
|
|
155
|
+
# BRAIN_GRAPH_THEME_LIMIT=5
|
|
156
|
+
|
|
157
|
+
# --- GraphRAG global communities (wave G3) -----------------------------------
|
|
158
|
+
# Parsed in wave G3; consumed by `brain graphrag communities build|refresh`
|
|
159
|
+
# (networkx Louvain over the tenant entity graph) and the global retrieval path.
|
|
160
|
+
# §17c pins the migration-013 schema + perf budgets but NOT these tuning
|
|
161
|
+
# defaults — the values below are chosen to be consistent with the other graph
|
|
162
|
+
# knobs.
|
|
163
|
+
|
|
164
|
+
# Louvain resolution. Higher values yield more, smaller communities; lower
|
|
165
|
+
# values yield fewer, larger ones. Positive float. Default 1.0 (networkx
|
|
166
|
+
# default).
|
|
167
|
+
# BRAIN_GRAPH_COMMUNITY_RESOLUTION=1.0
|
|
168
|
+
|
|
169
|
+
# RNG seed for deterministic Louvain detection (so repeated builds over an
|
|
170
|
+
# unchanged graph produce stable communities). Non-negative integer.
|
|
171
|
+
# Default 1234.
|
|
172
|
+
# BRAIN_GRAPH_COMMUNITY_SEED=1234
|
|
173
|
+
|
|
174
|
+
# Minimum members for a community to be materialized — smaller communities are
|
|
175
|
+
# dropped. Positive integer. Default 3.
|
|
176
|
+
# BRAIN_GRAPH_COMMUNITY_MIN_SIZE=3
|
|
177
|
+
|
|
178
|
+
# Jaccard overlap threshold for stable-identity matching across rebuilds: a new
|
|
179
|
+
# community whose member set overlaps an old one by >= this fraction reuses the
|
|
180
|
+
# old community_key. A float in [0.0, 1.0]. Default 0.5.
|
|
181
|
+
# BRAIN_GRAPH_COMMUNITY_JACCARD=0.5
|
|
182
|
+
|
|
183
|
+
# Number of ranked communities returned by the global retrieval mode. Positive
|
|
184
|
+
# integer. Default 5.
|
|
185
|
+
# BRAIN_GRAPH_COMMUNITY_LIMIT=5
|
|
186
|
+
|
|
187
|
+
# Ops safety cap on the number of communities materialized per tenant per build
|
|
188
|
+
# (bounds the summary + embedding cost). A positive integer, or "none"/
|
|
189
|
+
# "unlimited" to disable. Default none (unlimited).
|
|
190
|
+
# BRAIN_GRAPH_COMMUNITY_MAX=none
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Marker so importlib.resources can resolve this subdirectory in pipx-installed wheels."""
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!-- Jinja variables: brain_home, user_home, pipx_bin_dir, vault_path, brain_py
|
|
3
|
+
The launchd renderer (brain.bin.launchd.render_plist) MUST XML-escape every
|
|
4
|
+
value before substitution (Path strings with '&' / '<' / '>' would otherwise
|
|
5
|
+
produce invalid plist XML and launchctl bootstrap would fail).
|
|
6
|
+
|
|
7
|
+
Unlike the watcher/build agents this is a ONE-SHOT job: StartCalendarInterval
|
|
8
|
+
fires the brief once at 07:00 local each day (no KeepAlive, no RunAtLoad).
|
|
9
|
+
The brief writes the daily digest page; LLM suggestions are best-effort and
|
|
10
|
+
skipped silently if Ollama is down. -->
|
|
11
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
12
|
+
<plist version="1.0">
|
|
13
|
+
<dict>
|
|
14
|
+
<key>Label</key>
|
|
15
|
+
<string>com.brain.brief</string>
|
|
16
|
+
<key>ProgramArguments</key>
|
|
17
|
+
<array>
|
|
18
|
+
<string>{{ brain_home }}/.shims/_brain-brief-fg</string>
|
|
19
|
+
</array>
|
|
20
|
+
<key>EnvironmentVariables</key>
|
|
21
|
+
<dict>
|
|
22
|
+
<key>HOME</key>
|
|
23
|
+
<string>{{ user_home }}</string>
|
|
24
|
+
<key>PATH</key>
|
|
25
|
+
<string>{{ pipx_bin_dir }}:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
26
|
+
<key>BRAIN_VAULT_PATH</key>
|
|
27
|
+
<string>{{ vault_path }}</string>
|
|
28
|
+
<key>BRAIN_PY</key>
|
|
29
|
+
<string>{{ brain_py }}</string>
|
|
30
|
+
</dict>
|
|
31
|
+
<key>StartCalendarInterval</key>
|
|
32
|
+
<dict>
|
|
33
|
+
<key>Hour</key>
|
|
34
|
+
<integer>7</integer>
|
|
35
|
+
<key>Minute</key>
|
|
36
|
+
<integer>0</integer>
|
|
37
|
+
</dict>
|
|
38
|
+
<key>WorkingDirectory</key>
|
|
39
|
+
<string>{{ brain_home }}</string>
|
|
40
|
+
<key>StandardOutPath</key>
|
|
41
|
+
<string>{{ brain_home }}/logs/com.brain.brief.out.log</string>
|
|
42
|
+
<key>StandardErrorPath</key>
|
|
43
|
+
<string>{{ brain_home }}/logs/com.brain.brief.err.log</string>
|
|
44
|
+
</dict>
|
|
45
|
+
</plist>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!-- Jinja variables: brain_home, user_home, pipx_bin_dir, vault_path, brain_py
|
|
3
|
+
T1.7 renderer MUST XML-escape every value before substitution
|
|
4
|
+
(Path strings with '&' / '<' / '>' would otherwise produce invalid
|
|
5
|
+
plist XML and launchctl bootstrap would fail with a parse error). -->
|
|
6
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
7
|
+
<plist version="1.0">
|
|
8
|
+
<dict>
|
|
9
|
+
<key>Label</key>
|
|
10
|
+
<string>com.brain.build</string>
|
|
11
|
+
<key>ProgramArguments</key>
|
|
12
|
+
<array>
|
|
13
|
+
<string>{{ brain_home }}/.shims/_brain-build-fg</string>
|
|
14
|
+
</array>
|
|
15
|
+
<key>EnvironmentVariables</key>
|
|
16
|
+
<dict>
|
|
17
|
+
<key>HOME</key>
|
|
18
|
+
<string>{{ user_home }}</string>
|
|
19
|
+
<key>PATH</key>
|
|
20
|
+
<string>{{ pipx_bin_dir }}:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
21
|
+
<key>BRAIN_VAULT_PATH</key>
|
|
22
|
+
<string>{{ vault_path }}</string>
|
|
23
|
+
<!-- BRAIN_PY pins the exact Python interpreter that has `brain` importable.
|
|
24
|
+
For a pipx install this is the pipx venv Python
|
|
25
|
+
(e.g. ~/.local/pipx/venvs/secondbrain-py/bin/python).
|
|
26
|
+
T1.7's plist generator resolves and substitutes this variable.
|
|
27
|
+
Without it the shell scripts fall back to system python3 which
|
|
28
|
+
does NOT have brain on sys.path and every `python -m brain.*`
|
|
29
|
+
call would fail with ModuleNotFoundError. -->
|
|
30
|
+
<key>BRAIN_PY</key>
|
|
31
|
+
<string>{{ brain_py }}</string>
|
|
32
|
+
</dict>
|
|
33
|
+
<key>RunAtLoad</key>
|
|
34
|
+
<true/>
|
|
35
|
+
<key>KeepAlive</key>
|
|
36
|
+
<true/>
|
|
37
|
+
<key>ThrottleInterval</key>
|
|
38
|
+
<integer>10</integer>
|
|
39
|
+
<key>WorkingDirectory</key>
|
|
40
|
+
<string>{{ brain_home }}</string>
|
|
41
|
+
<key>StandardOutPath</key>
|
|
42
|
+
<string>{{ brain_home }}/logs/com.brain.build.out.log</string>
|
|
43
|
+
<key>StandardErrorPath</key>
|
|
44
|
+
<string>{{ brain_home }}/logs/com.brain.build.err.log</string>
|
|
45
|
+
</dict>
|
|
46
|
+
</plist>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!-- Jinja variables: brain_home, user_home, pipx_bin_dir, vault_path, brain_py
|
|
3
|
+
T1.7 renderer MUST XML-escape every value before substitution
|
|
4
|
+
(Path strings with '&' / '<' / '>' would otherwise produce invalid
|
|
5
|
+
plist XML and launchctl bootstrap would fail with a parse error). -->
|
|
6
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
7
|
+
<plist version="1.0">
|
|
8
|
+
<dict>
|
|
9
|
+
<key>Label</key>
|
|
10
|
+
<string>com.brain.watcher</string>
|
|
11
|
+
<key>ProgramArguments</key>
|
|
12
|
+
<array>
|
|
13
|
+
<string>{{ brain_home }}/.shims/_brain-watcher-fg</string>
|
|
14
|
+
</array>
|
|
15
|
+
<key>EnvironmentVariables</key>
|
|
16
|
+
<dict>
|
|
17
|
+
<key>HOME</key>
|
|
18
|
+
<string>{{ user_home }}</string>
|
|
19
|
+
<key>PATH</key>
|
|
20
|
+
<string>{{ pipx_bin_dir }}:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
21
|
+
<key>BRAIN_VAULT_PATH</key>
|
|
22
|
+
<string>{{ vault_path }}</string>
|
|
23
|
+
<!-- BRAIN_PY pins the exact Python interpreter that has `brain` importable.
|
|
24
|
+
For a pipx install this is the pipx venv Python
|
|
25
|
+
(e.g. ~/.local/pipx/venvs/secondbrain-py/bin/python).
|
|
26
|
+
T1.7's plist generator resolves and substitutes this variable.
|
|
27
|
+
Without it the shell scripts fall back to system python3 which
|
|
28
|
+
does NOT have brain on sys.path and every `python -m brain.*`
|
|
29
|
+
call would fail with ModuleNotFoundError. -->
|
|
30
|
+
<key>BRAIN_PY</key>
|
|
31
|
+
<string>{{ brain_py }}</string>
|
|
32
|
+
</dict>
|
|
33
|
+
<key>RunAtLoad</key>
|
|
34
|
+
<true/>
|
|
35
|
+
<key>KeepAlive</key>
|
|
36
|
+
<true/>
|
|
37
|
+
<key>ThrottleInterval</key>
|
|
38
|
+
<integer>10</integer>
|
|
39
|
+
<key>WorkingDirectory</key>
|
|
40
|
+
<string>{{ brain_home }}</string>
|
|
41
|
+
<key>StandardOutPath</key>
|
|
42
|
+
<string>{{ brain_home }}/logs/com.brain.watcher.out.log</string>
|
|
43
|
+
<key>StandardErrorPath</key>
|
|
44
|
+
<string>{{ brain_home }}/logs/com.brain.watcher.err.log</string>
|
|
45
|
+
</dict>
|
|
46
|
+
</plist>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Query the user's local second-brain knowledge base (career, past meetings, Slack/Gmail/Krisp transcripts) via the `brain` CLI. Use when the user asks about their background, past meetings, past Slack threads, past emails, interview prep, or specific people / projects they've mentioned.
|
|
3
|
+
when_to_use: Trigger on phrases like "what did I say about X", "my thoughts on Y", "meetings about Z", "interview prep", "tell me about my work on W", or any question requiring personal context the user has stored in their second brain.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Second Brain — `brain` CLI
|
|
7
|
+
|
|
8
|
+
The user has a personal knowledge base at their vault (default
|
|
9
|
+
`~/brain-vault`). Use it whenever a conversation touches their career,
|
|
10
|
+
past meetings, past Slack threads, past emails, interview prep, or
|
|
11
|
+
specific people / projects they've mentioned.
|
|
12
|
+
|
|
13
|
+
**Search** — `brain search "..."` returns the top 5 matching documents
|
|
14
|
+
with snippets and IDs. Use `--json` if you need to parse output.
|
|
15
|
+
Basic filters: `--source krisp|slack|gmail|manual`, `--tag X`,
|
|
16
|
+
`--has-tag X`, `--without-tag X`, `--since N` (days), `--limit N`,
|
|
17
|
+
`--fts-only`.
|
|
18
|
+
Metadata filters: `--person "Name"` (resolved via the directory, same
|
|
19
|
+
as `brain people`), `--after YYYY-MM-DD`, `--before YYYY-MM-DD`,
|
|
20
|
+
`--kind transcript|email|email_thread|note|markdown|pdf|...`,
|
|
21
|
+
`--thread <gmail-thread-id>`, `--draft` (only drafts) or `--no-draft`
|
|
22
|
+
(only published).
|
|
23
|
+
Prefer narrower queries — e.g. `brain search "interview prep"
|
|
24
|
+
--person "person-x" --after 2026-03-01 --kind transcript` is much better
|
|
25
|
+
signal than the same query unfiltered.
|
|
26
|
+
|
|
27
|
+
**Explain a search** — `brain explain "..."` shows per-result FTS rank,
|
|
28
|
+
vector cosine, RRF contributions, and recency boost so you can debug
|
|
29
|
+
why a result ranked where it did. `--verbose` also shows active filters.
|
|
30
|
+
|
|
31
|
+
**Read full** — `brain show <id-prefix>` (6+ chars). Returns the
|
|
32
|
+
document body. `brain show <id> --json` may also include a `summary`
|
|
33
|
+
field if the document has been auto-summarized; the key is omitted on
|
|
34
|
+
docs that haven't been summarized yet.
|
|
35
|
+
|
|
36
|
+
**Browse people** — `brain people` lists people with at least
|
|
37
|
+
`BRAIN_PEOPLE_HUB_MIN_DOCS` appearances in the corpus (default 3, owner
|
|
38
|
+
filtered out via `BRAIN_OWNER_PARTICIPANTS`). `brain people "Name"`
|
|
39
|
+
takes a case-insensitive substring of a display name and lists that
|
|
40
|
+
person's docs.
|
|
41
|
+
|
|
42
|
+
**Action items** — `brain todo` lists open Krisp-meeting action items.
|
|
43
|
+
Flags: `--source krisp` (only source supported today), `--since N`
|
|
44
|
+
(only items from docs ingested in the last N days), `--closed` (include
|
|
45
|
+
closed items, default open only), `--limit/-n N`, `--json`.
|
|
46
|
+
|
|
47
|
+
**Record a rating** — when the user explicitly says a search result was
|
|
48
|
+
useful or irrelevant, call `brain rate <id-prefix> useful` (or
|
|
49
|
+
`irrelevant`) so the interaction is logged. Don't volunteer this — only
|
|
50
|
+
when the user asks.
|
|
51
|
+
|
|
52
|
+
**Ingest Gmail** — `brain ingest-gmail` (requires one or more scope
|
|
53
|
+
flags — never bulk-ingest the inbox). Scope flags: `--query/-q` (raw
|
|
54
|
+
Gmail search), `--label/-l`, `--from`, `--since YYYY/MM/DD`,
|
|
55
|
+
`--until YYYY/MM/DD`. Optional: `--tag/-t`, `--max N` (default 50),
|
|
56
|
+
`--dry-run`, `--no-enrich`.
|
|
57
|
+
|
|
58
|
+
**Ingest from Krisp / Slack** — these don't have CLIs; pipe content via
|
|
59
|
+
`brain ingest-stdin --source krisp|slack --external-id … --title … --date
|
|
60
|
+
…` after fetching from the relevant MCP.
|
|
61
|
+
|
|
62
|
+
**When in doubt:** `brain doctor` confirms it's installed and healthy.
|
|
63
|
+
`brain --help` lists every subcommand.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Marker so importlib.resources can resolve this subdirectory in pipx-installed wheels."""
|