Система обязательств Милы Админ — как задача попадает в работу, где живёт, какая берётся следующей, чем доказывается закрытие. Использовать в начале и в конце каждой сессии, при любом поручении владельца, обещании человеку и перед любым «сделано».
Installs into .claude/skills of the current project.
Are you the author of Mila Tasks?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/shakhruz-mila-tasks-mila-companion)
---
name: mila-tasks
description: Система обязательств Милы Админ — как задача попадает в работу, где живёт, какая берётся следующей, чем доказывается закрытие. Использовать в начале и в конце каждой сессии, при любом поручении владельца, обещании человеку и перед любым «сделано».
---
# УЛИКА — управление обязательствами Милы
**Когда применять:** всегда, когда кто-то чего-то от нас ждёт, — и в начале и в конце каждой сессии. Если работа не оставила строки здесь, её не было; если строка закрылась без улики, она не закрылась.
Это **формат записи, а не движок**. Он ничего не запускает сам, ночью не работает, в чужие репозитории не коммитит. Работу делаю я, руками, в сессии. Выключить систему можно, удалив один скрипт, — файлы останутся читаемыми глазами.
---
## 1. Три сущности, а не один список
Затор был не в исполнении, а в том, что реплики, ходы, стройки и вопросы владельцу лежали в одном списке. У них разные часы и разные улики — значит, это разные вещи.
| Сущность | Что это | Часы | Чем закрывается |
|---|---|---|---|
| **обязательство** — `ход` (≤2 ч) / `стройка` (сутки–недели) | работа с приёмкой | `due`, если есть | `proof`, исполненный машиной |
| **обещание** — `promise` | «пришлю до вечера», «вернусь через час» | `due` — абсолютное время, **чужие часы** | доставленное сообщение с `message_id` |
| **развилка** — `ask` | ждёт слова, доступа или рук владельца | `deadline` + `default` | строка в `DECISIONS.md` |
**Реплика задачей не становится** — ответила и забыли. Но если в ответе прозвучало обещание, обещание заводится в ту же минуту. Именно здесь теряется больше всего: 63 входящих в сутки, задачей становится 7.
---
## 2. Как задача попадает — по источникам
**Голос владельца.** Расшифровка целиком уезжает в `archive/voice/ГГГГ-ММ-ДД-ЧЧММ.md`. Дальше **одна строка на каждый пункт, дословной цитатой**: 12-минутная надиктовка 31.07 дала пять пунктов, одна карточка на голосовое — заведомая потеря. Непонятное записываем непонятным, осмысляем после записи, не вместо неё.
Сразу за этим — **расписка, до содержательного ответа**:
`взяла: M-126 прайс · M-127 YouTube · M-128 Time Machine`
Это единственный принудитель с внешним свидетелем: не завела — он видит пропуск в ту же минуту. Правило «в ту же минуту» уже существовало и ломалось ровно потому, что свидетеля не было.
**Текст владельца.** Повелительное наклонение или срок → строка в ту же минуту, с якорем `msg:<chat>/<id>`. Якорь обязателен: через неделю «топливо на сайте» будет значить то, что решила я, а не то, что сказал он.
**Группы (28 чатов, отвечаем всем).** По умолчанию — ничего. Строка заводится, только если от нас ждут ответа или действия, либо названы срок, деньги, клиент. Шум не должен порождать карточки.
**Клиент.** Обещание заводится **руками**, не автоматом на каждое входящее: автомат на «спасибо» за неделю набьёт `PROMISES` сорванными обещаниями, которых никто не давал, и счёт репутации обесценится инфляцией. Завели — часы идут, канон ≤1 час даже ночью.
**Директора флота (29% потока).** Эскалация принимается в трёх видах: `--need decision | access | hands`. «Посоветуй» отбивается ответом в чат и задачей не становится. Файловый вход — каталог `./inbox-directors/` **вне git** (десять писателей в файл под git = конфликты слияния как штатный режим), забирается командой `task.py pull`.
**Сама нашла.** `--src self` обязателен и виден в вечерней карточке. Плюс: самонайденное без числа (`--bleed 60/сут`) не может обогнать поручение владельца. Ровно на этом сгорел MilaPM — все пять его закрытых дел были собственной гигиеной.
---
## 3. Где живёт
```
./tasks/ledger.jsonl ← ИСТИНА. append-only, git. Строку нельзя править и удалять
./tasks/OPEN.md ← генерится из леджера. В шапке: «править через ops/task.py»
./tasks/proof/<id>-<ts>.txt ← вывод исполненных улик
./ops/task.py ← шесть команд, ~250 строк, без зависимостей
./inbox-directors/ ← вне git, входящее флота
./NOW.md ← блок между <!-- tasks:begin --> и <!-- tasks:end -->
```
Строка события:
```json
{"ts":"2026-08-03T09:12:31+05:00","ev":"new","id":"M-0142","kind":"build","src":"owner",
"who":"<id хозяина>","anchor":"voice:2026-08-03-0910.md#3","title":"Два контура Милы Ташкент",
"check":"health отдаёт contours=2","verify":"ssh prod 'curl -s localhost:19011/health | jq .contours'",
"due":null,"bleed":null}
```
Событий шесть: `new · take · note · done · drop · promise/keep/broken`. Больше не нужно.
**Почему переживает перезапуск:** каталог не привязан к session-uuid и лежит в git. Задачи терялись в `~/.claude/tasks/<uuid>/` — 39 стёрты молча, 12 остались в мёртвых папках. Теперь `~/.claude/tasks/` — **черновик текущего дня**, ≤5 строк, умирает вместе с сессией, и это нормально. `TaskList` не вызываем никогда: 18–30 тыс. токенов за взгляд против 2 тыс. у `task.py open`.
**Ужим `NOW.md` больше не может ничего съесть.** Блок генерируемый; что не влезло — печатается строкой «скрыто 14, полностью в OPEN.md». Пункт «четыре навыка» исчез бесследно при ужиме 163→80 строк — потому что урезание было невидимым.
**Один реестр, ни дня двух.** `ROADMAP.md` в первый же день получает шапку «архив до 03.08, живая очередь — `tasks/OPEN.md`», `INBOX.md` упраздняется. Три реестра разошлись на 17 задач за трое суток именно от параллельного ведения.
`git commit` — в конце сессии, локально и безусловно. `push` — отдельным асинхронным проходом. Синхронный push в каждой записи превращает сетевой сбой в остановку учёта, а живая реакция на неудобный инструмент одна — вести работу мимо него.
---
## 4. Какая берётся следующей — правило, не интуиция
`task.py next` печатает одну задачу и причину выбора. Правило лексикографическое: первая непустая корзина выигрывает целиком, внутри — по возрасту, старшая первая.
1. **Сорванное или горящее обещание человеку** (`promise`, `due < now+60m`). Всегда первое: это чужие часы, тихие часы на них не действуют.
2. **Кровь и срок:** заполнен `bleed` (измеренная утечка числом) · взяты деньги · `due` сегодня или в прошлом.
3. **Сказал сегодня** (`src=owner`).
4. **Всё остальное**, и **строка старше 10 суток без касания поднимается наверх этой корзины сама**. Ритуал «раз в неделю пересмотреть залежавшееся» не нужен: ритуал, который надо помнить, заменяется сортировкой, которую помнить не надо.
**Три жёстких потолка, их держит скрипт:**
- В работе одновременно ≤3, из них **ровно одна стройка**. Стройка съедает сессию целиком — притворяться иначе значит потерять и стройку, и ходы.
- **Один слот стройки в сутки**, и он берётся до первой улики. Без слота стройки не двигаются вообще: 22 из 42 открытых старше трёх суток.
- Задача в работе без `note` за 24 часа падает обратно в очередь с меткой `stalled` и печатается на старте сессии. Статус, который ничего не значит, хуже отсутствия статуса.
---
## 5. Что считается закрытием
**`task.py done` без `--proof` завершается с кодом 2 и не пишет ничего.** Это запрет, на котором держится всё остальное.
**`check` и `verify` пишутся при заведении, а не при закрытии.** Иначе «сделано» определяет тот, кто делал. `new` без `check` отказывает.
**Улику исполняет скрипт, а не печатаю я.** `done` перезапускает `verify` прямо сейчас, кладёт в `proof/` команду, exit-code, первые строки вывода и время. Напечатать «curl → 1», не запустив curl, больше нельзя — а это был бы главный способ соврать.
Формы улики:
| Форма | Что делает `done` |
|---|---|
| `cmd:` / `probe:` | выполняет, сохраняет вывод и код возврата |
| `url:` | код 200 **и** grep отпечатка из `check` в теле ответа |
| `msg:<chat>/<id>` | ищет файл в `channels/telegram/sent/`, сверяет `chat.id` с адресатом карточки, отвергает при наличии того же текста в `failed/` |
| `git:` | sha в origin **плюс** отдельная проверка на бою |
| `human:` | цитата ответа человека и его `message_id` |
Три правила поверх:
- **Улика должна пересекаться с текстом `check`.** Проверяем не то, что улика существует, а то, что она доказывает обещанное.
- **`git:` ≠ выкачено.** Правка от 14.07 с «deployed» в теме коммита не работала 19 дней.
- **Клиентская задача закрывается только чужой рукой** — `human:` или `msg:`. Свой прогон не доказывает, что клиенту стало хорошо.
**Третий исход обязателен.** Не «прошло / отвалилось», а **«не смогла проверить»** — прод недоступен, токен протух, Мак спал. Такое пишется `unknown` и звучит громко: «проверено 5 из 14, 9 не проверялись». Тишина обязана значить ровно одно.
**`--force`** (принято со слов, машина не проверила) остаётся в строке навсегда и отдельной строкой в вечерней карточке: «закрыто 7, из них 1 без машинной проверки».
**Провал требует улики так же, как успех.** «Упёрлась в API» без лога и кода ответа — бесплатный способ не делать работу.
**`drop` требует `--why` и остаётся в леджере.** Но задачу владельца или клиента дропнуть нельзя — она уходит развилкой за его словом. Тихое списание чужого поручения — то, за что MilaPM потерял доверие.
**В карточке не «закрыто 4», а перечисление сутью.** Число дробится: разбил стройку на пять ходов — цифра выросла вдвое, честности не прибавилось. Перечисление выдаёт себя само.
---
## 6. Обещания — отдельная сущность с часами
Обещание заводится **до отправки сообщения, в котором оно звучит**:
`task.py promise --to <chat> --who "Наталья" --what "прайс" --due "03.08 18:00"`
Закрывается только `task.py keep --msg <chat>/<id>` — доставленным сообщением. «Отправила» ≠ «дошло»: в `failed/` лежит больше тысячи неотправленных.
Сорванное обещание **не удаляется никогда**: остаётся в разделе «сорвано» и обязано прозвучать в вечернем касании раньше, чем человек заметит сам. Это счёт репутации, а не мусор.
**Сторож — пишущий, не блокирующий.** Хук `PostToolUse` на исходящих пишет `message_id` в леджер. Раз в день `task.py scan-sent` перечитывает наши исходящие за сутки и помечает похожее на обязательство («пришлю», «сделаю», «до пятницы», «завтра») — каждое совпадение надо пометить «карточка есть» или «не обещание». Блокировать отправку нельзя: одно ложное срабатывание в 23:40 на живом клиенте — это отказ продакшена, и вслед за ним рубильник, который снесёт всю систему.
И честно: сторож стоит на одном пути отправки из трёх. Значит **гарантии «обещание не растворится» у нас нет** — есть ловушка, которая ловит большую часть. Обещать больше, чем механика держит, опаснее самой дыры: под гарантию перестают смотреть глазами.
---
## 7. Что ждёт владельца
Три разных ожидания — три разных обращения.
**Развилка `ask`.** Команда отказывается работать без `--a`, `--b`, `--default`, `--undo`, `--deadline`. Вопрос без дефолта — это домашняя работа, а не вопрос.
- **Дефолт — самая дешёвая отменяемая ветка, а не «ничего не делаем».** Иначе «первые касания 18 тёплым» по умолчанию превращается в «не пишем никому», и ровно те развилки, что стоят денег, дефолтятся в бездействие.
- **Часы идут от подтверждённой доставки** (`message_id` есть). Не дошло — таймер стоит, строка уходит в «твои руки». Иначе в `DECISIONS.md` появится решение, которого человек не принимал, — это подделка подписи, а не потеря задачи.
- По истечении срока `autodecide` исполняет дефолт и пишет честной формулировкой: «принято Милой по умолчанию, показано 03.08 08:31 msg 41207, ответа не было 48 ч, отменяемо одним словом».
- **Потолок — 3 открытых.** Четвёртый `ask` отказывается со словами «сначала закрой один», и сам отказ пишется в леджер и звучит в карточке: очередь не должна выглядеть здоровой оттого, что вопросы подавлены. У MilaPM она выросла 13→49, и слово «закрыто» встретилось в ней один раз.
**Необратимое** (деньги, публикация наружу, юридическое) дефолта не имеет — становится строкой с **ценой ожидания**, которая печатается каждый раз: «Окно TG Business: ждёт 4 дня · сгорело ~240 контактов из 376 · осталось 136». Цена ожидания — число из команды, а не из головы.
**Твои руки** (`--need access | hands`): карта, ключ, токен, доступ к каналу, Time Machine. Это не вопросы, их нельзя спрашивать по одному. Один хвост в утреннем сообщении, максимум пять строк, у каждой — дни ожидания и цена простоя. Растёт число дней — растёт цена в строке. Это единственное давление, которое вообще возможно.
---
## 8. Ритуалы
**Старт сессии — `task.py open`** (≤60 строк, ~2 тыс. токенов):
1. красной строкой — если вчерашний день не закрыт или за сутки в леджере нет ни одного `done`/`note`;
2. сорванные и горящие обещания;
3. что решено по умолчанию с прошлой сессии;
4. `stalled` — висящие в работе без записи;
5. `next` — пятёрка с причинами;
6. **перепроверка трёх случайных закрытий**: сессия начинается с недоверия к себе.
**Конец сессии — `task.py close-session`:** печатает всё, что в работе без улики, дописывает `CHANGELOG.md` из событий `done`, регенерит `OPEN.md` и блок в `NOW.md`, коммитит. **Печатает, но не блокирует.** Отказ завершать сессию ничего не стоит: сессия просто кончается, не вызвав команду. Работающий принудитель один — вечерняя карточка на глазах владельца: пустая — он спросит.
**Сторож снаружи.** Единственная автоматика первой недели: если за сутки в леджере ноль событий `done` и `note` — красная строка в утреннем сообщении. Система обязана жаловаться на себя вслух, иначе её молчание неотличимо от нормы. Каждый скрипт пишет `last_run`, и `open` первой строкой печатает «scan-sent не отрабатывал 3 дня». Уже проходили: сторож Мака сам был мёртв, алерт кричал 1440 раз в сутки, и его не читал никто.
---
## 9. Что видит владелец
Три касания в сутки, каждое ≤12 строк, строка ≤200 знаков. Тихие часы 22–08 — молчание, кроме утечки наружу, уходящих денег и сорванного обещания клиенту. Красное определяется списком меток, а не моим суждением.
**08:30 — лист дня.** Что беру (одна стройка + три хода) · что горит · один вопрос с дефолтом и сроком · хвост «от тебя, когда будешь у машины».
**14:00 — только если есть красное или готовая улика.** Иначе тишина. Норма — тишина.
**21:30 — касание улик.** Ни одного слова без доказательства: закрытое перечислением с кликабельной уликой · сорванные обещания · что решено по умолчанию · что не пошло и почему · «перепроверено N, отвалилось M, не проверялось K».
**Тело карточки собирается шаблоном из событий.** Свободная фраза допустима только в блоке «мнение», и **цифр в нём быть не может** — сводка уже врала ровно так: вывод разошёлся с исходником.
**Чего владелец не увидит никогда:** карточек «▶️ взяла в работу» (у MilaPM их 157 из 353 — чистый шум), простыней на 1200 знаков и внутренних поломок самой системы. Свою поломку пишу в лог и останавливаюсь.
---
## 10. Чего не делаем
Урок MilaPM: 225 оборотов, 64.9 часа машинного времени, 353 карточки за восемь дней — и один `ROLLED_OUT`. Все пять «подтверждённых» дел оказались его собственной гигиеной, поручения владельца ушли в DROPPED, 61 вопрос остался без ответа. **Он строил себе учёт, пока продукт стоял.** Второй раз этот кредит не выдадут.
Поэтому:
- **Никакого демона.** Ни ночных петель, ни параллельных обортов, ни веток и worktree в чужих боевых репозиториях. Один скрипт, один пишущий хук, один утренний печатающий крон.
- **Не строим учёт вперёд работы.** Пока формат не прожил вручную три дня, кода нет. Скрипт появляется, когда видно, какие три команды из пятнадцати реально нужны, — тогда это 250 строк, а не 400.
- **Не блокируем.** Ни отправку клиенту, ни завершение сессии, ни коммит. Блокирующий хук на боевом пути живёт до первого ложного срабатывания, а потом уносит с собой всю систему одним `mv`.
- **Не автоматизируем захват регэкспами.** Ночной grep по повелительным формам родит призрачные задачи из чужих разговоров, реестр загрязнится тихо и заметим через неделю.
- **Не тянем чужие бэклоги.** 47 строк бэклога мёртвого движка — это его гигиена, а не наша работа. Берём поручения владельца, остальное не наследуем.
- **Не заводим статусов вроде PARKED.** Есть развилка (с ценой и сроком) и `drop` (с причиной). Третьего нет — «отложено навсегда» это 52 карточки, о которых никто не вспомнит.
- **Не делаем ритуалов, о которых надо помнить.** Воскресный пересмотр, месячная архивация, недельные аудиты — заменяются сортировкой и порогом. Первый пропущенный вечер убивает ритуал, порог не пропускается.
- **Не обещаем гарантий шире покрытия.** «Физически не может потеряться» — только там, где это правда.
---
## 11. Первый час — без единой строки кода
1. **Семь развилок из `ROADMAP.md`** (они стоят с 31.07, ответа не было ни на одну) получают по три поля: дефолт — самая дешёвая отменяемая ветка · срок · откат. Уходят владельцу одним сообщением: **три штуки**, остальные ждут. Молчание до срока = исполнен дефолт, строка в `DECISIONS.md`. Это размораживает четверо суток простоя сегодня же.
2. **Один экран «твои руки»** — карта Tribute · прайс Иззатиллы · YouTube · Time Machine · токены ботов-отцов · права в двух группах. У каждой строки дни ожидания и цена простоя. Отправить в утреннем сообщении.
3. **Завести `./tasks/ledger.jsonl`** и перенести туда **десять живых** задач руками, в том же json-формате: `title`, `src`, `check`, `verify`, `due`. Не 53 и не 47 — остальные лежат в архиве и всплывут, если понадобятся. Массовый импорт даст стену диспозиций на первой же сессии, и она превратится в штамп.
4. **`ROADMAP.md` и `INBOX.md` в тот же час получают шапку «архив, живая очередь — tasks/OPEN.md».** Двух реестров не должно быть ни дня.
5. **Четыре красные разобрать отдельно и до системы** (задача с сорванным сроком, оплаченный заказ без исполнителя, инструмент без авторизации, окно интеграции, которое закрывается). Разбирать их внутри миграции нельзя: иначе через неделю не отличить пользу формата от пользы «наконец дошли руки».
6. **Вечером — карточка улик по новому образцу.** Она и есть первый принудитель.
Скрипт `ops/task.py` — завтра, шестью командами: `new · take · note · done · promise/keep · ask`. Первым пишется исполнитель улики: `done` запускает `verify` и сохраняет вывод. Он опирается на замер, а не на теорию.
**Метрика недели, доступная с третьего дня:** сколько закрытий несут улику, исполненную машиной, и сколько развилок закрылось без владельца. Не сдвинулось — система театр, каким бы красивым ни был формат.