Auto-generates a concise daily work report from three local sources and delivers it to Feishu:
- git commits — your commits that day across all repos under
~/code/* - Claude Code sessions — that day's session titles, prompts, and edited files
- Feishu calendar — that day's meetings/interviews (via CalDAV)
Sources 1 & 2 are harvested for the current user plus any "extra users" — service/bot
accounts whose work should roll up into the same report. None are folded in by default; name
them via the DAILY_REPORT_EXTRA_USERS env var (space-separated) or --extra-users a b.
Their $HOME is 0700, so gather_context.py reads them via passwordless sudo -n -u <user>
(git repos under /home/<user>/code/* and sessions under /home/<user>/.claude/projects).
Commits shared between clones are de-duplicated by hash; an unreachable extra user is
skipped with a note (never a crash). Disable extras with a bare --extra-users. This is how
work done under a service account (e.g. report_hub) rolls into the same report.
Remote machines (sessions only). Claude sessions on other hosts — e.g. Claude Desktop on
a Windows box reached over msys2 bash — fold in via DAILY_REPORT_SSH_HOSTS="host1 host2"
(ssh aliases) or --ssh-hosts. Each host is one ssh -o BatchMode=yes call that streams
back ~/.claude/projects/*/*.jsonl modified since the window start; no git is read there.
Sessions carry a [<host>] tag; an unreachable host is skipped with a note. Desktop session
names (custom-title) are used as titles, ignoring the New session placeholder.
Automated pipeline sessions are dropped. Queued automation (e.g. tq_ai library/alphas
mining) runs claude in ephemeral per-job scratch checkouts and can spawn hundreds of
sessions a day — under the primary user too — swamping the report. Sessions whose cwd
matches DAILY_REPORT_EXCLUDE_CWD_GLOBS (or --exclude-cwd, e.g. /tmp/tqlib_ro_* /tmp/aha_ro_*) are skipped, keeping only interactive Claude-Max work; the dropped jobs' git
commits still count. Match only the scratch dirs, not the pipeline's own code dirs. Empty /
bare --exclude-cwd = no filtering.
A small LLM pass (Claude headless) synthesizes the material into themed bullets.
| Path | What |
|---|---|
~/my/daily_report/ |
this repo — all code + config |
~/my/daily_report/holidays/ |
cached China holiday/workday JSON (one file per year), auto-refreshed |
~/.claude/skills/daily-report |
symlink → this repo, so /daily-report works as a skill |
/tq/scratch/<user>/daily_report_log/ |
generated reports + run_daily.log + last_covered cron cursor (NOT in repo) |
gather_context.py— git + Claude-session material for a date or date rangegather_calendar.py— Feishu calendar for a date/range (CalDAV). SeeFEISHU_SETUP.mdworkday.py— is a date a China workday? (调休-aware) + computes each cron run's report spanfetch_holidays.py— refresh the cached China holiday calendar (holiday-cn JSON) intoholidays/send_feishu.py— deliver a report to Feishu (group webhook, or 1:1 DM)run_daily_report.sh— gather → synthesize (claude -p) → archive → deliver (workday-gated)SKILL.md— the/daily-reportskill definition (interactive use)FEISHU_SETUP.md— calendar (CalDAV) + delivery setup.feishu_*.json— local secrets, gitignored (see the.examplefiles)daily_report.local— local site config, gitignored (extra service accounts, automated-sessionEXCLUDE_CWD_GLOBS,OUT_DIRoverride; see the.example)
Interactive (in Claude Code): /daily-report 2026-06-01
Manual / scheduled:
~/my/daily_report/run_daily_report.sh # cron mode: workday-gated, span since last report
~/my/daily_report/run_daily_report.sh 2026-06-01 # one specific date (never touches cron state)
~/my/daily_report/run_daily_report.sh 2026-06-01 --no-send
~/my/daily_report/run_daily_report.sh --no-send # cron-mode dry-run (generate only; no DM, no state)No systemd/cron natively on this box, so cron was installed and a job added:
0 7 * * * ~/my/daily_report/run_daily_report.sh >> /tq/scratch/<user>/daily_report_log/cron.log 2>&1
Runs every morning at 07:00. The cron run is China-workday-aware (incl. 调休 makeup
workdays — driven by workday.py + the cached calendar in holidays/):
- On a workday it reports every day since the last report (cursor file
last_covered), so the first workday after a weekend/holiday folds the whole break into ONE report (e.g. the Thursday back from National Day covers2026-09-30 → 2026-10-07). - On a non-workday it doesn't synthesize — it DMs a short rest-day placeholder that
points at the next workday (e.g.
📅 Holiday: 国庆节 (2026-10-01) — … on the next workday (2026-10-08)). last_coveredadvances only after a successful send, so a failed send or a missed run is retried next time — no dropped or double-sent days, and it self-heals after downtime.
The calendar self-updates: each run calls fetch_holidays.py --quiet (throttled to ~monthly),
which pulls next year's calendar once the State Council publishes it; otherwise everything is
offline. After a host reboot the cron daemon isn't auto-started (no systemd) — re-arm with
sudo service cron start.
Cursor (last_covered). Lives at /tq/scratch/<user>/daily_report_log/last_covered and
holds the last date already reported. The next cron run covers (last_covered, yesterday].
Seed/reset it with echo 2026-06-14 > .../last_covered; delete it to re-bootstrap (next
run then covers just yesterday). A corrupt/blank cursor self-heals to "cover yesterday".
Archived span reports are named YYYY-MM-DD_YYYY-MM-DD.md (single days stay YYYY-MM-DD.md).
English; a single markdown bullet list (no section headers, no commit count). 3–5 themed
work bullets (- **Topic**: …, max 8), then a final calendar bullet when there are events:
- 📅 2 interviews; Quant Team Weekly; 1-on-1 with Chang Zhang (interviews collapsed to a
count; meetings prefer their own name, falling back to "Meeting with " — names
romanized to pinyin — only when the title is generic). See SKILL.md for the exact rules.
Delivered to Feishu as a blue-header interactive card (Daily Report — <date>) with the
markdown rendered — bold Topics, inline code, one bullet per line. To paste it into a Feishu
Doc with formatting intact, copy from the Feishu desktop client (the web client drops bold
on paste); for a 100%-faithful copy, import the archived .md into Feishu Drive (drag it into
云空间). See FEISHU_SETUP.md for delivery setup + paste tips.
pip install requests icalendar recurring_ical_events
python3 fetch_holidays.py # seed holidays/ (this + next year)
cp .feishu_caldav.json.example .feishu_caldav.json # then fill in (or use --set-caldav)
cp .feishu_webhook.json.example .feishu_webhook.json # then fill in (or use --set-webhook)
cp daily_report.local.example daily_report.local # optional: extra service accounts / OUT_DIR
ln -s ~/my/daily_report ~/.claude/skills/daily-report # register the skill
holidays/*.jsonis committed, so a fresh checkout already works offline; thefetch_holidays.pystep just refreshes it. The calendar uses China's statutory holidays + 调休 makeup workdays via holiday-cn.