Часть 3. Как таск-трекер стал ежедневным AI-воркером. ии-агенты.. ии-агенты. искусственный интеллект.. ии-агенты. искусственный интеллект. матизация.. ии-агенты. искусственный интеллект. матизация. таск-трекер.. ии-агенты. искусственный интеллект. матизация. таск-трекер. ткрытый исходный код.

Коротко

В первых текстах про Personal Task Assistant я писал про базовую идею:

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

С тех пор проект сильно изменился.

Изначально это была доска задач с человеческой и агентской очередью. Сейчас это уже более практичный контур:

  • задачи можно безопасно забирать через атомарный claim;

  • повторный импорт из почты, Telegram или другого источника не создает дубли;

  • агент может работать через MCP, а не через скрейпинг UI;

  • MCP-инструменты проверяются отдельным eval-процессом;

  • для будущих Codex/Claude-сессий появились playbooks в AGENTS.md и .claude/skills/;

  • после явной установки launchd-расписания ежедневный ритуал в 15:00 пишет digest, а при явном включении дает Claude ограниченный набор инструментов, чтобы он сам двигал Codex-задачи до waiting_review.

То есть проект ушел от “вот список задач для AI” к более важному вопросу:

как сделать так, чтобы агент мог приходить в очередь каждый день, брать работу и не ломать операционный контроль человека.

Что было проблемой после первой версии

Первая версия решала маршрутизацию:

  • это должен сделать человек;

  • это может взять агент;

  • это ждет ревью;

  • это заблокировано;

  • это еще не разобрано.

Но когда начинаешь реально жить с такой системой, быстро появляются следующие проблемы.

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

Вторая: нельзя доверять только промпту. Если в промпте написано “не закрывай задачи”, это полезно, но недостаточно. Ограничение должно быть в коде.

Третья: интеграции будут переигрывать одни и те же события. Telegram polling, webhooks, будущие Gmail/Slack/Jira-адаптеры и scheduled jobs почти всегда когда-нибудь повторят один и тот же источник. Значит, ingest должен быть идемпотентным.

Четвертая: если MCP-инструменты плохо описаны, агент начинает ошибаться не потому, что модель плохая, а потому что контракт неочевидный. Это нужно проверять отдельно.

Атомарный claim вместо “возьми первую задачу из списка”

Главное изменение в 0.4.0: появился POST /api/agent/claim.

Агент больше не должен делать так:

  1. прочитать список;

  2. выбрать первую задачу;

  3. надеяться, что никто другой ее не взял.

Теперь он вызывает claim endpoint, а сервер сам выбирает верхнюю Codex-owned задачу в backlog, условно переводит ее в in_progress и возвращает агенту.

Это важно даже для личного проекта. Как только появляются расписания, параллельные агенты или ручные запуски из разных окон, состояние “оба взяли одну задачу” становится реальным багом.

В SQLite это сделано условным UPDATE, в Firestore – транзакцией. Если другой процесс успел забрать задачу раньше, текущий runner просто получает следующую или 404, когда брать нечего.

Идемпотентный ingest через external_id

Вторая практичная доработка – external_id.

У задачи может быть стабильный внешний идентификатор, например:

telegram:<chat_id>:<message_id>:<line>
jira:PROJ-42
gmail:<thread_id>:<message_id>:<n>

Если адаптер отправит тот же batch второй раз, система не создаст копии. В context ingest такие задачи вернутся в duplicates, а прямое создание одной задачи с тем же external_id даст conflict.

Для трекера это скучная, но критичная вещь. Без нее любая автоматизация из почты или чатов быстро превращается в генератор дублей.

MCP: агентский контракт стал нативным

Следующий шаг был в 0.5.0: MCP server.

До этого агент мог пользоваться JSON API напрямую. Это работает, но для Claude Code, Claude Desktop и других MCP-клиентов естественнее дать набор инструментов.

Сейчас MCP server в adapters/task_assistant_mcp.py оборачивает API в девять инструментов:

  • task_assistant_get_queue;

  • task_assistant_queue_summary;

  • task_assistant_claim_task;

  • task_assistant_finish_task;

  • task_assistant_create_task;

  • task_assistant_update_task;

  • task_assistant_list_tasks;

  • task_assistant_ingest_context;

  • task_assistant_due_reminders.

Нормальный цикл стал таким:

get_queue / queue_summary
-> claim_task
-> выполнить работу
-> finish_task
-> waiting_review

Ключевое здесь – последняя строка. Агент не должен по умолчанию закрывать задачу в done. Если он подготовил draft, внес изменения, собрал выводы или нашел блокер, это результат для review. Человек остается владельцем принятия.

Evals: проверяем не модель, а контракт

После MCP появилась новая проблема: как понять, что агент действительно сможет пользоваться этими инструментами?

Для этого в 0.5.1 появился evals/.

Там есть:

  • deterministic eval board из 16 задач;

  • 10 read-only вопросов с однозначными ответами;

  • бесплатная проверка verify_answers.py, которая решает вопросы через MCP без LLM;

  • опциональный LLM harness, который дает Claude только MCP server и смотрит, как он справляется;

  • write-loop check, который прогоняет claim -> in_progress -> finish -> waiting_review.

