C очередью web UI, Telegram-ботом и продолжением диалога
Я собрал инструмент, который решает несколько моих конкретных болей при работе с AI CLI — Claude Code, Codex, Qwen. Не абстрактных, а тех, на которые реально натыкаешься каждый день.
PromptPilot — очередь задач для AI CLI. Отправляешь промпт, воркер его выполняет. Запланировать задачу можно из командной строки, в веб-интерфейсе либо через Telegram-бота. Поддерживает планирование, приоритеты, retry при rate limit и продолжение диалога прямо из бота.

Содержание
Реальные кейсы
Вот конкретные ситуации, под которые писался проект. Возможно, что-то узнаешь:
Кейс 0. Упущенная прибыль и душевные терзания от непотраченных ресурсов
«Токены в конце месяца похожи на снег в апреле: они напоминают о зиме, но уже совершенно бесполезны» — Луций Сенека.
Накупили подписок, но в грандиозные планы вмешалась суровая реальность? Завтра сгорят токены — не буду спать, пока не потрачу их на всё своё TODO.
Теперь можно спать, распланировав пул задач, чтобы максимально потратить свои квоты.
Напишите в комментах: это чисто мой кейс и у меня расстройство AI-поведения, или у вас так же.
Кейс 1. «Разогреть» лимит до начала рабочего дня
Есть статья, где предлагается хак для удвоения лимита Claude: запускать сессию за 3–4 часа до начала кодирования. Это работает, но требует быть за компом в нужный момент (а ведь кто-то кодит сразу, как только проснулся).
У меня другой подход. Я планирую задачу на 5 утра — любой лёгкий промпт вроде "hi" или просьбу сгенерировать документацию:
pp add "Напиши подробную документацию к модулю auth.py" \ --dir C:\Projects\MyApp \ -a "2026-04-01T05:00"
или в UI

Воркер сам стартует сессию в 5:00. В 9:00 я начинаю работать — и использую лимит примерно за час, а в 10 он сбросится и будет свежим.
В Telegram-боте то же самое через кнопки: ➕ Добавить задачу → промпт → директория → выбрать расписание +8ч.

Кейс 2. Лимит кончился поздно вечером — поставить задачу на сброс
Сидишь поздно, Claude говорит, что лимит исчерпан.
Планируем продолжение банкета на время после сброса лимита и идём спать.
pp add "Продолжи рефакторинг, осталось разобрать worker.py" \ --dir C:\Projects\PromptPilot \ -a "2026-03-29T02:20"
Утром задача выполнена, а лимиты свежие.
Кейс 3. Ты не дома, но хочешь подготовить лимит к кодингу
Пришла гениальная идея, чувствуешь, что всю ночь будешь кодить. Отправляешь задачу, чтобы по возвращении максимально эффективно воспользоваться лимитами.
➕ Добавить задачу → "Проведи аудит кода в папке src/, найди потенциальные проблемы" → провайдер: claude → приоритет: 5 → директория: MyProject → расписание: +1ч
Воркер запустит задачу через час — к тому времени, когда ты дойдёшь до компа, лимит уже будет частично использован и скоро обновится. Плюс задача сделана.







Кейс 4. Появились мысли — доработать проект удалённо
Едешь в такси, пришли идеи. Открываешь Telegram-бот, создаёшь задачу прямо с телефона:
"В модуле payments.py добавь валидацию суммы: должна быть > 0 и не превышать 1 000 000. Напиши тесты. Используй существующий стиль в тестах."
Выбираешь проект из списка (если задана PP_PROJECTS_ROOT), провайдера, жмёшь «Отправить». К приезду домой — готовый коммит. Или не готовый — и тогда Claude задаст вопрос, и ты ответишь прямо из бота (об этом дальше).
Кейс 5. Скилы Claude Code через Telegram
У меня есть скил для формирования приглашений на демо — demo-invite.md в .claude/skills/ проекта. Раньше нужно было открывать терминал, помнить синтаксис. Теперь:
В боте: /skills → выбираешь demo-invite → вводишь аргументы → задача создана.



Скилы работают и в Web UI — при выборе Claude-провайдера появляется кнопка ⚡ Skills.

