TaskForge, Obsidian, Syncthing и ИИ-ассистенты

В прошлых статьях я переносил домой музыку и фотографии. Эта статья про другое: сделан свой трекер задач и пустил туда работать ИИ. Задачи живут в обычных Markdown-файлах, по одному файлу на задачу. Синхронизируются они между телефоном, ноутбуком и Linux-боксом. Читают и пишут их Android-приложение TaskForge, Obsidian, CLI, MCP-серверы и два вида ИИ-ассистентов: «Admin» (Grok Bot) на боксе и проектные сессии Claude на ноутбуке. Ниже рассказываю, как это устроено, какие правила пришлось ввести и где я наступил на грабли.

С чего всё началось

Всё началось с Google Таблиц. У каждого проекта была своя таблица-трекер: строки задач, вкладка с решениями, вкладка с вопросами. Рядом в репозиториях лежали PLAN.md, PROGRESS.md, DECISIONS.md и QUESTIONS.md. Пока агент был единственным, кто их вёл, это кое-как работало.

Потом работу проектов стали делать ИИ. Claude гонял замеры и писал код, Grok Bot следил за процессами и собирал отчёты. Обоим нужно было где-то записывать, что сделано, что решено и что ждёт меня. Результаты начали расползаться: часть оставалась в чате, часть в PROGRESS.md, часть в таблице, а часть только в контексте сессии, которая потом закрывалась и забывала всё. Я поймал себя на том, что по утрам выясняю у одного ИИ, о чём вчера договорился с другим, а склероз которым тотально страдают нейронки вообще приводил к непрерывным открытиям, что в плане двухнедельной давности половина не сделана.

Мне был нужен трекер, который одинаково удобен трём участникам. Мне на телефоне, причём с телефона я в основном и управляю. ИИ через нормальный программный интерфейс, а не через скриншоты веб-формы. И ему самому, чтобы трекер пережил любой из своих клиентов. Обычные Markdown-файлы под это подходят. TaskForge оказался приложением, которое умеет работать с такими файлами на телефоне и при этом даёт CLI и MCP-сервер для ИИ.

Трекер, в который пишут несколько ИИ, — это добровольное назначение себя администратором распределённой системы. Синхронизация файлов между тремя устройствами, на которых одновременно что-то правят, поломается обязательно. Поэтому половина статьи не про «как поставить приложение», а про правила, валидацию и сторожей, без которых всё это разваливается за пару дней.

Чего мы хотим

Мне не нужна Jira и не нужна командная работа в привычном смысле: команда здесь — это я и несколько ИИ. Нужен личный трекер, где ИИ ведут проекты, а решения остаются за мной. Отсюда цели:

  1. Одна задача — один файл. Формат TaskNotes: Markdown с YAML-шапкой, название задачи = имя файла. Никакой базы данных, никакого облака. Файлы читаются глазами, grep’ом и Obsidian’ом и переживут любое приложение.
  2. Телефон как главный пульт. Android-приложение TaskForge: посмотреть, поменять статус, ответить на вопрос, принять решение. Компьютер для этого не нужен.
  3. ИИ работают через API, а не руками. Каждый ассистент пишет в трекер только через MCP-сервер или CLI. Самодеятельности в YAML нет: формат знает инструмент, а не память модели. Тут нужно отметить, что я взял TaskForge CLI+MCP но у obsidian и TaskNotes есть свои, разницы для меня по сути нет.
  4. Трекер — единственный источник правды. Результаты замеров, решения, вопросы, логи и документы лежат в трекере или привязаны к задаче. Потому нередко можно просто отправить агента в трекер и он найдет немало новых задач, о которых забыл.
  5. Задача может разбудить ассистента. Ставлю задаче тег и время — в это время ИИ просыпается и выполняет то, что написано в её теле. Будильник, отложенная проверка или регулярная рутина задаются без отдельного планировщика.
  6. Защита от дурака, в том числе от умного дурака. Правила, которые нельзя забыть: валидация на каждой записи, ночные проверки, удаление только через карантин. ИИ иногда очень уверенно делает глупости, поэтому система должна это ловить, а не надеяться на внимательность.
  7. Выживание после ребута. Бокс перезагрузился (это у Grok Bot) — синхронизация, циклы и сторожа поднялись сами, а я узнал об этом одной строкой.

