GitHub Actions × Chatwork API で出退勤メッセージを自動化した話

2026.01.27 09:00
2026.03.16 12:26
GitHub Actions × Chatwork API で出退勤メッセージを自動化した話

毎朝「おはようございます!業務開始します」、毎夕「お疲れ様です、業務終了します」——リモートワークでは当たり前のこの一言を、毎日手打ちしていました。

別に大した手間じゃないんですけど、「今日は出勤日だっけ?」と考える瞬間が地味にストレスで。祝日の振替出勤がある週は特にそうなんですよね。

そこで GitHub Actions と Chatwork API を使って、たった3ファイルでこの作業を自動化してみました。

全体の仕組み

┌─────────────────────────────────────────────┐
│  GitHub Actions (cron)                      │
│  毎日 8:55 / 18:05 (JST) に起動            │
│                                             │
│  ┌─────────────────────────────────┐        │
│  │ resolve-message.py              │        │
│  │  1. calendar.yml を読み込む     │        │
│  │  2. 今日は出勤日? → No → 終了 │        │
│  │  3. 朝 or 夕のメッセージを取得  │        │
│  └──────────┬──────────────────────┘        │
│             │ メッセージ                     │
│             ▼                               │
│  ┌─────────────────────────────────┐        │
│  │ Chatwork API                    │        │
│  │  curl で POST → ルームに送信    │        │
│  └─────────────────────────────────┘        │
└─────────────────────────────────────────────┘

ポイントは「出勤日の管理」と「メッセージの送信」を完全に分離しているところ。出勤日の判定は YAML ファイルに書かれたカレンダーで行い、送信ロジックは一切カレンダーの事情を知らない、という構成です。

ファイル構成

automations/
├── .github/workflows/
│   └── chatwork-scheduled-message.yml   # ワークフロー定義
├── messages/
│   └── calendar.yml                     # 出勤日・メッセージ管理
└── scripts/
    └── resolve-message.py               # 当日判定スクリプト

3ファイル。これだけです。

1. calendar.yml — 出勤日とメッセージを管理する

# デフォルトメッセージ(個別指定がない出勤日に使われる)
defaults:
  morning: |
    おはようございます!業務開始します
  evening: |
    お疲れ様です、業務終了します

# 出勤日(ここにある日だけメッセージを送信する)
workdays:
  2026-03:
    - 2   # 月
    - 3   # 火
    - 4   # 水
    - 5   # 木
    - 6   # 金
    - 9   # 月
    - 10  # 火
    - 11  # 水
    - 12  # 木
    - 13  # 金
    - 16  # 月
    - 17  # 火
    - 18  # 水
    - 19  # 木
    - 21  # 土 春分の日週の振替出勤(土曜)
    - 23  # 月
    # ... 以下続く

# 日付ごとのメッセージ上書き
calendar:
  "2026-04-01":
    morning: |
      新年度スタートです!
      今期もよろしくお願いします。
    evening: |
      新年度初日お疲れさまでした!

ここで「平日を自動判定」ではなく「出勤日を明示的にリストする」方式にしました。

理由はシンプルで、現実の出勤日って「平日」とイコールじゃないんですよね。祝日の週に土曜出勤がある、お盆は休み、年末年始の稼働日は会社ごとに違う——こういった例外を祝日 API やライブラリで吸収しようとすると、結局カレンダーを手で管理するのと変わらない複雑さになります。

それなら最初から「この日に出勤する」というリストを YAML に書いた方が、見通しがよくて、間違いにも気づきやすいかなと。

2. resolve-message.py — 今日のメッセージを決める

#!/usr/bin/env python3
import sys
import datetime
import yaml


def main():
    calendar_path = sys.argv[1]

    with open(calendar_path) as f:
        data = yaml.safe_load(f)

    # JST で現在時刻を取得
    now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9)))
    today_day = now.day
    year_month = now.strftime("%Y-%m")
    today_date = now.strftime("%Y-%m-%d")
    period = "morning" if now.hour < 12 else "evening"

    # 出勤日かチェック
    workdays = data.get("workdays") or {}
    days = workdays.get(year_month) or []
    if today_day not in days:
        sys.exit(1)

    # 日付個別のメッセージを確認 → なければデフォルト
    calendar = data.get("calendar") or {}
    if today_date in calendar and period in calendar[today_date]:
        message = calendar[today_date][period]
    else:
        message = data.get("defaults", {}).get(period)

    if not message:
        sys.exit(1)

    print(message.rstrip())


