リモート開発メインのソフトウェア開発企業のエンジニアブログです

Agent Skills を GitHub Actions 経由で定時実行し、野良化を防ぐ

Agent Skills、便利ですよね。触りたての頃は

「1日1個、業務を skill にして自動化する!」

とか息巻いていたのですが、1週間くらいで辛くなってきて、最近は1週間に1個くらいに落ち着いています。

どんな業務自動化を行ったかについては、本題ではないですし技術以外の要素も多いためここでは触れず、別途、会社ブログの方にまとめようと思います。

課題: 定時実行の Agent Skills を管理された環境で実行したい

開発プロジェクトでもそれ以外の業務でも良いのですが、よく行う業務を Claude Code を使って Agent Skills 化したとします。人間起点の業務であれば、Claude Code の中で

/very-useful-skill 必要なパラメーターとか

と手動で実行すれば良いのですが、

  • 1日1回自動実行したい
  • ある条件に合致するメールが届いたら起動したい

とかになると、何らかの仕組みが必要です。後者はそもそも何らかのシステムが必須なので良いとして、前者の場合、担当者が自分の PC や開発サーバーに cron ジョブを仕込んで自動実行させている場合もあるかと思います。所謂野良化です。

個人プロジェクトであればそれでも問題無いのですが、私はエンジニア兼管理職という立場なので、プロジェクトで使用する自動化ジョブなどは透明性を確保したいところです。

要件

要件としては、スクリプト実行も含む Agent Skills を管理された環境で実行するというものです。少し説明します。

以前も書いたのですが、Agent Skills の中核は SKILL.md というファイルです。Anthropic や OpenAI の API がそれをプロンプトとして受け取って処理を行っているだけです。

Claude のスキルは単なるテキストファイルで特別な仕組みはない – もばらぶエンジニアブログ

ただ、Agent Skills には任意の構成要素として scripts, references, assets というものがあり、特に scripts にはその名の通り Python スクリプトなどが入っていて、 SKILL.md に記載された処理の中から適宜呼び出されます。そのため、 scripts が含まれるスキルについては Python やシェルなどの実行環境が必要となります。

調べた選択肢

どんな選択肢があるのか、AI 対応の業務自動化ツールを中心にいくつか調べてみました。

n8n

結論から言うと、現時点では対応してなさそうです。フォーラムみたいなところで、関連する議論がいくつか見つかりました。

Enable n8n agents to use Agent Skills (SKILL.md + references) – Feature Requests – n8n Community

Dify

1.14.0-rc1 で機能が追加されたものの、色々と問題があったようで、1.14.0 の正式版からは外されています。

1.14.0-rc1: Dify x Agent Skills for Production Workflows & Collaboration (beta) – Announcements – Dify Community

いつ頃リリースされるんだ?みたいな質問も出ています。

Questions regarding the roadmap of “Agent x Skills” and “Skill Editor”: Why was it omitted in v1.14.0? · Issue #35689 · langgenius/dify

以下の Roadmap にも含まれているのでそのうちリリースされるのかもしれませんが、変化の速い AI の世界で、他のツールの実装をノンビリ待つほど暇ではないので、選択肢からは外れました。

Roadmap – Dify.AI

OpenClaw

最近は少し落ち着いてきましたが一時は至る所で話題になっていたので、OpenClaw についても調べてみました。

OpenClaw は Agent Skills に対応しているようで、Claude Code や Codex CLI で作成したものも、ちょっとした修正や変換コマンドを使うだけで実行出来るようです。

Skills – OpenClaw

そういう点では良かったのですが、OpenClaw をセキュアな設定で動かすのが結構面倒そうだったのと、私自身が OpenClaw を本格的に触ったことがなかったため、今回は見送りました。

Moba Pro

実際に行った方法

概要: GitHub Actions から、 claude -p を実行

GitHub Actions の実行環境に Claude Code をインストールし、 claude -p "/very-useful-skill" のように実行します。

GitHub Actions にはスケジュール機能があるので、先ほどの処理を定時実行するように設定します。

何が良いか

良い点を挙げます

  • GitHub のサイト上から実行結果を確認できる
  • Dify 等のツールのインストールなどは不要。yaml ファイルを作るだけ
  • 今のところ、claude -p はサブスクリプションで使用可能
    • 定額課金(追加の支払いは不要)
    • 元々は、 -p はサブスクリプションの対象外となる予定だったが、一時撤回された
  • Claude Code で作成したスキルを変更無しで使用可能
  • スキルのソースの可視化・バージョン管理も、GitHub で容易に行える

次に、それほどありませんが、良くない点も挙げます。

  • 複雑なワークフローは組みづらい
    • n8n 等でワークフローを組んで、その中の1つの処理とする事は可能
    • その場合、GitHub Actions API を n8n 等から呼び出す形になる