Архитектура

Вся установка выросла из одной мысли:

Трекер — это папка с Markdown-файлами. Всё остальное — клиенты, которые по-разному в эту папку пишут, плюс Syncthing, который пытается договориться о том, какая версия файла правильная.

        ТЕЛЕФОН (Android)                     НОУТБУК
   TaskForge-app + Obsidian           Claude Code: сессии mon-g0, tq-g1, ...
   один vault, 5 папок проектов       taskforge CLI/MCP (обёртка bwrap)
            │                          interconnect (почта ассистентов, tmux)
            │                                   │
            └────────── Syncthing ──────────────┤
                (send-receive, .stversions)      │
                            │                    │
   ═════════════════ Linux-бокс (всегда онлайн) ══════════════════
   /workspace/taskforge-vaults/{admin,turboquant,monitor,liberec,proxy}
      └─ Projects/<Name>/  (реальная папка Syncthing: задачи, Archive/, attachments/)
            ▲
            │ stdio
   taskforge-mcp-proxy (--validate, 8 правил)  ──►  taskforge mcp --stdio
            ▲
   Admin (Grok Bot)  ◄──  tt-loop (раз в минуту: теги agent, напоминания, precheck)
            ▲             selftest 23:50 · validate_vault 03:17 · сторож Syncthing
            └── рутина раз в 10 минут: письма Claude + сработавшие задачи

На схеме важны две вещи. Во-первых, у файлов нет главного: телефон, ноутбук и бокс равноправны, и Syncthing по очереди тащит изменения от каждого. Это удобно, пока все правят разное, и превращается в отдельный жанр, когда двое правят одно и то же (см. «Грабли»). Во-вторых, ИИ пишут в трекер только через инструменты. Admin на боксе работает через MCP, обёрнутый в валидирующий прокси. Claude на ноутбуке работает через свой CLI/MCP. Ни один ИИ не сочиняет YAML руками.

Компонент Где живёт Роль
TaskForge (Android) телефон Главный пульт: смотреть, менять статусы, ставить напоминания, принимать решения
Obsidian телефон, ноутбук Читать и связывать задачи как заметки, смотреть граф ссылок
taskforge CLI / taskforge mcp --stdio бокс, ноутбук Программный доступ к задачам: запросы, создание, правка полей, закрытие
taskforge-mcp-proxy бокс Прослойка между ИИ и MCP: подставляет пространство и проверяет каждую запись по 8 правилам
Syncthing телефон, ноутбук, бокс Синхронизация 5 папок проектов и общих настроек TaskForge
tt-loop + selftest бокс Будит ассистента по задачам с тегом agent, ночью проверяет сам себя
Admin (Grok Bot) бокс Ведёт трекер, управляет сессиями Claude, следит за синхронизацией
Сессии Claude ноутбук (tmux) Делают проектную работу по группам задач и пишут результаты в трекер
interconnect ноутбук Файловая почта между ассистентами и управление tmux-сессиями Claude

Проектов пять, и у каждого свой vault, свой MCP-сервер и своя папка Syncthing:

Свой MCP потому, что мне нужно было внутри одного Obsidian vault на телефоне расшарить на другие устройства подпапки через syncthing и каждому проекту назначить свою папку на боксе (grok bot и ноутбук с Claude), а taskforge MCP такое не может сам по себе, так что пришлось обойти.

  • admin — задачи самого Admin по управлению проектами: запуск сессий, сверки, рутины, правила;
  • turboquant — эксперименты с квантованием KV-кэша для локальных LLM (замеры, порт, сборки);
  • monitor — проект сервиса мониторинга;
  • liberec — бытовой личный проект, его ведёт отдельный ассистент;
  • proxy — подпроект прокси памяти для Claude Code.

По данным ночной проверки сейчас в них чуть больше двух тысяч задач вместе с архивом. Тысяча с лишним приходится на один Monitor, и это хорошо показывает, сколько мелких шагов набирается, когда каждый шаг ИИ становится задачей. При этом ИИ забывает обычно 95% на долгом проекте.

Шаг 0. Формат: одна задача — один файл