Это важный сдвиг в мышлении. Я не проверяю абстрактно “умная ли модель”. Я проверяю, достаточно ли понятен и надежен мой tool surface.

Если eval падает, чаще всего проблема не в интеллекте модели, а в том, что:

  • инструмент плохо назван;

  • описание недостаточно конкретное;

  • markdown output неудобен для агента;

  • ошибка не объясняет следующий шаг;

  • API допускает неоднозначное состояние.

Playbooks: опыт разработки стал частью репозитория

Еще одна вещь, которая появилась после нескольких итераций с Codex и Claude, – это AGENTS.md и .claude/skills/.

Это не просто документация для человека. Это операционный контракт для будущих агентов.

Например, если агент собирается:

  • работать с доской как worker;

  • менять daily automation;

  • трогать MCP tools;

  • менять схему БД;

  • shipping/release flow,

он сначала должен открыть соответствующий SKILL.md.

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

Для меня это стало отдельным выводом: если проект должен развивать не один человек, а человек плюс несколько AI-агентов, то repo docs должны быть написаны не только для людей. Они должны быть executable memory для агентов.

Ежедневный ритуал: второй работник приходит на смену

Самое заметное изменение в 0.6.0 – automation/. Расписание не включается само после обновления: его нужно осознанно установить через automation/install.sh.

Там два слоя.

Первый слой всегда deterministic:

daily_ritual.py

Он читает доску, классифицирует задачи и пишет digest:

  • overdue;

  • waiting for review;

  • blocked;

  • unassigned;

  • due soon;

  • agent-ready queue.

Этот слой ничего не меняет в трекере. Он просто каждый день дает картину:

что сейчас требует внимания.

Второй слой opt-in:

work_loop.py

Если включить DAILY_RITUAL_WORK=1 и передать ANTHROPIC_API_KEY, то Claude получает только task_assistant_* MCP tools и worker-инструкции.

Важно, что ограничения здесь не только в prompt:

  • у модели нет shell;

  • нет доступа к repo;

  • нет web;

  • только MCP tools трекера;

  • попытка поставить status=done отклоняется в коде;

  • --max-tasks ограничивает, сколько задач можно claim-нуть за один запуск.

То есть daily worker может прийти, взять несколько Codex-задач, сделать то, что реально можно сделать только через task tools, и вернуть результат в waiting_review. Но он не может сам закрыть работу за человека.

Почему я считаю это правильной границей

Есть соблазн сделать “полного автономного агента”, который сам ходит в shell, браузер, почту, GitHub, Slack и закрывает задачи.

Но для личного операционного трекера мне важнее другая модель:

core tracker = источник правды
MCP tools = ограниченный контракт
daily ritual = расписание и digest
human review = финальное принятие

Такой агент менее эффектен в демо, зато его проще оставить без присмотра.

Он не делает вид, что у него есть доступы, которых нет. Он не закрывает задачу сам. Если ему не хватает данных, он должен оставить блокер или вопрос.

Что изменилось в инженерном качестве

Параллельно с продуктовой логикой проект стал заметно взрослее:

  • SQLite schema теперь идет через Alembic migrations, а не create_all;

  • есть pytest suite;

  • есть Ruff;

  • CI гоняет lint и tests;

  • Local Mode стал безопаснее: loopback-only auto-login;

  • Docker image запускается non-root user;

  • Firestore reads оптимизированы, чтобы не читать done/cancelled backlog при polling;

  • Google Sheets history writes вынесены из request path в background tasks.

Это не самые громкие изменения, но именно они превращают toy project в штуку, которую можно запускать каждый день.

Что я бы сформулировал как принцип после третьей итерации

Первая версия отвечала на вопрос:

какие задачи можно отдать AI?

Текущая версия отвечает на более операционный вопрос:

как дать агенту регулярный, ограниченный и проверяемый способ двигать задачи, не забирая контроль у человека?

Мой текущий ответ:

  • статусы и next-action owner в модели задачи;

  • атомарный claim;

  • waiting_review как стандартный финал агентской работы;

  • идемпотентный ingest;

  • MCP как native tool layer;

  • evals для проверки tool surface;

  • playbooks как память проекта для будущих агентов;

  • deterministic digest отдельно от opt-in agent work loop.

Что дальше

На версии 0.6.0 работа не остановилась. Следующие изменения я опишу отдельно, чтобы не смешивать несколько релизов в одной статье.

Следующие интересные направления:

  • user-built адаптеры для Gmail, Slack, Linear/Jira и более production-ready Telegram pattern;

  • более явное объяснение, почему задача считается agent-ready;

  • отчеты агента как отдельные first-class поля, а не только описание;

  • более удобный hosted setup;

  • шаблоны для разных рабочих ритмов: solo founder, PM, coding-agent workflow.

Исходники: https://github.com/J3d1-fm/Personal-Task-Assistant

Если вы уже используете Codex, Claude Code или других агентов не разово, а как часть рабочего процесса, мне особенно интересно: где у вас сейчас граница между “агент может взять сам” и “человеку нужно принять решение”?

Автор: J3d1fm

Источник