All docs/Operations

docs/architecture/daily-overview-slack-posting.md

Daily Overview Slack Posting — Architecture

Flow (Step by Step)

Trigger

The daily overview is generated by Claude Code, triggered by .github/workflows/daily-overview.yml:

  • Schedule: Cron at midnight UTC daily (0 0 * * *)
  • Manual: workflow_dispatch with optional target_date for retrospective runs

Execution Chain

Plan Steps (from .github/prompts/daily-overview.md)

StepNamePurpose
1pull-historyFetch PRs + commits for 24h window
2classify-changesCategorize by user impact
3segment-summarySplit into Product/Engineering buckets
4draft-detailsWrite detailed sections below --- divider
5craft-compactWrite COMPACT block (TL;DR, highlights, wins, slowdowns)
6craft-headWrite HEAD block (punchy 4-6 bullet headline)
7commit-and-prCommit, push, create non-draft PR with labels

Slack posting is not in the plan — it happens in a separate GitHub Action triggered by the PR.

File Structure

<!-- HEAD_START -->
šŸš€ Product Update — Jan 28

• šŸ“± iPad onboarding works → more completions
• šŸŽ„ Large videos fail less → smoother delivery
• šŸ‘€ Admin visibility up → faster support
<!-- HEAD_END -->

<!-- COMPACT_START -->
### 🧭 TL;DR
...
<!-- COMPACT_END -->

---
### — Details —
...

Posting Logic

The posting script (post-daily-overview-to-slack.ts) extracts the HEAD and COMPACT blocks:

  • HEAD + COMPACT present + SLACK_BOT_TOKEN set: Posts HEAD as main channel message via Slack Web API, COMPACT as threaded reply using thread_ts
  • HEAD + COMPACT present, no token: Falls back to combined webhook message (no threading)
  • Only COMPACT or raw content: Posts via webhook as single message

Threading Mechanism

MethodAuthThreadingWhen Used
Incoming WebhookNone (URL has token baked in)Not supportedFallback when SLACK_BOT_TOKEN not set
Web API chat.postMessageSLACK_BOT_TOKEN env varSupported via thread_tsPrimary path (GHA has the secret)

GitHub Action Workflows

WorkflowTriggerPurpose
daily-overview.ymlCron (midnight UTC) / manualRuns Claude Code to generate the overview
daily-overview-post.ymlpull_request: opened (path: .kanbn/daily-overview/*-daily-overview.md)Posts to Slack with SLACK_BOT_TOKEN from secrets
auto-merge-eligible.ymlpull_request: opened (path: .kanbn/**/*.md)Adds auto-merge label if PR only changes safe markdown files

Key Files

FileRole
.github/workflows/daily-overview.ymlCron trigger, runs Claude Code via claude-code-action@v1
.github/workflows/daily-overview-post.ymlPR-triggered Slack posting
.github/workflows/auto-merge-eligible.ymlPR-triggered auto-merge label check
.github/prompts/daily-overview.md7-step plan Claude Code follows
.kanbn/daily-overview/daily-overview-template.mdTemplate with HEAD + COMPACT + Details structure
packages/ci-scripts/src/find-daily-overview-file.tsFinds the overview file from PR changed files
packages/ci-scripts/src/post-daily-overview-to-slack.tsCLI script: extracts HEAD/COMPACT, dispatches posting
packages/ci-scripts/src/utils/post-markdown-to-slack.tsPosting logic: webhook + Web API threading
packages/ci-scripts/src/convert-markdown-to-slack.tsMarkdown → Slack mrkdwn conversion
packages/ci-scripts/src/check-auto-merge-eligibility.tsChecks if PR is safe to auto-merge

Design Decision: Why Slack Posting Lives in a GHA Workflow

Claude Code generates the daily overview markdown and creates a PR. Slack posting happens in a separate GitHub Action (daily-overview-post.yml) triggered by the PR, not inside Claude Code.

Why? Content generation is decoupled from delivery. The SLACK_BOT_TOKEN is only needed in the posting workflow, keeping the generation step focused on analysis and writing. This also means:

  • Content generation (Claude Code) is decoupled from delivery (GHA)
  • Posting is deterministic — same script, same secret source, every time
  • The plan is simpler (7 steps instead of 8)

Migration History

This system was originally implemented using the Cursor cloud agent API (POST /v0/agents). It was migrated to anthropics/claude-code-action@v1 for:

  • Simpler architecture: Claude Code runs directly in the GHA runner with full repo access — no remote agent launch, no model selection API calls, no agent monitoring
  • Reliability: No dependency on Cursor API availability or model availability
  • Unified tooling: Same Claude Code that developers use locally