TaskNotes — это простой формат. Задача = файл .md, метаданные в YAML-шапке, тело — свободный Markdown. Название задачи хранится в имени файла, ключа title нет. Вот как выглядит типичная задача:

---
status: open
priority: normal
due: 2026-10-10
scheduled: 2026-10-09
dateCreated: 2026-10-08T20:44:57.215+02:00
tags:
  - task
contexts:
  - pc
projects:
  - "[[TurboQuant]]"
timeEstimate: 15
onCompletion: archive
taskSourceType: taskNotes
dateModified: 2026-10-08T20:44:57.215+02:00
id: muzvyzun
---

Короткое описание, что сделать, и критерий готовности.

Материалы: [[attachments/Название отчёта]]

Несколько деталей, о которых стоит знать заранее:

  • Файл считается задачей, только если в tags есть task. Без этого тега файл — просто заметка.
  • id — это base36 от времени создания. Он не меняется никогда, даже при переименовании, и машинные ссылки (depends_on) идут по нему.
  • projects со ссылкой на другую задачу означает «подзадача». blockedBy — это список зависимостей «нельзя начать, пока не закончено то».
  • Закрытая задача с onCompletion: archive переезжает в Archive/. Переносит её TaskForge на телефоне или инструмент, но никогда не ИИ руками.
  • Из имени файла вырезаются / \ : * ? " < > | # [ ] ^, а кириллица и пробелы остаются. Заголовок «Решение: да/нет?» превратится в имя файла, по которому потом не найдёшь ни одну вики-ссылку.

Структура vault’а одинаковая у всех пяти проектов:

Тут нужно понимать, что это структура на компе Grok Bot в облаке, на моем телефоне где работает TaskForge это один vault, а это сделано как раз потому, что taskforge cli не поддерживает указание отдельных пространств (термин TaskForge) с задачами по разным папкам. Мне нужно было что бы агенты копаясь в своих задачах чужие не трогали.

/workspace/taskforge-vaults/<проект>/
├── Projects/<Name>/          ← реальная папка Syncthing
│   ├── *.md                  ← активные задачи
│   ├── Archive/              ← закрытые
│   └── attachments/          ← документы: docs/, history/, research/, runs/<run-id>/
├── TaskNotes/Archive  →  symlink в Projects/<Name>/Archive
└── TaskForge/Settings →  symlink на общие настройки (dialect.json, spaces.json)

Папка проекта должна быть настоящей, а не симлинком: TaskForge CLI не индексирует задачи, до которых добирается только через симлинк. На ноутбуке у Claude по той же причине стоит маленькая обёртка taskforge-project. Она через bwrap монтирует реальную папку Syncthing внутрь vault-обёртки в приватном пространстве имён и подкладывает свою копию dialect.json, где папка новых задач указывает в проект, а не в несинхронизируемый TaskNotes/Tasks:

# taskforge-project <turboquant|monitor|proxy> <аргументы taskforge>
exec bwrap --bind / / --dev-bind /dev /dev \
  --bind "$R" "$V/Projects/$N" \
  --ro-bind "$O" "$(readlink -f "$DL")" \
  --die-with-parent "$HOME/.local/bin/taskforge" "$@"

Без sudo, ничего не перемещается, общий файл настроек телефона не меняется. Но это просто “как агент придумал”, я не критиковал его, работает и ладно.

Ещё одно правило, которое я ввёл не сразу: всё содержимое трекера пишется по-русски. Это касается названий, тел, логов и решений, кто бы их ни писал. Между собой ассистенты переписываются по-английски, но всё, что читаю я, должно быть по-русски. В трекере я читаю всё, поэтому он русский. Но то, что агенты обязаны говорить между собой ао английски экономит токены.

Шаг 1. MCP: ИИ пишет только через инструмент

Главное правило установки звучит так: формат задач знает инструмент, а не ИИ. Модель уверенно напишет YAML «по аналогии», перепутает in_progress с in-progress. Каждая такая мелочь ломает приложение на телефоне. Поэтому любые правки задач идут только через MCP-сервер проекта, а если его нет — через CLI. Руками файл не редактирует никто.

На боксе работают пять MCP-серверов, по одному на vault: taskforge-admin, taskforge-turboquant, taskforge-monitor, taskforge-liberec, taskforge-proxy. Все они запускаются одинаково, через прокси:

command: python3
args:    /workspace/agent-tools/taskforge-mcp-proxy/proxy.py \
           --vault /workspace/taskforge-vaults/<имя> --default-space <имя> --validate
env:     TASKFORGE_VAULT=/workspace/taskforge-vaults/<имя>

Важная мелочь: taskforge mcp игнорирует --vault и берёт путь только из переменной окружения TASKFORGE_VAULT. Прокси выставляет её сам и без хранилища не стартует.

Как ИИ работает с задачей:

  1. Перед первой записью в сессии вызывает get_dialect. Это машинное описание настроек vault’а, которое приложение генерирует само: какие статусы есть, как они пишутся в файл, где архив. Например, MCP-токен todo пишется в файл как open, а medium — как normal.
  2. Находит задачи через query_tasks (status:in_progress path:^Projects/Turboquant/ text:"...").
  3. Меняет задачу через update_task, и меняет точечно: статус отдельно (set_status), зависимость отдельно (add_depends_on), лог отдельно (append_note). MCP не переписывает файл целиком, а меняет конкретное поле, сохраняя всё остальное, включая ключи, которых он не знает.
  4. Передаёт в каждую правку if_hash из последнего get_task. Если хэш не совпал, значит, файл успел поменяться, обычно потому, что я в этот момент правил задачу на телефоне. Тогда ИИ перечитывает задачу, пробует ещё раз и, если снова не вышло, останавливается и сообщает мне.

Последний пункт оказался важнее, чем выглядит. Без if_hash ИИ спокойно затирает правку, которую я сделал на телефоне минуту назад.

Шаг 2. Валидирующий прокси: восемь правил, которые нельзя забыть

Правила в инструкциях ИИ работают примерно как правила в офисной вики: все читали, никто не соблюдает. Поэтому через несколько дней правила переехали из текста в код. Между ассистентом и MCP-сервером стоит taskforge-mcp-proxy — stdio-прокси на Python, который перехватывает каждый вызов записи и до сервера проверяет его по правилам из rules.json.

Режимов два. error — вызов не уходит, ИИ получает «Нарушено правило N (имя): … Исправь: …», исправляет и повторяет. fix — прокси исправляет сам и пишет в ответ «прокси исправил: …». Режима warn нет сознательно: предупреждения ИИ читают так же, как я читаю лицензионные соглашения.

  1. Связи обязательны. Задача без связей запрещена: нужна родительская задача, вики-ссылка в теле или зависимость. Исключение — тег root и пометка «корневая задача проекта». Задача, ни с чем не связанная, — это потерянная задача.
  2. Без опасных символов в заголовке. Никаких / \ : * ? " < > | # ^ [ ], иначе ломаются имена файлов и вики-ссылки.
  3. Задача с тегом agent должна иметь время в scheduled и тело не короче 80 символов. Тело — это инструкция, которую ассистент выполнит, когда проснётся, и «сделать» за инструкцию не считается.
  4. У задачи со временем есть напоминание (fix). add_task не умеет писать напоминания, поэтому прокси дописывает их отдельным вызовом после записи.
  5. При закрытии onCompletion: archive (fix). В TurboQuant задача-замер не закроется без заполненных result, measured_at и run_dir.
  6. blocked и deferred требуют причины и связи. Нужна строка Причина: … или Ждёт: … и ссылка на то, чего задача ждёт. Если она ждёт меня, то ссылка ведёт на задачу «Решение Романа — …».
  7. Удаление под замком. Удалять можно только тестовые задачи или задачи с тегом delete-ok, пачками не больше 25.
  8. Только своё пространство. Создавать задачи в чужом проекте или в несинхронизируемой папке нельзя.

Кусочек rules.json, чтобы было понятно, насколько это просто устроено:

"blocked_needs_reason": {
  "enabled": true,
  "mode": "error",
  "statuses": ["blocked", "deferred"],
  "reason_regex": "(?im)^[\\s>*_-]*(Причина|Ждёт|Ждет)[*_]*\\s*:[*_\\s]*\\S",
  "require_blocker": true,
  "cross_space_prop": "blocked_by_ref"
}

