Skip to content

Shared Brain — кросс-проектные знания в Notion

Статус: opt-in, pipeline готов. v1.4 поставляется с интерактивным мастером настройки: чеклист требований сразу при запуске, дружелюбные сообщения при отсутствующем токене, конкретные подсказки про URL и page ID. Запуск bootstrap с --interactive --init сам предложит мастер; иначе — .tausik/tausik brain init.

Локальная проектная память TAUSIK (.tausik/tausik.db) — основной store для всего, что относится к этому репозиторию. Shared Brain — опциональный второй слой: база знаний в Notion, куда пишутся только обобщаемые между проектами знания — дорого добытые архитектурные инсайты, жёсткие подводные камни, стабильные паттерны, и HTTP-кэш, который полезен всем репозиториям.

Разделение намеренное. Локальная БД хранит проектно-специфичные следы (пути к файлам, имена модулей, слаги клиентов) — всё, что может утечь между несвязанными кодовыми базами. Brain хранит то, что ты хотел бы, чтобы свежий агент в другом репозитории унаследовал.

Философия

СлойStoreScopeПример
Local.tausik/tausik.dbТолько этот проект"auth-middleware.py строка 42 логирует PII — фикс в MR-1234"
BrainNotion databasesКросс-проектное"SHA256-хэш проекта избегает утечки имён и уникален для N<1000"

Таксономия артефактов (v1.4): общий словарь artifact / pattern / snippet для MCP brain_store_* и будущих snippet-карт — см. brain-artifact-taxonomy.md (опциональное поле и строгий режим в .tausik/config.json).

Редакция памяти: когда объединять локальные строки памяти, а когда заводить новую запись (ортогонально scrubbing) — Память: merge vs новая запись.

Ничто идентифицирующее проект не должно попасть в brain. Защита:

  1. Scrubbing linter отклоняет записи с абсолютными путями, kebab-слагами ≥3 частей, командами .tausik/tausik, internal URLs.
  2. Classifier решает, local или brain у записи; только brain-класс попадает в Notion.
  3. Source Project Hash — каждая запись несёт SHA256(canonical_name)[:16], так что даже если проектный идентификатор случайно проскочит аудит, читатель Notion не сможет сопоставить хэши с именами проектов без локального реестра.

Архитектура

                     ┌────────────────────┐
                     │  Notion workspace  │
                     │  (4 databases)     │
                     │  decisions         │
                     │  web_cache         │
                     │  patterns          │
                     │  gotchas           │
                     └─────────┬──────────┘
                               │  Notion REST API
                               │  (Bearer + Notion-Version)
              ┌────────────────▼─────────────────┐
              │  scripts/brain_notion_client.py  │  stdlib urllib,
              │  throttle 350ms, 429/5xx retry   │  ноль зависимостей
              └────────────────┬─────────────────┘

                  ┌────────────┴─────────────┐
                  │                          │
         pages_create             iter_database_query
         (write path)             (pull с дельтой)
                  │                          │
                  │                          ▼
                  │           ┌──────────────────────────┐
                  │           │ scripts/brain_sync.py    │
                  │           │ map Notion→SQLite rows   │
                  │           │ upsert по page_id        │
                  │           │ продвижение sync_state   │
                  │           └────────────┬─────────────┘
                  │                        │
                  │                        ▼
                  │           ┌──────────────────────────┐
                  │           │ ~/.tausik-brain/brain.db │
                  │           │ brain_schema + FTS5      │
                  │           │ unicode61 tokenizer      │
                  │           └────────────┬─────────────┘
                  │                        │
                  │                        ▼
                  │           ┌──────────────────────────┐
                  │           │ scripts/brain_search.py  │
                  │           │ bm25-ранжированный поиск │
                  │           └────────────┬─────────────┘
                  │                        │
                  └────────────┬───────────┘

                  ┌────────────▼──────────────┐
                  │ scripts/brain_config.py   │
                  │ загрузка и валидация      │
                  │ project hash, token env   │
                  └───────────────────────────┘

Модули (готовы)