それくらいでしょうか。

実装方法

ディレクトリ構成

  • プロジェクト root
    • CLAUDE.md : どんなプロジェクトがあるか等の説明
    • .github/workflows/ : GitHub Actions の設定。詳細は後述
    • project-a/ : プロジェクトA
      • task-a1/ : 業務A1
        • .mcp.json : API key は環境変数で渡す
        • .claude/settings.json : 許可するコマンド、MCP ツール等を記載
        • .claude/skills/ : その業務で使う複数のスキル
          • skill-a1-foo/
          • skill-a2-bar/
      • task-a2/ : 業務A2
    • project-b/ : プロジェクトB
      • task-b1/ : 業務B1
        • .mcp.json
        • .claude/settings.json
        • .claude/skills/
          • skill-b1-baz/
      • task-b2/ : 業務B2

手動で実行するときは、各タスクのディレクトリ(例、project-a/task-a1)に cd で移動してから claude コマンドを起動し、そこでスキルを実行していました。

GitHub Actions ワークフロー定義

各種タスクで共通で使う内容を .github/workflows/_run-task.yml として以下のように通り作成します。(そのまま使えるように全部載せます。)

# Reusable workflow called by per-task workflow files.
#
# To add a new skill:
#   1. Create .github/workflows/run-task_<project>_<task>_<skill>.yml
#   2. Call this workflow with `uses: ./.github/workflows/_run-task.yml`
#   3. Pass `task-dir` (relative path) and `skill` (name without leading /)
#   4. Explicitly pass secrets (do NOT use `secrets: inherit`):
#        secrets:
#          CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
#          BLOQUE_API_KEY: ${{ secrets.<PROJECT>_BLOQUE_API_KEY }}
#   5. If the task needs a new type of API key, add a secret entry below
#      and wire it into the env vars of the "Run skill" step.

name: Run Task (reusable)

on:
  workflow_call:
    inputs:
      task-dir:
        description: "Relative path to the task directory from the repository root"
        required: true
        type: string
      skill:
        description: "Skill name to invoke (without the leading /)"
        required: true
        type: string
      artifact-name:
        description: "Base name for the uploaded artifact (run number is appended automatically)"
        required: false
        type: string
        default: task-output

    secrets:
      CLAUDE_CODE_OAUTH_TOKEN:
        required: true
        description: "Claude Code OAuth token for authentication"
      # Callers map their project-specific secret to this name, e.g.:
      #   BLOQUE_API_KEY: ${{ secrets.PROJECT_FOO_BLOQUE_API_KEY }}
      BLOQUE_API_KEY:
        required: false
        description: "Bloque API key — mapped from <PROJECT>_BLOQUE_API_KEY by the caller"

jobs:
  run:
    name: ${{ inputs.task-dir }} / ${{ inputs.skill }}
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: "24"

      - name: Install Claude Code CLI
        run: npm install -g @anthropic-ai/claude-code

      - name: Run skill
        working-directory: ${{ inputs.task-dir }}
        env:
          CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          BLOQUE_API_KEY: ${{ secrets.BLOQUE_API_KEY }}
        run: |
          set -o pipefail
          mkdir -p out
          claude -p "/${{ inputs.skill }}" 2>&1 | tee out/run.log

      - name: Upload output artifact
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: ${{ inputs.artifact-name }}-${{ github.run_number }}
          path: ${{ inputs.task-dir }}/out/
          if-no-files-found: warn

次に、各タスク毎の設定は、.github/workflows/run-task_<project名>_<業務名>_<スキル名>.yml として以下の通り作成します。

# Task: project-foo / task-bar / backlog-report
#
# Required GitHub secrets:
#   CLAUDE_CODE_OAUTH_TOKEN       — Claude Code OAuth token
#   PROJECT_FOO_BLOQUE_API_KEY    — Bloque API key for this project

name: project-foo / task-bar / backlog-report

on:
  workflow_dispatch:
  # schedule:
  #   - cron: '0 1 * * 1'  # Every Monday at 10:00 JST (UTC+9)

jobs:
  run:
    uses: ./.github/workflows/_run-task.yml
    with:
      task-dir: project-foo/task-bar
      skill: backlog-report
      artifact-name: project-foo-bask-bar-backlog-report
    secrets:
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      BLOQUE_API_KEY: ${{ secrets.PROJECT_FOO_BLOQUE_API_KEY }}

GitHub に秘密情報の登録

知っている方も多いと思いますが、GitHub では AWS の Secrets Manager のように、秘密情報をサイト上に登録して GitHub Actions で読み込むようにさせることが出来ます。