Файл перечитывается по mtime, перезапуск не нужен. Если файл битый, остаётся прежний рабочий конфиг, а ошибка уходит в журнал. Если сломалась сама проверка, вызов уходит как есть, чтобы прокси никогда не стал причиной, по которой трекер не работает. Все решения прокси пишутся в validation.log: дата, vault, инструмент, правило, block или fix. К прокси есть тесты на свежей копии Admin-vault’а, боевое хранилище они не трогают.

Прокси ловит только записи через MCP. Телефон, Obsidian и Claude на ноутбуке (у него свой MCP без прокси) пишут мимо него. Поэтому раз в сутки ночью validate_vault.py проходит по файлам всех хранилищ с теми же правилами и присылает Grok Bot отчёт. В первый же прогон он нашёл больше сотни нарушений в старых задачах; их разобрали за день. Сейчас в типичном отчёте несколько строк.

Шаг 3. Syncthing: телефон, ноутбук, бокс

Синхронизацию делает Syncthing. Это шесть папок: пять проектов и общие настройки TaskForge (dialect.json, spaces.json), без которых MCP не понимает, где у проекта папки. Режимы такие:

  • бокс и телефон — send-receive для всех папок;
  • ноутбук — send-receive для проектов, где работает Claude, и receive-only для admin: в задачи Admin сессии Claude не пишут;
  • версии старых файлов складываются в .stversions/.

Бокс — это общая машина, на которой живут ассистенты Grok Bot. Он иногда перезагружается и обновляется, и при этом теряет часть домашней папки. Поэтому всё, что должно пережить ребут, лежит в /workspace, а поднимает это идемпотентный скрипт:

#!/bin/bash
# box-ensure.sh — восстанавливает то, что бокс теряет при сбросе, и перезапускает фоновые службы.
# 1) taskforge CLI: восстановить из копии, если npm-установка пропала
if [ ! -x ~/.local/lib/node_modules/taskforge-md/bin/taskforge.js ]; then
  cp -a /workspace/agent-tools/taskforge-md-copy/. ~/.local/lib/node_modules/taskforge-md/
  echo "restored taskforge-md"
fi
# 2) Syncthing: состояние в /workspace/syncthing-state (--home), ключи зеркалируются в бэкап
/workspace/agent-tools/syncthing/syncthing-ensure
# 3) цикл триггеров задач
bash /workspace/agent-tools/task-trigger/tt-start.sh

Ключи и конфиг Syncthing (key.pem, cert.pem, config.xml) syncthing-ensure зеркалирует в бэкап и возвращает обратно, если каталог состояния пропал. Это правило написано кровью ИИ агентов :)

Сверху работает рутина «Сторож Syncthing и цикла задач». Сначала она запускалась каждый час, сейчас реже, раз в четыре часа: токены не бесплатные. Сторож запускает box-ensure.sh (если в выводе есть restored или started, значит, бокс перезагружался, и я получаю одну строку). Через REST проверяет, что папок ровно столько, сколько должно быть, что все они idle с need=0 и что телефон и ноутбук подключены. Ищет новые *.sync-conflict-* и проверяет, что цикл триггеров жив. Если всё в порядке, сторож молчит. Пишет мне только при настоящей проблеме.

Шаг 4. Задачи, которые будят ассистента

Задача с тегом agent и временем в scheduled — это будильник для ИИ. В её теле лежит инструкция. Когда наступает время, ассистент просыпается и выполняет её.

Работает это так. На боксе крутится один цикл tt-loop.py, который раз в минуту через taskforge CLI опрашивает все хранилища из vaults.txt. Событий три:

kind Когда Что происходит с задачей
scheduled тег agent, scheduled ≤ сейчас, задача не в работе и не закрыта разовая переходит в in_progress, повторяющаяся сдвигается на следующее вхождение (пропущенные склеиваются в одно пробуждение)
reminder наступило напоминание TaskNotes (PT0M, -PT1H, абсолютное время) ничего: статус не меняется
precheck за 90 минут до дедлайна ЛЮБОЙ открытой задачи со временем ничего: ассистент только проверяет, стоит ли на задаче будильник или напоминание, и чинит, если нет

