Memory Architecture v2 — Foundation Release

Память по проектам
для Claude Code.

cwd-aware слой памяти, основанный на паттерне Karpathy LLM Wiki. Каждая сессия загружает только то, что относится к текущему проекту. Всё остальное молчит.

~/.claude-memory-compiler/

├── КОРНИ        wiki/_archive/                     ← архивные знания
├── СТВОЛ        ~/CLAUDE.md                        ← всегда загружен
│              Karpathy_Guidelines.md
│              global MEMORY.md
│              wiki/index.md (100 строк)
├── ВЕТКИ        entities/  ideas/  references/      ← по запросу
├── ЛИСТИКИ      wiki/projects/myapp/               ← только активный slug
│                ├── index.md
│                ├── MEMORY.md      (≤30 строк)
│                └── journal/2026-05-01.md
└── HOT-STATE    myapp/AGENT_ACTIVITY.md            ← живые изменения

Где ломается плоский подход

Паттерн Карпати отлично работает для одного проекта. Когда их четыре:

Как это работает

Оригинальный паттерн Карпати
  • Плоский дневной лог — один файл, все проекты
  • SessionStart загружает весь knowledge/index.md
  • Каждая сессия идёт в LLM на flush
  • Единый MEMORY.md для всего контекста
  • Нет изоляции проектов
Ramas-Karpathy-Tree
  • daily/<slug>/<date>.md — по проекту
  • SessionStart загружает ствол + активный листик
  • Pre-filter: тривиальные сессии не идут в LLM ($0)
  • Двухуровневый MEMORY — глобальный + per-project
  • Строгая slug-изоляция через cwd routing
slug_router.py — longest-prefix cwd match
def resolve_slug(cwd: str, config_path: Path) -> str:
    """Вернуть slug для cwd, или '_global' если нет совпадений."""
    config = json.loads(config_path.read_text())
    routes = config.get("routes", [])
    fallback = config.get("fallback_slug", "_global")

    best_slug, best_len = fallback, 0
    for route in routes:
        for prefix in route.get("cwd_prefixes", []):
            if cwd.startswith(prefix) and len(prefix) > best_len:
                best_len = len(prefix)
                best_slug = route["slug"]

    return best_slug
pre_filter.py — детерминированный пропуск без LLM
def should_flush(transcript: str, char_threshold: int = 1000) -> FilterDecision:
    if not transcript.strip():
        return FilterDecision(False, FilterReason.EMPTY)

    if len(transcript) < char_threshold:
        return FilterDecision(False, FilterReason.TOO_SHORT)

    # все строки совпадают с тривиальными bash / no-op паттернами?
    non_trivial = sum(
        1 for line in transcript.splitlines()
        if not any(p.search(line) for p in TRIVIAL_PATTERNS)
    )
    if non_trivial == 0:
        return FilterDecision(False, FilterReason.TRIVIAL_OPS)

    return FilterDecision(True, FilterReason.OK)

Оригинальный паттерн Карпати vs Ramas-Karpathy-Tree

Параметр Karpathy LLM Wiki Ramas-Karpathy-Tree
Дневные логи daily/<date>.md — плоский, все проекты daily/<slug>/<date>.md new
Старт сессии Загружает весь knowledge/index.md Ствол + только листик активного slug new
Изоляция проектов Нет Строгая — slug router исключает утечки new
Pre-filter Нет — каждая сессия стоит денег Детерминированный Python — ~40-60% пропуска new
Модель flush Настраивается Haiku 4.5 — ~$0.005/flush
Структура памяти Один MEMORY.md Глобальный (≤20 строк) + per-project (≤30 строк) new
Покрытие тестами Не указано 18 юнит-тестов, TDD с первого дня
Deep Dive

Как было vs Как стало

Это самая важная часть документа. Без понимания реальной проблемы не ясно, зачем нужен апдейт. Ниже — конкретика: что такое оригинальный паттерн, где он ломается, реальная история поломки, и как именно архитектура дерева её решает.

1. Что такое Karpathy original

Андрей Карпати описал паттерн «LLM Wiki» — три слоя: raw sources → wiki → schema. В Claude Code это выглядит как:

  • SessionEnd хук пишет flush в daily/<date>.mdплоско, все проекты в одном файле
  • ночной cron (compile.py) читает daily, обновляет knowledge/index.md
  • SessionStart хук грузит knowledge/index.md + последний daily в каждую новую сессию