Архитектура
Схема: интерфейсы → SQLite → воркер → CLI
┌─────────────────────────────────────────┐ │ Интерфейсы │ │ CLI (pp add) │ Web UI │ TG Bot │ └────────────────┴──────────┴─────────────┘ │ создают задачи ▼ ┌─────────────────┐ │ SQLite (WAL) │ │ ~/.promptpilot │ └────────┬────────┘ │ читает очередь ▼ ┌─────────────────┐ │ Worker │ ← опрос каждые 5с └────────┬────────┘ │ subprocess ┌──────────┼──────────┐ ▼ ▼ ▼ claude.exe codex qwen
Три независимых процесса через одну SQLite-базу в WAL-режиме:
Worker — опрашивает очередь, запускает задачу через
subprocess, сохраняет результат. Намеренно однопоточный: одна задача в момент времени, никаких гонок за API-лимит.Server — FastAPI + Web UI на чистом JS. Принимает задачи через REST.
Bot — Telegram-бот, полный менеджмент задач через чат.
Все три можно запускать независимо или вместе через tray.
Установка
git clone https://github.com/your/promptpilot cd PromptPilot pip install -e .
Требования: Python 3.10+, хотя бы один AI CLI в PATH.
Создай .env в папке проекта (или рядом с pp.exe):
# Telegram бот (опционально) PP_TG_TOKEN=7123456789:AAF... PP_TG_ALLOWED_PHONES=+79001234567 Для авторизации бота PP_TASK_PASSWORD=12345 Вдруг другие вайбкодеры украдут телефон уже авторизованный # Claude PP_CLAUDE_EXE=C:\Users\username\.local\bin\claude.exe PP_DEFAULT_CLI=claude # Папка с проектами — для выбора директории кнопками в боте/веб PP_PROJECTS_ROOT=C:\Projects # Таймаут и retry PP_TASK_TIMEOUT=300 PP_BASE_DELAY=60 PP_MAX_DELAY=3600
Запуск: CLI, tray и .exe
Вариант 1 — CLI (для разработки и серверов)
# Три процесса в трёх терминалах pp worker # выполняет задачи pp server # веб-интерфейс http://127.0.0.1:8420 pp bot # Telegram-бот # Или воркер + сервер одной командой pp start
Вариант 2 — PowerShell-скрипт
.\start.ps1 # воркер + сервер; если PP_TG_TOKEN задан в .env — бот тоже запустится автоматически .\start.ps1 -Bot # явно запустить бот, даже если PP_TG_TOKEN не в .env (нужен в переменных окружения) .\stop.ps1 # остановить все запущенные сервисы
Вариант 3 — Tray (.exe, рекомендуется на Windows)

Двойной клик на pp.exe — иконка в трее. Воркер и сервер стартуют автоматически. Иконка меняет цвет: 🟢 всё работает / 🟠 частично / ⚫ остановлено.
Чтобы собрать .exe самому:
.\build.ps1 # результат: dist\pp.exe (~40 МБ, Python внутри, зависимостей не нужно)
PyInstaller упаковывает Python, все зависимости и статику в один файл. На целевой машине ничего устанавливать не нужно — только .env рядом с pp.exe.
Нюанс с .env:
load_dotenv()читает файл один раз при запуске. Порядок поиска: папка рядом сpp.exe→ рабочая директория →~/.promptpilot/.env. Переменные окружения системы имеют приоритет над.env.
Интерфейсы: CLI, Web UI, Telegram-бот
CLI
Самый быстрый способ добавить задачу:
# Простая задача pp add "Отрефактори модуль db.py, избавься от дублирования" # С директорией и приоритетом pp add "Напиши тесты для api.py" \ --dir C:\Projects\PromptPilot \ -p 1 # Запланировать на конкретное время pp add "Сгенерируй отчёт за месяц" \ -a "2026-04-01T09:00" # Использовать другой провайдер pp add "Explain this codebase" --provider codex # Пакетная загрузка из файла (каждая строка — задача) pp add --file prompts.txt # Список задач pp list pp list --status pending pp list --status completed --limit 5
Web UI

Минималистичный интерфейс на http://127.0.0.1:8420:
Выбор провайдера → для Claude совместимых автоматически появляется кнопка ⚡ Skills
Промпт (Ctrl+Enter для отправки)
Чекбокс
--dangerously-skip-permissionsПресеты расписания (+1ч / +3ч / +8ч / +24ч) или ручной ввод ISO-даты
Фильтры по статусу с бейджами-счётчиками
Раскрытие задачи — полный результат, метаданные (модель, стоимость, токены)
Автообновление каждые 5 секунд