Последний тип события — страховка от меня. Если я поставил задачу «к 15:00», но забыл тег или напоминание, ассистент заметит это за полтора часа, а не после того, как дедлайн прошёл.

Изначально цикл слал вебхуки, и ассистент просыпался мгновенно. Потом от вебхуков отказались (кто то ддосит Grok Bot), и теперь доставка выглядит так:

{
  "delivery": "log",
  "default": "admin",
  "rules": [
    {"vault": "liberec", "recipient": "admin"},
    {"tag": "agent-lberec", "recipient": "admin"}
  ],
  "vault_options": {"liberec": {"reminders_any_tag": true}}
}

Цикл пишет строки [EVENT] в свой журнал, а Admin раз в 10 минут запускает одну рутину «Проверка писем Claude и задач TaskForge». Сначала идёт дешёвая предпроверка: маленький скрипт на боксе смотрит события, а такой же скрипт на ноутбуке смотрит почту. Если ответ NONE, рутина сразу заканчивается и почти не тратит токенов. Если что-то есть, Admin обрабатывает своё, а чужое пересылает адресату: например, события бытового проекта уходят его ассистенту. Остальные боты собственных опросов не держат. Опрашивает один, и платим за один.

Выполнив разовую задачу, ассистент закрывает её. Если работа длинная, он оставляет задачу в in_progress, пишет в тело, что запущено и где лог, и ставит себе новую задачу-будильник «проверить в 06:45». Так у меня в трекере появились задачи вида «Admin — будильник 14.10 06:45, проверка приёмки шага 2».

Ночной самотест. Каждый день в 23:50 selftest.py создаёт в Admin-vault’е задачу admin-selftest-<дата> с тегом agent и временем «через две минуты». Он ждёт, пока цикл её заметит, отправит событие и переведёт задачу в работу, а потом закрывает её. Любой сбой дописывается в selftest-fail.txt. Нет файла — нет проблем; есть файл — Grok Bot узнает. Самотест честно доказывает только то, что цикл жив и события уходят. То, что ассистент проснулся и что-то сделал, проверяют уже по результатам в трекере.

Шаг 5. Сессии Claude: сначала задача, потом код

Проектную работу делает Claude Code на ноутбуке. Одна длинная сессия на весь проект быстро переполняет контекст, начинает забывать начало и дорого стоит. Поэтому работа нарезана на группы задач, и каждая группа получает свою свежую сессию: mon-g0, tq-g1 и так далее. Открывает и закрывает их Admin через interconnect:

# открыть сессию под группу, связав её с задачей-хабом группы
python3 interconnect.py open tq-g5 ~/projects/turboquant --task turboquant:<id-хаба>

# кто чем занят: состояние, время в нём, непрочитанные письма, связанная задача
python3 interconnect.py sessions
python3 interconnect.py watch --idle-min 60     # сторож: печатает только проблемы

# письмо в ящик сессии, затем «толчок» в терминал, если она ждёт ввода
python3 interconnect.py send --from admin --to tq-g5 "Start: hub task <id>, rules in the start letter"
python3 interconnect.py nudge tq-g5

interconnect — это файловые почтовые ящики с flock плюс управление tmux-сессиями. Скрипт сам ничего не решает и ничего не нажимает. Он сообщает состояние (РАБОТАЕТ, ЖДЁТ ВВОДА, ЖДЁТ ПОДТВЕРЖДЕНИЯ, ЛИМИТ, УПАЛА), а решает Grok Bot Admin. Каждые 15 минут сторож запускает watch. Пустой вывод значит, что всё хорошо. «ЖДЁТ ВВОДА + непрочитанные» значит nudge. Меню и подтверждения разбираются по правилам, а всё, что касается удаления или публикации, решаю я.