Идея блестящая. Но в наивной реализации:

  • 20+ тыс. токенов на старт каждой сессии — index растёт линейно, грузится весь
  • Контекст всех проектов вперемешку — открыл чат для betaline, видишь обсуждения ebay, fundament21
  • Нет лимита на стоимость — flush гонит Sonnet каждый раз, даже если ты сделал ls && pwd
  • Если flush падает — тишинаdaily/ пустой, ты не знаешь что сломано

2. Реальная картина «до»

Karpathy compiler был поставлен 21 апреля 2026. До 1 мая он молча не работал ни одного дня.

uv не был установлен на системе. Хук пытался спавнить flush.py через uv run, получал FileNotFoundError, тихо логировал ошибку и выходил. daily/ оставался пустым. Казалось — работает в фоне.

Параллельно Jarvis-vault велся руками в Obsidian — отдельная система. Между Karpathy compiler и Jarvis vault не было никакой связи. Двойная база, оба источника рассинхронизированы.

Симптомы:

  • Возвращаешься через 3 часа — пересказываешь Claude задачу с нуля
  • Открываешь чат в betaline/ — модель «помнит» обрывки про ebay из общего контекста
  • Не понимаешь сколько денег уходит на flush
  • Дайджеста за день нет — что было вчера? ищешь в git-истории или Obsidian руками
Warning — если твой daily/ пустой после нескольких дней работы: проверь logs/flush.log. Вероятно, uv недоступен по PATH в хуке. Хуки работают со stripped PATH — наивная установка именно на этом и ломается. Решение: прописывай абсолютный путь к uv через переменную UV_BIN.

3. Что починил апдейт — метафора дерева

Память не куча, а структура с уровнями релевантности. Каждый уровень загружается по-разному.

КОРНИ — глубокий архив
  wiki/_archive/              cold storage, вне активного контекста
  доступ: только через /wiki-query

СТВОЛ — всегда в контексте, ~1500 токенов
  ~/CLAUDE.md                     ~500 токенов
  Karpathy_Guidelines.md          ~300 токенов
  global MEMORY.md (≤ 20 строк)   ~150 токенов
  wiki/index.md (только заголовки) ~400 токенов

ВЕТКИ — по запросу, не на старте
  wiki/entities/   wiki/ideas/   wiki/references/

ЛИСТИКИ — грузится ОДИН по cwd
  wiki/projects/<slug>/
    ├── index.md             ~600 токенов
    ├── MEMORY.md            ~500 токенов
    ├── open-questions.md
    └── journal/<вчера>.md  ~800 токенов

HOT-STATE — в самом репо проекта
  <project>/AGENT_ACTIVITY.md

Когда открываешь Claude Code в ~/Documents/betaline/, только ствол + листик betaline/ грузятся в контекст. ebay/, fundament21/, karpathy-vault/ — невидимы.

4. Поток данных — технически

SessionEnd hook — закрытие сессии
  1. 1. Хук получает cwd из stdin (Claude Code передаёт через JSON)
  2. 2. Извлекает последние ~30 turns транскрипта в markdown-формат
  3. 3. Спавнит детач-процесс flush.py через абсолютный путь ~/.local/bin/uv — потому что хуки работают со stripped PATH
  4. 4. flush.py определяет slug по cwd через projects.json (longest-prefix match)
  5. 5. Pre-filter без LLM — контекст < 1000 символов или только bash-команды → пропуск, $0
  6. 6. Haiku 4.5 (60-секундный timeout) сжимает в структурированную выжимку 200–400 слов: контекст / решения / препятствия / open-вопросы / action items
  7. 7. Append к daily/<slug>/<date>.md
SessionStart hook — старт сессии
  1. 1. Хук читает cwd из stdin
  2. 2. Резолвит slug через projects.json
  3. 3. Собирает: ствол + только листик активного проекта (index, MEMORY, open-questions, последние 3 journal-файла) + сегодняшний/вчерашний daily log + AGENT_ACTIVITY.md
  4. 4. Жёсткий cap 18 000 символов (~5000 токенов) — trunk сначала, потом truncate листика
  5. 5. Возвращает JSON хуку, Claude Code инжектит как additionalContext

