Skill

scheduled-tasks

Запуск Claude-сессий по расписанию (cron). Без живого пользователя. Для polling inbox, утренних дайджестов, мониторинга, регулярных отчётов.

Когда применять

Решение в 1 предложение

На macOS — launchd через ~/Library/LaunchAgents/*.plist. На Linux — cron через crontab -e. Внутри расписания — вызов claude -p "промт" или python-скрипт.

macOS launchd (рекомендую)

Шаг 1 — создаёшь plist

Файл ~/Library/LaunchAgents/world.demi.inbox-poll.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>world.demi.inbox-poll</string>

  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>-c</string>
    <string>/Users/<you>/bin/poll_inbox.sh</string>
  </array>

  <key>StartInterval</key>
  <integer>300</integer>  <!-- каждые 5 минут -->

  <key>StandardOutPath</key>
  <string>/tmp/inbox-poll.log</string>
  <key>StandardErrorPath</key>
  <string>/tmp/inbox-poll.err.log</string>

  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

Шаг 2 — загружаешь

launchctl load ~/Library/LaunchAgents/world.demi.inbox-poll.plist
launchctl list | grep world.demi    # проверка

Шаг 3 — выгружаешь когда надо

launchctl unload ~/Library/LaunchAgents/world.demi.inbox-poll.plist

Linux cron

crontab -e
# каждые 5 минут
*/5 * * * * /home/<you>/bin/poll_inbox.sh > /tmp/inbox-poll.log 2>&1
# каждый день в 9:00
0 9 * * * /home/<you>/bin/daily_report.sh

Что внутри скрипта (3 варианта)

Вариант A — простой curl без AI

#!/bin/bash
# poll_inbox.sh
NEW=$(curl -s https://demis.world/inbox/$PEER.ndjson | tail -20)
LAST_CURSOR=$(cat ~/.demi-node/inbox_cursor 2>/dev/null || echo "0")
HAS_NEW=$(echo "$NEW" | jq -r --arg c "$LAST_CURSOR" 'select(.id > ($c | tonumber)) | .severity' | head -1)

if [ "$HAS_NEW" = "critical" ]; then
  curl -s "https://api.telegram.org/bot$TG_TOKEN/sendMessage" \
    -d "chat_id=$DIMA_TG_ID" \
    -d "text=⚠️ Critical в inbox $PEER"
fi

Вариант B — Claude CLI обрабатывает

#!/bin/bash
# claude_poll.sh
claude -p "Прочитай свой inbox через GET https://demis.world/inbox/$PEER.ndjson,
  сравни с cursor в ~/.demi-node/inbox_cursor, обработай новые записи
  по правилам в CLAUDE.md. После — запиши новый cursor." \
  --append-system-prompt "$(cat ~/.claude/CLAUDE.md)"

Вариант C — Python скрипт через anthropic SDK

#!/usr/bin/env python3
# poll_with_ai.py
import os, json, requests
from anthropic import Anthropic

resp = requests.get(f"https://demis.world/inbox/{PEER}.ndjson")
new_lines = [json.loads(l) for l in resp.text.split('\n') if l.strip()]
cursor = int(open(os.path.expanduser("~/.demi-node/inbox_cursor")).read())
new = [m for m in new_lines if m['id'] > cursor]

if not new: exit(0)

client = Anthropic()
reply = client.messages.create(
    model="claude-haiku-4-5-20251001",
    max_tokens=500,
    system="Ты — assistent. Классифицируй inbox-сообщения, верни JSON action plan.",
    messages=[{"role":"user","content":json.dumps(new)}]
)
print(reply.content[0].text)
# дальше — обработка action plan, POST ответов, обновление cursor

Примеры реальных задач

ЗадачаРасписаниеЧто делает
Inbox poll каждые 5 мин Читает новые сообщения, critical → Telegram, action → ждёт утра
Daily report 09:00 daily Собирает git log за вчера + новые INBOX entries → сводка в Telegram
Site uptime каждые 5 мин curl главной страницы, если HTTP != 200 в течение 3 проверок → alert
Email digest 08:00 + 18:00 Gmail API → важные письма → INBOX.md
CI digest (Mon) понедельник 08:00 Perplexity research конкурентов → Telegram
Meeting reminder каждый час Google Calendar → если встреча через 30 мин и нет meeting-prep → пинг

Тонкие места

1. launchd при разлогине / sleep. StartInterval не считает время когда Mac в sleep — таймер пропускается. Решение: для критичных задач используй StartCalendarInterval с явными часами/минутами вместо StartInterval. Или проверяй внутри скрипта last run timestamp и догоняй.
2. Зомби-процессы. Если scheduled-task запустит Claude CLI и тот зависнет на 10 мин, через 5 мин запустится следующий — два параллельных процесса конкурируют. Решение: flock / lockfile в начале скрипта:
FLOCK=/tmp/poll.lock
exec 200>$FLOCK
flock -n 200 || { echo "уже запущен"; exit 0; }
# тут основная логика
3. Расход API/токенов в фоне. Cron запускает Claude/anthropic SDK раз в 5 мин = 288 запусков в день. Даже на Haiku ($0.001/req) это ~$0.30/день = $9/мес. Решение: circuit-breaker в скрипте — если новых сообщений нет, не зови LLM вообще; используй простой grep/jq если задача rule-based.
4. Тихий fail. Cron не уведомляет если скрипт упал. Может неделями молчать. Решение: в конце скрипта пиши heartbeat: echo $(date) > /tmp/last_run_inbox_poll. Отдельный watchdog раз в день проверяет что heartbeat младше 1 часа, иначе пинг.
5. Permission errors. launchd запускается до того как Keychain разблокирован → security find-generic-password вернёт ошибку. Решение: для скриптов которые нуждаются в Keychain — либо ставь зависимость от login (LimitLoadFromGUI=false ❌, наоборот), либо клади ключи в ~/.env с chmod 600 + читай из файла, не из Keychain.
6. Time zone. launchd использует системный TZ, cron — иногда UTC. Если расписание «каждый день в 9:00» — проверь что это PT, а не UTC. Решение: явно ставь TZ=America/Los_Angeles в скрипте либо в plist.
✅ Хороший паттерн: один master-supervisor (`com.demi.bot-monitor.plist` у Димы), который сам запускает другие задачи в нужный момент. Лучше один умный процесс чем 20 отдельных launchd entries — проще debug.

Готовые скрипты (примеры из demis-world)


Связанные: data-intake-protocol (что poll-ить), audio-to-text. Версия 1.0 · 2026-04-24.