Правила для сессий родились из конкретных неприятностей, и каждое теперь вписывается в стартовое письмо каждой сессии:

  • Сначала задача, потом реализация. Перед тем как делать шаг, сессия заводит на него задачу в трекере через MCP. Потом делает шаг и записывает результат в эту задачу. Так в трекере остаётся полный путь разработки, а не только итог. Отсюда и тысяча задач в одном проекте.
  • Вопросы только письмом. Сессия, которая молча ждёт ответа в терминале, считается ошибкой. Любой вопрос, решение или блокировку, включая запросы подтверждения от самого Claude Code, сессия отправляет письмом в ящик admin и продолжает другую работу.
  • Результаты перепроверяет тот, кто их получил. Если замер выглядит подозрительно, Admin сам в логи не лезет, а поручает проверку сессии и обсуждает с ней вывод до согласия. Ко мне приходят только вопросы, которые остались неясными, по одному, с вариантами и рекомендацией.
  • Знания попадают в трекер до закрытия. Перед закрытием сессия сдаёт handoff — документ во вложениях проекта: что сделано, что прервано, как продолжить, что предлагается дальше. Каждая новая идея, находка, проблема и новая работа в handoff должна иметь id задачи в трекере. Admin сверяет handoff с трекером построчно, по таблице «пункт → id». Пункт без id возвращается сессии.
  • Закрыть без сверки нельзя технически. close без флага --reconciled откажет, а пока сессия работает, тоже откажет:
$ python3 interconnect.py close cs-test
close: сверка не отмечена (задача: admin:...). Сначала handoff + задачи/хабы через MCP
       + сверка Admin + «сверка ок», затем повторить с --reconciled

Порядок всегда одинаковый: handoff → сверка трекера (задачи, хабы, дубли) → письмо «сверка ок» → close --reconciled → снимок экрана в logs/closed/, путь к нему записывается в задачу. Логи сессий не удаляются никогда.

Мне нравится, как это смотрится с телефона. Я открываю TaskForge и вижу хаб группы, его подзадачи с результатами и handoff со ссылками. Если хочется, через remote control Claude подглядываю в саму сессию. Решения, которые ждут меня, лежат отдельными задачами «Решение пользователя — …», и от них по depends_on зависят задачи, которые без меня не двинутся.

Шаг 6. Правила, без которых всё это не живёт

Часть правил стоит в прокси, а часть — это договорённости, которые записаны в навыках ассистентов и проверяются ночью:

  • Любое удаление — через карантин. Ничего не удаляется напрямую. Сначала объекты переносятся в quarantine/<дата>-<задача>/ с манифестом (путь, размер, sha256). Git-ветки сначала упаковываются в git bundle, бандл проверяется git bundle verify, его sha256 записывается в задачу. Затем проверяется, что ничего нужного не ушло. Окончательное удаление идёт отдельным шагом, только после моего «ок», и записывается в задачу. Это касается даже чисток, которые я сам одобрил.
  • Дубли не удаляются, а отменяются со ссылкой. Дубль получает строку «Дубль: [[основная задача]]» и статус cancelled. История остаётся, ссылки на дубль продолжают работать, а при следующей миграции понятно, откуда что взялось.
  • Заблокированная задача ссылается на то, чего ждёт. «Ждёт: ответа» без ссылки не считается. Если задача ждёт меня, то её блокирует задача-решение, и я вижу полный список ожидающих.
  • Документы переносятся в трекер, а не копируются. Отчёт, лог, план или выгрузку кладут в attachments/ проекта и ссылаются на них из задачи. После проверки sha256 и ссылки оригинал удаляется (тоже через карантин). Документ без задачи значит потерянную задачу. Модели, бинарники, секреты и файлы больше ~50 МБ в трекер не попадают, в задаче записывается только путь к ним.
  • Задачи читаем раньше документов. Чтобы экономить токены, ассистент сначала читает задачи (там лежат свойства и выжимки), идёт по ссылкам на другие задачи и только при нехватке данных открывает вложения. Тяжёлое чтение он поручает исполнителю и просит прислать только выводы.

Грабли