Весь UI — один HTML-файл, ванильный JS, никаких npm-зависимостей.
Telegram-бот

Авторизация — без паролей в чате. Пользователь жмёт «Поделиться контактом», Telegram передаёт номер, бот сверяет с PP_TG_ALLOWED_PHONES. Авторизованные пользователи сохраняются в JSON — при перезапуске авторизация не слетает.
Опционально: PP_TASK_PASSWORD — пользователь вводит пароль один раз за сессию перед созданием задачи.
Создание задачи в боте — пошаговый сценарий
Промпт → Провайдер [claude | claude-z | codex | qwen | ...] → Приоритет [1..10] → skip-permissions [Да / Нет] → Директория [список из PP_PROJECTS_ROOT + "Ввести вручную"] → Расписание [+1ч / +3ч / +8ч / +24ч / Ввести / Без расписания] ✅ Задача #N добавлена!

Список задач — пагинация по 5, кнопки перехода, клик на задачу — детали.
Пример списка задач

Пример экрана деталей задачи в боте
📋 Задача #42 Статус: ✅ completed Провайдер: claude Модель: claude-opus-4 Промпт: Добавь валидацию суммы в payments.py... Результат: Добавил проверку в строке 47: if amount <= 0 or amount > 1_000_000... Model: claude-opus-4 Cost: $0.0063 Time: 18.4s Tokens: 312 in / 891 out Rate limit resets: 2026-03-29 02:17 [❌ Отменить] [💬 Ответить] [🗑 Удалить]

Пример экрана со статистикой и списком провайдеров

Rate limits и exponential backoff
Воркер определяет rate limit по stderr или по событиям stream-json:
RATE_LIMIT_PATTERNS = [ "rate limit", "rate_limit", "ratelimit", "overloaded", "too many requests", "429", "quota exceeded", "capacity", "try again later", ]
При срабатывании задача переходит в rate_limited и уходит в exponential backoff:
def compute_next_run(retry_count: int) -> datetime: delay = min(BASE_DELAY * (2 ** retry_count), MAX_DELAY) jitter = delay * 0.1 * (random.random() * 2 - 1) return datetime.now(timezone.utc) + timedelta(seconds=delay + jitter)
Задержки: 60с → 120с → 240с → 480с → … → 3600с. Джиттер ±10% — чтобы не молотить синхронно, если несколько задач rate-limited одновременно. После max_retries попыток — failed.
Воркер при запуске вызывает db.recover_running() — все задачи со статусом running (зависшие при прошлом краше) откатываются в pending. Crash recovery из коробки.
Продолжение диалога — reply в боте
Claude Code может задать вопрос в середине задачи:
«Нашёл два файла:
auth.pyиauth_v2.py. Какой актуальный?»
Задача завершается — Claude ждёт ответа. Но терминала нет, сессия закрыта.
Теперь в деталях завершённой задачи есть кнопка 💬 Ответить:

Нажимаешь → вводишь «auth.py, auth_v2.py — устаревший черновик» → новая задача создаётся с флагом --resume <session_id>. Claude продолжает разговор в том же контексте, помнит всё, что было.

