LittleJakub

daily-brief

0
0
# Install this skill:
npx skills add LittleJakub/daily-brief

Or install specific skill: npx add-skill https://github.com/LittleJakub/daily-brief

# Description

Morning & evening personal briefings via Telegram — weather, ICS calendar (Outlook/Google/iCloud), Todoist tasks, life-ledger reminders, pulse-board rig status. OpenClaw skill. Stdlib only, no pip deps.

# SKILL.md

daily-brief

Version: 1.2.0
Location: ~/.openclaw/agents/main/workspace/skills/daily-brief/


What it does

daily-brief posts two personal briefings to a configurable channel (Feishu or Telegram) each day — a morning edition and an evening edition. Personal day planner, not a system health monitor (that's pulse-board).


Morning briefing — 06:00

Section Source Required
Weather today OpenWeatherMap OPENWEATHER_API_KEY
Today's calendar ICS feeds configured in setup
Tasks due today + overdue Todoist REST API v1 TODOIST_API_TOKEN
Life-ledger reminders (7-day window) ledger.json configured in setup
Rig status (one-liner) pulse-board last-delivered.md configured in setup

Evening briefing — 21:00

Section Source Required
Tomorrow's calendar ICS feeds configured in setup
Weather tomorrow OpenWeatherMap OPENWEATHER_API_KEY
Unfinished items from today Todoist REST API v1 TODOIST_API_TOKEN
7-day task + date horizon Todoist + life-ledger
Life-ledger reminders ledger.json configured in setup

Manual run

python3 ~/.openclaw/agents/main/workspace/skills/daily-brief/daily_brief.py morning
python3 ~/.openclaw/agents/main/workspace/skills/daily-brief/daily_brief.py evening

Required secrets

All in ~/.openclaw/shared/secrets/openclaw-secrets.env:

Variable Description
TELEGRAM_BOT_TOKEN Telegram bot token (when channel = telegram)
TODOIST_API_TOKEN Todoist REST API token (shared with task-bridge)
OPENWEATHER_API_KEY OpenWeatherMap API key (free — new keys take up to 2h to activate)
FEISHU_APP_ID Feishu app ID (when channel = feishu)
FEISHU_APP_SECRET Feishu app secret (when channel = feishu)
FEISHU_HORIZON_ROOT_MSG Root om_xxx message ID of the target Feishu topic
DAILY_BRIEF_ICS_* One per calendar — name is up to you

Config file

~/.openclaw/config/daily-brief/config.json — written by setup.py.

{
  "channel": "feishu",
  "feishu": {
    "chat_id": "oc_..."
  },
  "telegram": {
    "chat_id": -1001234567890,
    "thread_id": 99
  },
  "weather": {
    "lat": 0.0000,
    "lon": 0.0000,
    "city_name": "Your City"
  },
  "calendar": {
    "enabled": true,
    "calendars": [
      {"label": "Personal", "ics_secret_key": "DAILY_BRIEF_ICS_PERSONAL"},
      {"label": "Work",     "ics_secret_key": "DAILY_BRIEF_ICS_WORK"}
    ]
  },
  "life_ledger": {
    "enabled": true,
    "path": "/home/USER/.openclaw/shared/life-ledger/ledger.json"
  },
  "pulse_board": {
    "enabled": true,
    "last_delivered_path": "/home/USER/.openclaw/agents/main/workspace/skills/pulse-board/last-delivered.md"
  },
  "alert_window_days": 7
}

Notes:
- channel"feishu" or "telegram". Defaults to "telegram" if omitted.
- feishu.thread_id — not used. Topic routing is via FEISHU_HORIZON_ROOT_MSG secret (reply API).
- calendar.calendars — add as many calendars as needed.
- life_ledger.enabled / pulse_board.enabled — set false to omit those sections entirely.


Feishu topic routing

Feishu rejects receive_id_type=thread_id with a field validation error. The only working method to post into an existing topic is the reply API, using the root om_xxx message ID of that thread.

To get the root message ID of a topic:

source ~/.openclaw/shared/secrets/openclaw-secrets.env

TOKEN=$(curl -s https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
  -H "Content-Type: application/json" \
  -d "{\"app_id\":\"$FEISHU_APP_ID\",\"app_secret\":\"$FEISHU_APP_SECRET\"}" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["tenant_access_token"])')

curl -s "https://open.feishu.cn/open-apis/im/v1/messages?container_id_type=thread&container_id=$FEISHU_TOPIC_HORIZON&page_size=1" \
  -H "Authorization: Bearer $TOKEN" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["data"]["items"][0]["message_id"])'

Store the result as FEISHU_HORIZON_ROOT_MSG in openclaw-secrets.env.


Calendar — ICS feeds

Works with any calendar that provides an ICS URL. URLs stored in secrets, never in config.