ФайлНазначение
scripts/brain_config.pyПарсинг конфига + валидация; compute_project_hash, get_brain_mirror_path
scripts/brain_schema.pyLocal SQLite DDL (4 таблицы + FTS5 + триггеры, unicode61 токенизатор)
scripts/brain_notion_client.pyStdlib Notion REST клиент (throttle + retry + pagination iterator)
scripts/brain_sync.pyDelta-pull Notion → local; маппинг Notion page JSON → SQLite rows
scripts/brain_search.pyЛокальный FTS5 поиск с bm25 и SQL snippet()
brain-db-schema.mdDesign-doc — properties, JSON payload примеры, trade-offs

Настройка

Предпосылка: Notion workspace, который ты контролируешь.

1. Создать parent page

В сайдбаре Notion создай страницу "TAUSIK Shared Brain" (или любое имя). Wizard создаст под ней 4 базы.

2. Создать integration

  1. https://www.notion.so/my-integrations → "New integration".
  2. Имя: "TAUSIK Brain".
  3. Type: Internal.
  4. Capabilities: Read, Update, Insert content.
  5. Скопируй internal integration token (начинается с ntn_ или legacy secret_).

3. Дать integration доступ к parent page

Открой страницу "TAUSIK Shared Brain" → справа вверху ... → "Add connections" → выбери "TAUSIK Brain". Wizard создаёт базы под этой страницей — integration должен её видеть.

4. Сохранить токен (выбери одно — v1.3.2+ поддерживает каскад)

Notion-токен резолвится в таком порядке приоритета:

  1. os.environ[NOTION_TAUSIK_TOKEN] — env var. Высший приоритет. Подходит для CI / shared машин.
  2. .tausik/.env — project-local KEY=VALUE файл. Рекомендуется для индивидуальных разработчиков: gitignored, не требует правки shell-rc, переживает ребут.
  3. brain.notion_integration_token в .tausik/config.json — выдаёт stderr warning ("stored inline; prefer .tausik/.env"). Разрешено, но не рекомендуется.

Рекомендуемый путь — .tausik/.env:

bash
echo "NOTION_TAUSIK_TOKEN=ntn_xxx" >> .tausik/.env

Если предпочитаешь env-переменную:

bash
# Linux / macOS — для persistence добавь в ~/.bashrc / ~/.zshrc / ~/.profile
export NOTION_TAUSIK_TOKEN='ntn_xxx'
powershell
# Windows — User-level (переживёт ребут, IDE restart подхватит)
[System.Environment]::SetEnvironmentVariable('NOTION_TAUSIK_TOKEN', 'ntn_xxx', 'User')
# Применить к текущей PowerShell-сессии:
$env:NOTION_TAUSIK_TOKEN = 'ntn_xxx'

После установки перезапусти IDE (Claude Code / Cursor / ...), чтобы MCP-subprocess подхватил новый env. С .tausik/.env IDE-restart не нужен — токен читается на каждом brain-вызове.

5. Запустить wizard

Один комплект из 4 баз на workspace, общий для всех проектов. Приватность по проектам обеспечивает колонка Source Project Hash в каждой строке, а НЕ создание отдельных копий 4 баз для каждого проекта. Wizard это требование защищает (см. "Частые ошибки" ниже).

Первый проект — создаём 4 базы:

bash
.tausik/tausik brain init

Non-interactive (для CI / скриптов):

bash
.tausik/tausik brain init \
  --parent-page-id 'abc123...' \
  --token-env NOTION_TAUSIK_TOKEN \
  --project-name my-project \
  --yes --non-interactive

Parent page ID — 32-символьный hex после notion.so/...- в URL (с дефисами или без). Wizard:

  1. Pre-flight workspace search (v1.3.3+): ищет канонически-озаглавленные BRAIN-базы (Brain · Decisions / Patterns / Gotchas / Web Cache), уже расшаренные с интеграцией. Если все 4 найдены — отказывается создавать дубли и направляет к --join-existing.
  2. Четыре раза вызывает POST /v1/databases для decisions, web_cache, patterns, gotchas со схемами из brain-db-schema.md.
  3. Атомарно пишет .tausik/config.json с brain.enabled=true, 4 database_ids, notion_integration_token_env, именем проекта (для scrubbing blocklist).
  4. Никогда не сохраняет сам токен в config.json — только имя env-переменной. Сам токен живёт в .tausik/.env (рекомендуется) или в shell-environment.

Повторный запуск в уже настроенном проекте упадёт с ошибкой; для перезаписи — --force.

Второй / третий / N-ный проект — присоединяемся к существующим базам:

bash
.tausik/tausik brain init --join-existing

Wizard ищет в Notion-workspace канонические 4 BRAIN-базы (auto-discovery через POST /v1/search) и пишет их ID в .tausik/config.json этого проекта. Новые базы не создаются. Все проекты, указывающие на одни и те же 4 ID, делят один knowledge store; колонка Source Project Hash сохраняет различимость по проектам.

Auto-discovery — два прохода (v1.4-polish):

  1. Title-match. Базы с точным названием Brain · Decisions / Web Cache / Patterns / Gotchas (как создаёт wizard) подключаются по имени.
  2. Schema-fallback. Для категорий, не сматченных по title, wizard инспектирует properties каждой оставшейся видимой базы. База, у которой properties содержат required-набор для категории (например, decisions требует Name, Decision, Rationale, Source Project Hash), подключается независимо от title. Перехватывает базы, переименованные в Notion (UI rename, emoji-префикс, перевод) и базы, созданные вне wizard'а.

Когда auto-discovery возвращает 0 совпадений, но интеграция видит другие базы, ошибка перечислит этих кандидатов — можно либо переименовать их канонически, либо передать ID явно. Когда интеграция не видит ничего, ошибка укажет на share-with-integration шаг.

Если auto-discovery не находит базы (например, интеграция не приглашена на parent page), передай ID явно:

bash
.tausik/tausik brain init --join-existing \
  --decisions-id  '...' \
  --web-cache-id  '...' \
  --patterns-id   '...' \
  --gotchas-id    '...' \
  --token-env NOTION_TAUSIK_TOKEN \
  --non-interactive --yes

Аварийный выход — --force-create. Если действительно нужен новый отдельный комплект из 4 баз (другой Notion-account, осознанно изолированное знание), передай --force-create. Wizard пропустит pre-flight проверку и создаст новые. Используй с осторожностью — проекты, указывающие на старый комплект, не будут видеть записи нового, и наоборот.

Частые ошибки

  • Запустить обычный brain init во втором проекте, использующем тот же workspace → создаст параллельный набор из 4 BRAIN-баз. Знание тихо разделится надвое; одни проекты увидят одну половину, другие — другую. v1.3.3 pre-flight check отказывается это делать по умолчанию — не обходи через --force-create, если только не нужны действительно два независимых "мозга".
  • "Отдельные копии для приватности" → не нужно. Используй колонку Source Project Hash (она уже есть на каждой строке) для фильтрации по проектам; 4 базы делятся между проектами.
  • Ручная правка database_ids в config.json → используй --join-existing --decisions-id ..., чтобы wizard верифицировал каждый ID через Notion перед сохранением.

6. Smoke-тест

python
from brain_config import load_brain, validate_brain, get_brain_mirror_path
from brain_notion_client import NotionClient
from brain_sync import open_brain_db, sync_all
import os

brain = load_brain()
errors = validate_brain()
assert not errors, errors

client = NotionClient(os.environ["NOTION_TAUSIK_TOKEN"])
conn = open_brain_db(get_brain_mirror_path())
result = sync_all(client, conn, brain["database_ids"])
print(result)

get_brain_mirror_path() принимает три формы входа: None (читает load_config() сам), top-level dict {"brain": {...}}, либо уже merged brain dict {"enabled": ..., "local_mirror_path": ...} (то что возвращает load_brain()). Все три разрешаются в один абсолютный путь.

Ожидание: 4 ключа (decisions/web_cache/patterns/gotchas), каждый — {fetched: N, upserted: N, last_edited_time: ...} или {error: ...}. На свежем пустом setup все четыре — {fetched: 0, upserted: 0, last_edited_time: null}.

Метрики (v1.4)

Чтобы ответить на главный вопрос «реально ли brain помогает?», v1.4 пишет каждую brain-операцию в проектную таблицу brain_events (живёт в .tausik/tausik.db, не в зеркале Notion — это сохраняет dispersion firewall между проектами). tausik metrics показывает блок Shared Brain, как только в таблице появляются события:

--- Shared Brain (v1.4) ---
Session: 6 searches, 4 hits, 2 writes, 0 ignored (hit rate: 66.7%)
All-time: 142 searches, 87 hits, 18 writes (hit rate: 61.3%)