Места, где ИИ потратил время (а пару раз чуть не потерял данные), чтобы вы не потратили.

  1. Syncthing разрешает конфликты молча. Если две стороны поправили один файл, Syncthing оставит под нормальным именем более новую по mtime версию, а старую положит рядом как <задача>.sync-conflict-<ДАТА>-<ВРЕМЯ>-<УСТРОЙСТВО>.md. Уведомлений не.
  2. Бокс потерял ключи Syncthing. Однажды при обновлении (комп облачный Grok Bot) каталог состояния Syncthing на боксе пересоздался.
  3. Телефон завис на 95% из-за длины имени файла. Конфликтная копия задачи с длинным русским названием получила имя в 251 байт.
  4. Ребут воскресил двести закрытых задач. После перезагрузки бокса около двухсот уже закрытых задач во всех пяти проектах вернулись в активные папки как старые копии, а их актуальные закрытые версии остались в Archive/. Syncthing сделит за версиями, боты разобрали все сами.
  5. ИИ сочиняет формат по памяти. До MCP-only ассистент однажды «аккуратно поправил» несколько задач руками, по аналогии с соседними. Приложение на телефоне потом показывало их без статуса.
  6. Новые задачи уезжали в несинхронизируемую папку. По умолчанию TaskForge кладёт новые задачи в TaskNotes/Tasks, а эта папка не синхронизируется. Задачи создавались и исчезали для всех, кроме того, кто их создал. На боксе это лечит прокси (подставляет пространство и запрещает TaskNotes/Tasks правилом 8), на ноутбуке — обёртка с подменой dialect.json. Перенести задачу оттуда на ноутбуке нельзя: move_task падает с EXDEV через bind mount. Поэтому о таких задачах ИИ сообщает, а не чинит их сам.
  7. Сессия Claude молча ждёт. Claude Code любит спросить «Do you want to proceed?» и ждать часами. Сессия при этом выглядит живой, а работа стоит. Отсюда правило «вопросы только письмом», сторож watch и проверка, что nudge действительно нажал Enter (до трёх нажатий, затем «Enter НЕ принят» и разбор по экрану). После сброса лимита Claude сам работу не продолжает, его нужно толкнуть этим занимается Grok Bot.
  8. Знания умирают вместе с сессией. Первые сессии закрывались с хорошим handoff, но половина находок в нём не превратилась в задачи и через день была забыта. Теперь действует гейт: каждый пункт handoff сопоставлен с id в трекере, иначе close --reconciled не выполняется.
  9. Вебхуки оказались лишними. Мгновенное пробуждение по вебхуку выглядело красиво, пока вебхук не начал отвечать HTTP 400 на каждое письмо так как Grok ддосят.

Что в итоге

  • Трекер — это папка с файлами. Пять проектов, одна задача = один Markdown-файл. Читается глазами, Obsidian’ом, grep’ом и переживёт любое приложение. Ни одного облака по дороге.
  • Телефон — главный пульт. Я вижу всё, что делают ИИ: каждый шаг, каждый результат, каждое решение, которое ждёт меня, с зависимостями и ссылками на документы.
  • ИИ работают через инструменты, а не руками. MCP с валидирующим прокси на боксе, CLI/MCP на ноутбуке, восемь правил на каждой записи и ночная проверка всех файлов.
  • Задачи будят ассистента. Тег agent и время превращают задачу в будильник или рутину. Precheck страхует от забытых напоминаний, ночной самотест подтверждает, что цикл жив.
  • Сессии Claude не уносят знания с собой. Задача на каждый шаг до реализации, handoff со сверкой по id, закрытие только после «сверка ок».
  • Ничего не удаляется сразу. Карантин с манифестом, дубли отменяются со ссылкой, конфликты Syncthing разбираются вручную, а не «новее значит правильнее».
  • Всё поднимается после ребута само, а я узнаю об этом одной строкой. Ребут 14.10 правда показал, что «поднялось» и «осталось как было» — разные вещи, и разбор воскресших задач ещё впереди.

Рутину — скрипты, прокси, валидацию, сторожей, разбор конфликтов, сверку handoff, даже большую часть этих правил в виде текста — делали ИИ. Решения «что удаляем, что считаем дублем, когда закрываем сессию, какое правило становится жёстким» оставались за мной. Каждое такое решение лежит в трекере отдельной задачей с датой. Забавно, что половина правил выше появилась как реакция на то, что ИИ сделал что-то очень уверенно и очень не так. Трекер, в котором работают ИИ, в итоге оказался не про задачи, а про то, как сделать ошибку дешёвой и заметной.

P.S. Самым полезным правилом оказалось не самое умное, а самое занудное: «сначала заведи задачу на шаг, потом делай». Сессии пишут тысячу задач, но теперь на вопрос «а почему мы так решили неделю назад» есть ответ в трекере, а не в закрытой сессии.