5. Конкретные метрики до/после

Параметр Karpathy original Дерево Рамас-Карпати
Токенов в SessionStart 15–25k (всё подряд) 3–5k (только активный листик)
Утечка проектов Все видны всегда Изолированы по cwd
Цена за flush средней сессии $0.05–0.15 (Sonnet, без фильтра) $0.005–0.01 (Haiku, после pre-filter)
Тривиальная сессия (ls + pwd) $0.05+ (всё равно гонит LLM) $0 (pre-filter режет)
Стоимость/мес, 4 проекта × 10 сессий/день $60–150 $15–30 (с Plan B)
Видимость поломок Тишина, daily/ пустой logs/flush.log, статусы FLUSH_OK / FLUSH_ERROR
Память про вчера Угадываешь или ищешь руками Daily log активного slug автоматически в SessionStart
Fault tolerance flush Один failure mode (silent exit) Timeout + sanitize + cleanup + structured logs

6. Сценарии повседневного использования

Сценарий A — вернулся через 3 часа в проект
раньше Открываешь чат в betaline, спрашиваешь «на чём остановились?» — модель не знает, либо рассказывает про ebay из общего контекста. Пересказываешь сам.
сейчас Модель читает daily/betaline/<сегодня>.md + journal/<вчера>.md + open-questions.md — отвечает «вчера остановились на webhook scaling, висят вопросы X, Y». Без пересказа.
Сценарий B — два проекта параллельно
раньше В каждом чате весь контекст обоих проектов смешан, модель путается, иногда даёт совет из чужой архитектуры.
сейчас Физически невозможно — _project_leaf("ebay") не читает wiki/projects/betaline/. Тестом покрыто: test_does_not_leak_other_projects.
Сценарий C — открыл Claude в ~/Downloads
раньше Грузится весь knowledge index, ~20k токенов, контекст забит ничего не значащей информацией.
сейчас slug = _global, грузится только trunk (CLAUDE.md, Karpathy_Guidelines, wiki/index.md headers) — ~1500 токенов. Чисто.
Сценарий D — сделал ls && cat README.md
раньше SessionEnd триггерит flush, Sonnet тратит ~$0.05 чтобы «выжать» «пользователь посмотрел README».
сейчас pre-filter определяет TRIVIAL_OPSreturn False, $0 потрачено, daily log не загрязняется бесполезным.

7. Что ещё впереди — Plan B

Сейчас зафиксирован foundation: стенография в daily/<slug>/. Plan B — ночной compile (Sonnet 4.6) который читает daily и обновляет project leaves (journal/, decisions.md, lessons.md, MEMORY.md), плюс утренний digest.

Foundation работает, но Plan B compile.py ещё не сделан — daily logs пока накапливаются как сырьё. Запустится после 1–2 недель работы foundation в проде: нужно сначала убедиться, что pipeline не падает и логи имеют нужную структуру для компиляции.

Разбивка стоимости

Активный разработчик, 4 проекта, ~3-5 сессий в день.

Session flush — Haiku 4.5 (~100/мес, после pre-filter) ~$0.50
Старт сессии — Sonnet 4.6 (~150/мес) ~$1.50
Plan B: ночная компиляция — Sonnet 4.6 (скоро) ~$3.00
Итого / месяц ~$5–15

Наивный плоский подход при той же нагрузке: $30–80/месяц.

Быстрый старт

Mac, Python 3.12+, uv, Claude Code 1.x. Полное руководство — в README.

1. Клонируем
git clone https://github.com/sergeyramas/ramas-karpathy-tree \
  ~/.claude-memory-compiler
cd ~/.claude-memory-compiler
2. Устанавливаем
uv sync
3. Настраиваем projects.json
cp projects.json.example projects.json
# Редактируем: добавляем маппинг cwd → slug
4. Указываем env vars (добавляем в ~/.zshrc)
export VAULT_DIR="$HOME/Library/Mobile Documents/iCloud~md~obsidian/Documents/YourVault"
export UV_BIN="$HOME/.local/bin/uv"
5. Регистрируем hooks в ~/.claude/settings.json, запускаем тесты
uv run pytest tests/ -v
# 18 passed — всё готово.

Роадмап