Как это работает под капотом
Claude CLI возвращает
session_idв stream-json-выводе (событиеresult)Worker сохраняет его в колонку
tasks.session_idКнопка 💬 появляется у завершённых задач с
session_idОтвет создаёт задачу с
session_idиparent_task_idот родительскойWorker добавляет
--resume session_idв команду
# config.py — build_cmd extras = [] if session_id: extras += ["--resume", session_id] if skip_permissions: extras.append("--dangerously-skip-permissions") if extras: prompt_idx = cmd.index(prompt) cmd[prompt_idx:prompt_idx] = extras
Цепочка не ограничена — каждый ответ тоже сохраняет session_id и показывает 💬. Новая задача наследует провайдера, рабочую директорию и флаги от родительской.
[СКРИНШОТ: цепочка задач — #1 → #2 (ответ) → #3 (ответ на ответ)]
Скилы Claude Code
Скилы — это файлы .md в ~/.claude/commands/ или ~/.claude/skills/, в плагинах (~/.claude/plugins//commands/), а также в локальных папках проекта (.claude/commands/ или .claude/skills/). Claude Code вызывает их через /skill-name [args].
PromptPilot умеет читать эти файлы, показывать список и подставлять /skill-name в промпт.
Web UI: при выборе Claude-провайдера появляется кнопка ⚡ Skills. Клик → список с описаниями. Выбор скила подставляет /skill-name в поле промпта — дополняешь аргументами и отправляешь.
Telegram-бот: команда /skills или кнопка в меню:
/skills ⚡ Скилы (claude) [commit] Create a git commit [review-pr] Review a pull request [demo-invite] Формирует приглашение на демо для клиента [feature-dev] Guided feature development → [demo-invite] Введите аргументы: ООО Ромашка, среда 14:00 ✅ Задача #47 добавлена!

Скилы из рабочей директории проекта (workdir/.claude/commands/ или workdir/.claude/skills/) добавляются к глобальным — то есть у каждого проекта могут быть свои скилы, и они будут видны в боте при выборе этой директории.
При нажатии на кнопку "Скилы проекта" отображаются только те проекты, у которых есть скилы

Работает только с провайдерами claude и claude-z — для Codex и Qwen скилы не отображаются.
Провайдеры и кастомные команды
Встроенные:
Имя | Описание | Скилы |
|---|---|---|
| Claude Code (Anthropic) | ✅ |
| Claude Code через GLM/z.ai | ✅ |
| OpenAI Codex ( | — |
| Qwen Code ( | — |
Кастомный провайдер:
pp provider add myai \ --cmd "myai run {prompt}" \ --desc "My AI Tool" \ --env "MYAI_API_KEY=sk-..."
Провайдер — шаблон команды с {prompt}. Воркер подставляет промпт, добавляет флаги и запускает через subprocess.run с нужными переменными окружения.
Пример: кастомный claude-z через GLM (PowerShell)
pp provider add claude-z ` --cmd "C:\Users\<username>\.local\bin\claude.exe -p --verbose --output-format stream-json {prompt}" ` --desc "Claude Code (GLM via z.ai)" ` --env "ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic" ` --env "ANTHROPIC_AUTH_TOKEN=your-token-here" ` --env "ANTHROPIC_DEFAULT_SONNET_MODEL=glm-4.7" ` --env "ANTHROPIC_DEFAULT_OPUS_MODEL=glm-4.7"
Нюанс для Windows: если claude настроен как PowerShell-функция или алиас,
subprocessего не найдёт — нужен полный путь кclaude.exe.
Конфигурация
Таблица переменных окружения
Переменная | По умолчанию | Описание |
|---|---|---|
| — | Токен Telegram бота |
| — | Разрешённые номера через запятую |
| — | Пароль для создания задач в боте |
|
| Путь к claude |
|
| Провайдер по умолчанию |
| — | Корень проектов для выбора директории |
|
| Папка с БД и конфигами |
|
| Таймаут задачи, секунд |
|
| Интервал опроса очереди, секунд |
|
| Начальная задержка retry |
|
| Максимальная задержка retry |
|
| Максимум попыток перед failed |
|
| Хост веб-сервера |
|
| Порт веб-сервера |
Структура репозитория (дерево файлов)
promptpilot/ ├── config.py — настройки, провайдеры, скилы, build_cmd ├── models.py — Pydantic-модели (TaskCreate, TaskInDB) ├── db.py — SQLite CRUD, миграции, очередь ├── worker.py — subprocess, парсинг stream-json, retry ├── cli.py — Click CLI (pp add, pp list, pp worker...) ├── api.py — FastAPI REST ├── bot.py — Telegram-бот (ConversationHandler, reply flow) ├── tg_auth.py — авторизация по номеру телефона ├── tray.py — системный трей (pystray) └── static/ └── index.html — Web UI (ванильный JS, один файл)
Намеренно без тяжёлых зависимостей: SQLite вместо Postgres, один HTML-файл вместо React, subprocess вместо SDK. pip install + pp worker — и работает.
Что дальше
Уведомления в Telegram — сообщение, когда задача завершилась (или упала)
История диалогов — показывать цепочку задача → ответ → ответ в одном view
Параллельные воркеры — отдельный воркер для каждого провайдера
Итог
Если коротко: отправляешь промпт откуда угодно — с компа, телефона, по расписанию — воркер сам разберётся с rate limits, дождётся своей очереди, выполнит и отдаст результат. Если модель задала вопрос — отвечаешь прямо из Telegram, не открывая терминал.
Буду рад вопросам и фидбеку — особенно если используете что-то похожее или есть идеи, как улучшить.
Первая статья на ХАБРе, прошу не судить строго.