Service Path
Outlook.com Settings → Calendar → Shared calendars → Publish → copy ICS link
Office 365 Same flow at outlook.office.com (requires IT to allow external publishing)
Google Calendar Calendar settings → Integrate calendar → Secret address in iCal format
iCloud Share → Public Calendar → copy link (change webcal:// to https://)

Logs

~/.openclaw/agents/main/workspace/skills/daily-brief/daily-brief.log


Cron

crontab -l | grep daily-brief

Includes a PATH= line with ~/.npm-global/bin so openclaw resolves in cron context.


Skill Relationship
pulse-board daily-brief reads last-delivered.md for the morning rig one-liner
task-bridge Shares TODOIST_API_TOKEN
life-ledger daily-brief reads ledger.json — read-only

# README.md

Daily Brief

An OpenClaw skill that posts a morning and evening personal briefing via a configurable channel (Feishu or Telegram) — weather, calendar events, tasks, life reminders, and a rig health check.

This is a personal day planner, not a system health monitor. For system health, see pulse-board.


What's in each briefing

Morning — 06:00

Section Source
Weather today OpenWeatherMap (free tier)
Today's calendar ICS feeds (Outlook, Google, iCloud, etc.)
Tasks due today + overdue Todoist REST API v1
Life-ledger reminders (7-day window) life-ledger skill
Rig status (one-liner) pulse-board

Evening — 21:00

Section Source
Tomorrow's calendar ICS feeds
Weather tomorrow OpenWeatherMap
Unfinished items from today Todoist REST API v1
7-day task + date horizon Todoist + life-ledger
Life-ledger reminders life-ledger skill

Life-ledger and pulse-board are optional — setup asks whether they're installed and omits their sections cleanly if not.


Delivery channels

Set "channel" in config.json:

Value Description
"feishu" Feishu chat topic via tenant access token + reply API
"telegram" Telegram supergroup topic (default)

Both configs can coexist — switching channels is a one-line change.


Requirements

  • Python 3.9+ (stdlib only — no pip dependencies)
  • OpenWeatherMap API key (free tier — new keys take up to 2 hours to activate)
  • Todoist account + API token
  • Feishu (primary): app with app_id + app_secret, target chat, and root message ID of the topic
  • Telegram (fallback): bot token, supergroup chat_id, topic thread_id

Optional:
- ICS calendar URLs (Outlook.com, Office 365, Google Calendar, iCloud, or any standard ICS source)
- life-ledger — for upcoming date/reminder alerts
- pulse-board — for the morning rig status one-liner


Install

cp daily_brief.py setup.py SKILL.md CHANGELOG.md _meta.json \
  ~/.openclaw/agents/main/workspace/skills/daily-brief/

python3 ~/.openclaw/agents/main/workspace/skills/daily-brief/setup.py

Setup will:
- Ask for your delivery channel and credentials
- Ask for city name, coordinates, and OpenWeatherMap key
- Ask for Todoist token
- Ask about ICS calendar feeds
- Ask whether life-ledger and pulse-board are installed
- Validate each API live before writing anything
- Write ~/.openclaw/config/daily-brief/config.json
- Install cron entries (06:00 and 21:00)


Feishu topic routing

Feishu rejects receive_id_type=thread_id. The only working method to post into an existing topic is the reply API, targeting the root om_xxx message ID of the thread.

Get the root message ID of your target topic:

source ~/.openclaw/shared/secrets/openclaw-secrets.env

TOKEN=$(curl -s https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
  -H "Content-Type: application/json" \
  -d "{\"app_id\":\"$FEISHU_APP_ID\",\"app_secret\":\"$FEISHU_APP_SECRET\"}" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["tenant_access_token"])')

curl -s "https://open.feishu.cn/open-apis/im/v1/messages?container_id_type=thread&container_id=$FEISHU_TOPIC_HORIZON&page_size=1" \
  -H "Authorization: Bearer $TOKEN" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["data"]["items"][0]["message_id"])'

Store the result:

echo "FEISHU_HORIZON_ROOT_MSG=om_xxx..." \
  >> ~/.openclaw/shared/secrets/openclaw-secrets.env

Calendar setup

ICS URLs are treated as secrets — store them in openclaw-secrets.env:

echo "DAILY_BRIEF_ICS_PERSONAL=https://..." \
  >> ~/.openclaw/shared/secrets/openclaw-secrets.env
Service Path
Outlook.com Settings → Calendar → Shared calendars → Publish → copy ICS link
Office 365 Same flow at outlook.office.com (requires IT to allow external publishing)
Google Calendar Calendar settings → Integrate calendar → Secret address in iCal format
iCloud Share → Public Calendar → copy link (change webcal:// to https://)

Required secrets

All in ~/.openclaw/shared/secrets/openclaw-secrets.env:

Variable Description
FEISHU_APP_ID Feishu app ID
FEISHU_APP_SECRET Feishu app secret
FEISHU_HORIZON_ROOT_MSG Root om_xxx message ID of the target Feishu topic
TELEGRAM_BOT_TOKEN Telegram bot token (fallback channel)
TODOIST_API_TOKEN Todoist REST API token
OPENWEATHER_API_KEY OpenWeatherMap API key
DAILY_BRIEF_ICS_* One per calendar — name is up to you

Manual run

python3 ~/.openclaw/agents/main/workspace/skills/daily-brief/daily_brief.py morning
python3 ~/.openclaw/agents/main/workspace/skills/daily-brief/daily_brief.py evening

Why ICS and not Microsoft Graph?

Microsoft deprecated personal account app registration outside a directory in June 2024. ICS export requires no auth, no app registration, and works for personal Outlook.com and (if IT allows external publishing) work/school Microsoft 365 accounts.


Formatting note

Briefs are composed in HTML internally. Telegram receives them with parse_mode: HTML. Feishu receives plain text — all HTML tags are stripped before delivery.


License

MIT

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.