Счётчики:

  • searches — каждый вызов brain_search / search_with_fallback.
  • hits — запросы, вернувшие ≥1 результат (прокси для «brain ответил на вопрос?»).
  • writes — успешные try_brain_write_decision / try_brain_write_web_cache (Notion подтвердил). Падения не считаются.
  • ignored — записи tausik_memory_quick brain.ignored:<id>, когда агент пометил подсказку как нерелевантную (в следующей сессии её не покажут снова).

hit_rate_pct = hits / searches * 100. Если в сессии стабильно <20% — значит либо (а) brain пустой/устаревший и нужен tausik brain sync + новые записи, либо (б) запросы слишком project-specific (classifier должен отправлять их в локальную память, не в brain). По метрикам эти две ситуации не различить — читайте последние строки brain_events напрямую.

Телеметрия никогда не блокирует операцию: если INSERT в brain_events упал (заблокированная БД, права), search/write всё равно проходит, а строка просто теряется.

Приватность

  1. Plaintext-имя проекта никогда не уходит с машины. Единственный per-project идентификатор в brain — SHA256(canonical_name)[:16]. Canonical name берётся из project_names[0] локального .tausik/config.json и сам никуда не отсылается.
  2. Scrubbing linter (задача brain-scrubbing, в планах) будет перехватывать каждую запись до клиента. Отклоняет: абсолютные Windows/POSIX пути, internal-domain URLs, любой текст, совпавший с regex-списком brain.private_url_patterns, kebab-слаги похожие на internal-идентификаторы.
  3. Classifier (задача brain-classifier, в планах) выбирает local vs brain по записи. Только brain-класс пушится. Консервативный default: неоднозначное → local.
  4. Можно отозвать в любой момент. Отозвать integration в Notion или убрать NOTION_TAUSIK_TOKEN; следующий sync/write падает с NotionAuthError, а локальное зеркало продолжает работать для read-only поиска.

Edge cases / failure modes

СценарийЧто происходитЧто делать
Отозвали integration tokenСледующий API-вызов бросает NotionAuthError (401/403) без retryВосстановить токен; данные не теряются — local mirror цел
Rate-limit 429Клиент ретраит с учётом Retry-After; исчерпано → NotionRateLimitErrorОбычно автоматом. Если упорно: снизить частоту sync
Offline / DNS failURLError ретраится backoff-ом; исчерпано → NotionErrorbrain_search.search_local() работает по локальному зеркалу
Content >180 KBВ property [see page body]; полный текст в child blocksДержи заметки компактными; большие web-страницы труncate-ятся
Чувствительные данные проскочили scrubbingУдалить Notion page руками; следующий pull заметит 404Улучшить private_url_patterns regex
Schema drift базОтсутствующие properties читаются как NULL; лишние игнорируютсяДобавить недостающие properties (шаг 2)
Два проекта с одинаковым canonical nameКоллизия хэшей — записи мешаются в Notion viewsПереименовать один в project_names[]

Плюсы / минусы

ПлюсыМинусы
Пиши один раз — ищи по всем проектамНужен Notion-аккаунт + setup
Notion UI для просмотра/правкиRate limits (3 req/s) на bulk writes
bm25 local search работает offlineНадо управлять integration-токеном
Ноль внешних Python-зависимостей (stdlib urllib)Нужно активно фильтровать что "обобщаемое"
Privacy-preserving hash, ноль plaintext имёнScrubbing-линтер фильтрует утечки (scripts/brain_scrubbing.py)
FTS5 поддерживает кириллицу / диакритикуНет shared-team режима (single-user в v1)

Что входит в v1.4

Полный brain-стек ушёл в v1.4 — read И write пути, MCP-инструменты с обеих сторон, hook-driven захват WebFetch, classifier + scrubbing, init-wizard, offline fallback, search-proactive хук. Модули: brain_mcp_read.py, brain_mcp_write.py, brain_classifier.py, brain_scrubbing.py, brain_search.py (bm25 ранжирование со stack boost), brain_init.py (init wizard), brain_project_registry.py, brain_fallback.py, brain_universality.py + brain_universality_semantic.py (эвристики кросс-проектной универсализации). Типизированная иерархия ошибок: NotionAuthError, NotionNotFoundError, NotionRateLimitError, NotionServerError. Ручные one-time шаги (brain-notion-space, brain-integration-token) задокументированы в выводе tausik brain init.