使い方は、レポジトリの Settings タブ -> 左メニューの Secrets and variables 配下の Actions を選択し、Repository secrets を追加します。

追加するものは、以下の通りです。

  • CLAUDE_CODE_OAUTH_TOKEN (必須): Claude Code を使うために必要
  • 使用する MCP サーバーの API キー等(タスクによって異なる)

CLAUDE_CODE_OAUTH_TOKEN は、以下のドキュメントを参考に作成してください。

Authentication – Claude Code Docs

MCP サーバーは、タスク毎に必要な MCP サーバーを弊社で開発している Bloque 上で一元管理して、Bloque の API キーのみを渡しています。上の例では PROJECT_FOO_BLOQUE_API_KEY というsecret を BLOQUE_API_KEY という環境変数に設定しています。

その他設定

今回の GitHub Actions 固有の話ではなく Agent Skills の設定にはなりますが、いくつか確認しておくべき設定項目を記載します。

まずは、各タスク毎のディレクトリに保存されている .mcp.json ですが、以下の通りになっています。GitHub の secret が環境変数としてここに注入されます。

{
  "mcpServers": {
    "bloque": {
      "type": "http",
      "url": "https://mcp.bloque.run/mcp",
      "headers": {
        "Authorization": "Bearer ${BLOQUE_API_KEY}"
      }
    }
  }
}

.claude/settings.json には、スキルから呼び出される MCP ツールを以下の通り事前に許可リストに追加しておきます。そうしないと、Claude Code がユーザーに許可を求めようとして、そこで止まってしまうはずです。

{
  "permissions": {
    "allow": [
      "mcp__bloque__backlog__get_issue",
      "mcp__bloque__backlog__get_issues",
      "mcp__bloque__backlog__get_issue_comments",
      "mcp__bloque__slack__slack_send_message"
    ]
  }
}

とここまで書いて思ったのですが、上の設定はローカル環境で実行するときには必要ですが、GitHub Actions のような隔離された環境であれば claude コマンドに --dangerously-skip-permissions を付けて実行してしまっても良いかもしれません。

感想

やってみたら意外に簡単で特にはまりポイントもなく、実行結果も GitHub Actions の画面から確認できますし、 SKILL.mdscripts のソースコードも当然 GitHub で管理できるので、満足しています。他のツール(例えば OpenClaw)でやろうとすると、多分 Claude Code と OpenClaw 間の違いとかで細かい調整が必要になりそうですが(※)、今回の仕組みは Claude Code をそのまま動かすので楽でした。

※: OpenClaw から Claude Code を呼び出せば回避できそうですが、私は OpenClaw に詳しくないので深入りはしません。

今後やりたい事

複雑なワークフローに組み込む

最初の方で、今回の方法では「複雑なワークフローは組みづらい」と書きました。GitHub Actions のワークフロー単体だとそうなのですが、n8n などで分岐などがあるワークフローを組んで、その中の1ステップとして GitHub Actions を呼び出すという方法は可能です。

これについては、実際にやる事があればまたブログ記事で書こうと思います。

他のプロジェクトに広げる

現在はある1つのプロジェクト限定で試しているところでしたが、結構良い感じに出来たので、別プロジェクトでもこの方式を展開していきたいと思っています。特に開発業務であれば既に GitHub を使っているので、この方式を導入するのも容易だと思います。

具体的な自動化の事例を共有する

今回は、仕組みを構築する部分を詳しく説明しましたが、上の方でも書いたとおり今後はどのような業務の自動化を行ったのかについても(技術ブログではなく会社ブログの方に)書いていこうと思います。

最近は様々な MCP サーバーが凄い勢いでリリースされていますので、それらを上手く活用して業務のさらなる効率化を目指したいです。

まとめ

業務の自動化で AI ツールを自由に使わせると、業務が属人化したり野良化したりしがちです。野良 Excel マクロと本質的には同じ問題です。

今回、既存の Agent Skills に GitHub, GitHub Actions を組み合わせることで、

  • 定時実行タスクを、管理された環境(GitHub)で実行
  • Agent Skills の変更管理(Git)

を実現することが出来ました。

また、(少し宣伝になりますが)スキルから使用する MCP サーバーを Bloque 上で一元管理することで、

  • GitHub Actions の設定の簡略化(必要な API キーは1つだけ)
  • MCP サーバーの認証・設定の簡略化(Bloque 上で実施)

を実現することが出来ました。

MCP サーバーの設定が IaC 化されなくなるという懸念もあるかもしれませんが、Bloque 上で MCP サーバーの設定を一括で JSON に出力する事も出来るので、必要であればそれを GitHub 上で管理しておくと良いと思います。

← 前の投稿

git diff で改行とかを無視したい

次の投稿 →

コメントを残す