if __name__ == "__main__":
    main()

やっていることはシンプルです。

  1. JST で現在時刻を取得して、午前なら morning、午後なら evening を判定
  2. 今日が出勤日リストにあるかチェック。なければ終了コード 1 で即終了(何も送信しない)
  3. 日付ごとの上書きメッセージがあればそれを使い、なければデフォルトを出力

終了コード 1 で抜けるのがポイントで、GitHub Actions 側で || exit 0 と組み合わせることで「出勤日じゃなければワークフローを正常終了」という制御ができるようになっています。

3. chatwork-scheduled-message.yml — GitHub Actions ワークフロー

name: Chatwork Scheduled Message

on:
  schedule:
    # 毎日 朝8:55(JST)= UTC 23:55(前日)
    - cron: '55 23 * * *'
    # 毎日 夕方18:05(JST)= UTC 9:05
    - cron: '5 9 * * *'
  workflow_dispatch: # 手動実行も可能

jobs:
  send-message:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Resolve message
        id: resolve
        run: |
          pip -q install pyyaml
          MESSAGE=$(python scripts/resolve-message.py messages/calendar.yml) || exit 0
          {
            echo "message<<__EOF__"
            echo "$MESSAGE"
            echo "__EOF__"
          } >> "$GITHUB_OUTPUT"
          echo "should_send=true" >> "$GITHUB_OUTPUT"

      - name: Send Chatwork Message
        if: steps.resolve.outputs.should_send == 'true'
        run: |
          curl -s -X POST \
            -H "X-ChatWorkToken: ${{ secrets.CHATWORK_API_TOKEN }}" \
            --data-urlencode "body=${{ steps.resolve.outputs.message }}" \
            "https://api.chatwork.com/v2/rooms/${{ secrets.CHATWORK_ROOM_ID }}/messages"

いくつか気になったポイントをまとめます。

cron の時刻は UTC で書く

GitHub Actions の cron は UTC 基準です。JST 8:55 は UTC 23:55(前日)になります。ここを間違えると夜中にメッセージが飛んでしまうので気をつけたいところです。

|| exit 0 で非出勤日をスキップ

resolve-message.py が終了コード 1 を返した場合、|| exit 0 でステップを正常終了させます。こうすると should_send が設定されず、次の送信ステップが if で自然にスキップされる仕組みです。

workflow_dispatch で手動実行

workflow_dispatch を入れておくと、GitHub の Actions タブから手動で実行できます。セットアップ直後の動作確認に便利でした。

セットアップ手順

リポジトリの Settings → Secrets and variables → Actions → Repository secrets に以下を登録します。

Name 説明
CHATWORK_API_TOKEN Chatwork API トークン
CHATWORK_ROOM_ID 送信先のルーム ID
  1. calendar.yml に自分の出勤日を記入
  2. GitHub にプッシュ
  3. Actions タブ → Run workflow で手動実行して動作確認

これだけで翌日から自動送信が始まります。

運用してみて

実際に運用を始めて気づいたことがいくつかありました。

メッセージの送り忘れがゼロになったのがいちばん大きいです。当たり前なんですけど、特に祝日明けや振替出勤の土曜日に送り忘れることが多かったので、地味に助かっています。

月初に calendar.yml を更新する習慣ができたのも良かったです。出勤日を YAML に書く作業自体が、来月のスケジュールを確認する良いきっかけになっています。

特別な日のメッセージ上書きは意外と使わないですね。用意はしたものの、普段のメッセージで十分でした。ただ、年始の挨拶など年に数回は使いそうなので、仕組みとしてはあって正解かなと思っています。

まとめ

  • GitHub Actions の cron + Chatwork API で、出退勤メッセージを完全自動化できた
  • ファイル3つ、外部サービスの追加契約なし、ランニングコストなし(GitHub Actions の無料枠内)
  • 「祝日 API で自動判定」より「出勤日を YAML に明記」の方が、実運用ではシンプルで確実だった
  • 同じ仕組みで Slack や Teams への送信にも応用できそう(curl の宛先を変えるだけ)

小さな自動化ですが、毎日のことだからこそ効果を実感しやすいです。同じような「地味だけど毎日やってること」がある人の参考になれば嬉しいです。

今回は以上です!