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.