1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

OpenCode + さくら AI Engineをコーディング以外にも様々な用途に使うことができますが、Skills(スキル)を使うともっと便利になります。

スキル とは、OpenCode に特定のタスクを実行するための「専門知識」「手順書」「スクリプト」を追加する機能です。毎回細かい指示を出さなくても、あらかじめスキルを置いておくと、OpenCode が状況を判断して自律的に手順を読み込み、定型業務や開発作業を自動実行します。

スキルの使い方

スキルの使い方は、Claude Code、Kiro などと共通です。Claude Code のスキルもそのまま使うことができます。

詳しいドキュメントはこちらを参照してください。
Skillshttps://opencode.ai/docs/ja/skills/

スキルの使い方は、簡単で、SKILL.md ファイルを次の場所に配置します。

スキル名ごとにフォルダーを 1 つ作成し、その中に SKILL.md を置きます。 OpenCode は次の場所を検索します。

  • プロジェクト設定: .opencode/skills//SKILL.md
  • グローバル設定: ~/.config/opencode/skills//SKILL.md
  • プロジェクト Claude 互換: .claude/skills//SKILL.md
  • グローバル Claude 互換: ~/.claude/skills//SKILL.md
  • プロジェクトエージェント互換: .agents/skills//SKILL.md
  • グローバルエージェント互換: ~/.agents/skills//SKILL.md

SKILL.mdについて

公式ドキュメントの例のように SKILL.md は次のような内容になります。
先頭の1行目から9行目がフロントマターと呼ばれる部分で、name(名前)とdescription(説明)は必須です。

ここの name と、上記のスキルを配置するフォルダー は一致する必要があります。ハイフン区切りの英数字になります。(これを間違えるとスキルを検出してくれません)

内容は、簡単なプロンプトを書くイメージです。生成AIを活用している人であればそれほど違和感はないと思います。

OpenCodeは起動時に上記の検索パスを検索して、この条件に一致するスキルを候補としてリストアップします。AIエージェントは、このスキルの名前をもとに、指示の内容に合ったスキルを探して、処理を行います。そのため、名前だけで何を行うスキルか分かるような名前をつけます。

---
name: git-release
description: Create consistent releases and changelogs
license: MIT
compatibility: opencode
metadata:
  audience: maintainers
  workflow: github
---

## What I do

- Draft release notes from merged PRs
- Propose a version bump
- Provide a copy-pasteable `gh release create` command

## When to use me

Use this when you are preparing a tagged release.
Ask clarifying questions if the target versioning scheme is unclear.

使ってみる

次のようなスキルを使っています。明示的に「このスキルで」という使い方もありますが、基本的には文脈で勝手に判断して使ってくれます。

1. さくら AI Engine の TTS

せっかく、さくら AI Engine を使っているので、簡単に呼び出せるようにしておく
opencode の中で読み上げ音声を作成するなどで利用できる、複数ファイルの連続処理もできる
音声モデルは、VOICEVOX の音声が使える。利用前にさくら AI Engineのコンソールで利用規約に同意しておく必要がある。

使用例:ずんだもんの声で「こんにちは」を読み上げて

---
name: sakura-text-to-speech
description: さくら AI Engineの音声読み上げ
---

次の形式でリクエストして、音声読み上げ(音声合成)/Text-to-Speech(TTS)を行う
無料プランは月に50回までのリクエストができる
<Token> は今使っているアクセストークンと同じ
<string> は読み上げの文字列

\```
curl --request POST \
  --url https://api.ai.sakura.ad.jp/v1/audio/speech \
  --header 'accept: audio/wav' \
  --header 'Authorization: Bearer <Token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "zundamon",
    "input": "<string>",
    "voice": "normal",
    "response_format": "wav"
  }' --output ./audio-speech-output.wav
\```

2. さくら AI Engine の STT

せっかく、さくら AI Engine を使っているので、簡単に呼び出せるようにしておく
opencode の中で音声認識などで利用できる、複数ファイルの連続処理もできる

使用例:sample.wav を文字起こしして

---
name: sakura-speech-to-text
description: さくら AI Engineの文字起こし(音声認識)
---

次の形式でリクエストして、文字起こし(音声認識)/Speech-to-Text(STT/speech recognition)を行う
<Token> は今使っているアクセストークンと同じ、環境変数 SAKURA_AI_API_KEY で設定する
以下の例では入力ファイルが sample.mp3

音声ファイルは30分、もしくは30MBの制限があるため、送信する前にチェックしてください

\```sh
curl --request POST \
  --url https://api.ai.sakura.ad.jp/v1/audio/transcriptions \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <Token>' \
  --header 'Content-Type: multipart/form-data' \
  --form 'file=@sample.mp3' \
  --form 'model=whisper-large-v3-turbo'
\```

3. マルチモーダル

opencode から画像の認識をしたり、OCR を行うことができる。OCR結果をExcelにしたりといった操作ができる。
このスキルがない、デフォルト状態では pytesseract から Tesseract が使われるが、これを使う方が断然はやい。

使用例:sample.pdf をOCRして、Excel形式にして

---
name: sakura-multi-modal
description: さくら AI Engineのマルチモーダル(画像認識/OCR)
---

次の形式でリクエストして、画像認識やOCRを行う
<Token> は今使っているアクセストークンと同じ、環境変数 SAKURA_AI_API_KEY で設定する
入力ファイルは、URL を指定するか、画像をBASE64エンコードして "data:image/jpeg;base64,${imageBase64}" 形式でセットする

エンドポイント: https://api.ai.sakura.ad.jp/v1/chat/completions
入力テキスト: <input_text>
入力ファイル: <input_file>

POSTデータ形式:

\```
{
  "model": "preview/Kimi-K2.7-Code",
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "<input_text>"},
        {
          "type": "image_url",
          "image_url": {"url": "<input_file>"}
        }
      ]
    }
  ]
}
\```

4. パワーポイント資料

資料作成は利用頻度が高いので、使うテンプレートを指定しておく
パワーポイントはデザインの指定、好みがあるので特に

---
name: create-powerpoint-presentation
description: テンプレートを用いて、PowerPointのプレゼンテーション資料を作成する
---

使用するテンプレート: template.pptx

指定された文書を読んで、テンプレートを用いて、PowerPointのプレゼンテーション資料を作成する。
想定読者に最適化された、論理的かつ視覚的にわかりやすいスライドを作成してください
想定読者、関心事、求めるアクション、を作成前に確認してください。

#レイアウトルール
現在のスライドマスターのレイアウトをそのまま使用し、ロゴ、タイトルの要素の位置を絶対に変更しないこと。
#デザインルール
~~お好みのデザインをここに記載する~~
#資料品質ルール
- 1スライド1メッセージを徹底し、伝えたいポイントを明確にすること
- 文章の羅列は避け、視覚要素を積極的に使うこと

5. Excel

資料作成は利用頻度が高いので使うテンプレートを指定しておく
パワーポイント同様、作成する時にテンプレートを探さなくてもいいように、あらかじめ使うテンプレートを置いておく
いまでも方眼Excelを求められることが多いので、方眼Excelのテンプレートを作成し、次のようなスキルを作成しておく

---
name: create-excel-specification
description: 指定された文書を読んで、テンプレートの「本文」シートに、Excelの仕様書/設計書を作成する
---

使用するテンプレート: template.xlsx

指定された文書を読んで、テンプレートの「本文」シートに、Excelの仕様書/設計書を作成する。
テンプレートはいわゆる「方眼Excel」なので、折り返して表示属性はつけず、列幅が変わらないようにする。
入力された文字数に合わせて、列を結合する。
1列に格納された文字数が20文字より多い場合は、例外として折り返して表示することも許可。

6. Word

資料作成は利用頻度が高いので使うテンプレートを指定しておく
パワーポイント同様、作成する時にテンプレートを探さなくてもいいように、あらかじめ使うテンプレートを置いておく
開発ではMarkdownを使っていても、提出はWordでというケースは多いので、Wordのテンプレートも用意しておく

7. Yahoo ファイナンス

特に指定しないと、デフォルトで海外のサイトを見にいくので、Yahoo! Japan を指定しておく

---
name: stock-price
description: 株価を調べる(日本国内)
---

使用するURL: https://finance.yahoo.co.jp

8. 今日は何の日?

メールやチャットで、日によって違う話題を提供するネタの1つとして用意しておく
外部サービスの呼び出しは OpenAPI 仕様で指定すると簡単かつ正確

---
name: what-is-todays-anniversary
description: 今日は何の日?
---

次の OpenAPI仕様でリクエストして、今日は何の日?か調べる

\```yaml:openapi.yaml
openapi: 3.0.3
info:
  title: 'What is today API'
  description: 'This is a simple API that can tell what is today.'
  version: 0.0.1
externalDocs:
  description: Find out more about What is today API
  url: https://note.com/sooz/n/n94cc1c71ad97
servers:
  - url: https://api.whatistoday.cyou/v3
paths:
  /anniv/{mmdd}:
    get:
      tags:
        - Anniversary
      summary: 'What anniversary is it today?'
      parameters:
        -
          name: mmdd
          in: path
          required: true
          description: 'MMDD format date.'
          schema:
            type: string
          example: 0214
      responses:
        200:
          description: 'Anniversary'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Anniversary'
        400:
          description: 'Error message.'
          content:
            application/json:
              schema:
                type: string
        404:
          description: 'Not found.'
          content:
            application/json:
              schema:
                type: string
  /anniv1_img/{mmdd}.png:
    get:
      tags:
        - AnniversaryImage
      summary: 'Get image of what anniversary is it today?'
      parameters:
        -
          name: mmdd
          in: path
          required: true
          description: 'MMDD format date.'
          schema:
            type: string
          example: '0214'
      responses:
        200:
          description: 'AnniversaryImage'
          content:
            image/png:
              schema:
                type: string
                format: binary
        400:
          description: 'Error message.'
          content:
            application/json:
              schema:
                type: string
        404:
          description: 'Not found.'
          content:
            application/json:
              schema:
                type: string
  /md/{mmdd}:
    get:
      tags:
        - Merchandising
      summary: 'What merchandising day is it today?'
      parameters:
        -
          name: mmdd
          in: path
          required: true
          description: 'MMDD format date.'
          schema:
            type: string
          example: '0214'
      responses:
        200:
          description: 'Merchandising'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Merchandising'
        400:
          description: 'Error message.'
          content:
            application/json:
              schema:
                type: string
        404:
          description: 'Not found.'
          content:
            application/json:
              schema:
                type: string
  /birthflower/{mmdd}:
    get:
      tags:
        - BirthFlower
      summary: 'What birthflower is it today?'
      parameters:
        -
          name: mmdd
          in: path
          required: true
          description: 'MMDD format date.'
          schema:
            type: string
          example: '0214'
      responses:
        200:
          description: 'BirthFlower'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BirthFlower'
        400:
          description: 'Error message.'
          content:
            application/json:
              schema:
                type: string
        404:
          description: 'Not found.'
          content:
            application/json:
              schema:
                type: string
  /famousbirthday/{mmdd}:
    get:
      tags:
        - famousbirthday
      summary: 'Which great birthday is it today?'
      parameters:
        -
          name: mmdd
          in: path
          required: true
          description: 'MMDD format date.'
          schema:
            type: string
          example: '0214'
      responses:
        200:
          description: 'FamousBirthday'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FamousBirthday'
        400:
          description: 'Error message.'
          content:
            application/json:
              schema:
                type: string
        404:
          description: 'Not found.'
          content:
            application/json:
              schema:
                type: string
components:
  schemas:
    Anniversary:
      type: object
      properties:
        _count:
          type: integer
          description: 'Counts'
          example: 1
        _last:
          type: string
          description: 'is last'
          nullable: true
        _items: 
          type: array
          items: 
            type: object
            properties: 
              anniv1: 
                type: string
                example: '世界気象デー'
              anniv2: 
                type: string
              anniv3: 
                type: string
              anniv4: 
                type: string
              anniv5: 
                type: string
              key: 
                type: string
                example: '83'
              mmdd: 
                type: string
                example: '0323'
    Merchandising:
      type: object
      properties:
        _count:
          type: integer
          description: 'Counts'
          example: 1
        _last:
          type: string
          description: 'is last'
          nullable: true
        _items: 
          type: array
          items: 
            type: object
            properties: 
              fashion1: 
                type: string
                example: '春物(プロパー)'
              fashion2: 
                type: string
              food1: 
                type: string
                example: '冬メニュー'
              food2: 
                type: string
              gift1: 
                type: string
                example: 'バレンタイン'
              gift2: 
                type: string
              key: 
                type: string
                example: '45'
              life1: 
                type: string
                example: '新生活(入園・入学・フレッシャーズ)'
              life2: 
                type: string
              mmdd: 
                type: string
                example: '0214'
    BirthFlower:
      type: object
      properties:
        _count:
          type: integer
          description: 'Counts'
          example: 1
        _last:
          type: string
          description: 'is last'
          nullable: true
        _items: 
          type: array
          items: 
            type: object
            properties: 
              flower: 
                type: string
                example: 'シュンラン'
              key: 
                type: string
                example: '45'
              lang: 
                type: string
                description: 'language of flower'
                example: '素直なしぐさ'
              mmdd: 
                type: string
                example: '0214'
    FamousBirthday:
      type: object
      properties:
        _count:
          type: integer
          description: 'Counts'
          example: 1
        _last:
          type: string
          description: 'is last'
          nullable: true
        _items: 
          type: array
          items: 
            type: object
            properties: 
              key: 
                type: string
                example: '7qfmexz8qu8d'
              lifespan: 
                type: string
                example: '1820-1893'
              mmdd: 
                type: string
                example: '0214'
              name: 
                type: string
                example: '清水次郎長'
              profile: 
                type: string
                example: '侠客・博徒'
\```

9. 天気予報

お好みの天気予報サイトを事前に指定しておく
外部サービスの呼び出しは OpenAPI 仕様で指定すると簡単かつ正確

---
name: jma-wheather-forecast
description: 気象庁の天気予報
---

次の OpenAPI仕様でリクエストして、天気予報を調べる

\```yaml:openapi.yaml
openapi: 3.0.3
info:
  version: 1.0.0
  title: JMAForecastAPI
  description: JMAForecastAPI provides weather data in Japan.
servers:
  - url: https://www.jma.go.jp/bosai
paths:
  /forecast/data/overview_forecast/{area}.json:
    get:
      summary: Retrieves overview forecast for a specific area.
      tags:
        - overview_forecast
      parameters:
        - in: path
          name: area
          schema:
            type: string
          description: The location for which to retrieve overview forecast (Area code is bellow, 北海道=016000,青森県=020000,秋田県=050000,岩手県=030000,宮城県=040000,山形県=060000,福島県=070000,宮城県=080000,栃木県=090000,群馬県=100000,埼玉県=110000,東京都=130000,千葉県=120000,神奈川県=140000,長野県=200000,山梨県=190000,静岡県=220000,愛知県=230000,岐阜県=210000,三重県=240000,新潟県=150000,富山県=160000,石川県=170000,福井県=180000,滋賀県=250000,京都府=260000,大阪府=270000,兵庫県=280000,奈良県=290000,和歌山県=300000,岡山県=330000,広島県=340000,島根県=320000,鳥取県=310000,徳島県=360000,香川県=370000,愛媛県=380000,高知県=390000,山口県=350000,福岡県=400000,大分県=440000,長崎県=420000,佐賀県=410000,熊本県=430000,宮崎県=450000,鹿児島県=460100,沖縄県=471000).
          example: 130000
          required: true
      responses:
        '200':
          description: Successful response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Overview'
        '400':
          description: Bad request. Invalid or missing parameters.
        '404':
          description: Not found. The specified location was not found.
        '500':
          description: Internal server error. Something went wrong on the server side.
  /forecast/data/forecast/{area}.json:
    get:
      summary: Retrieves forecast for a specific area.
      tags:
        - forecast
      parameters:
        - in: path
          name: area
          schema:
            type: string
          description: The location for which to retrieve forecast (Area code is bellow, 北海道=016000,青森県=020000,秋田県=050000,岩手県=030000,宮城県=040000,山形県=060000,福島県=070000,宮城県=080000,栃木県=090000,群馬県=100000,埼玉県=110000,東京都=130000,千葉県=120000,神奈川県=140000,長野県=200000,山梨県=190000,静岡県=220000,愛知県=230000,岐阜県=210000,三重県=240000,新潟県=150000,富山県=160000,石川県=170000,福井県=180000,滋賀県=250000,京都府=260000,大阪府=270000,兵庫県=280000,奈良県=290000,和歌山県=300000,岡山県=330000,広島県=340000,島根県=320000,鳥取県=310000,徳島県=360000,香川県=370000,愛媛県=380000,高知県=390000,山口県=350000,福岡県=400000,大分県=440000,長崎県=420000,佐賀県=410000,熊本県=430000,宮崎県=450000,鹿児島県=460100,沖縄県=471000).
          example: 130000
          required: true
      responses:
        '200':
          description: Successful response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forecast'
        '400':
          description: Bad request. Invalid or missing parameters.
        '404':
          description: Not found. The specified location was not found.
        '500':
          description: Internal server error. Something went wrong on the server side.
components:
  schemas:
    Overview:
      type: object
      properties:
        publishingOffice:
          type: string
          description: Publishing Office.
          example: 気象庁
        reportDatetime:
          type: string
          description: Report datetime.
          example: "2024-03-27T16:37:00+09:00"
        targetArea:
          type: string
          description: Area name.
          example: "東京都"
        headlineText:
          type: string
          description: Headline text.
        text:
          type: string
          description: Overview forecast.
    Forecast:
      type: array
      items:
        type: object
        properties:
          publishingOffice: 
            type: string
            example: "気象庁"
          reportDatetime: 
            type: string
            format: date-time
            example: "2024-03-24T11:00:00+09:00"
          timeSeries: 
            type: array
            items: 
              type: object
              properties: 
                timeDefines: 
                  type: array
                  items: 
                    type: string
                    example: "2024-03-24T11:00:00+09:00"
                areas: 
                  type: array
                  items: 
                    type: object
                    properties: 
                      area: 
                        type: object
                        properties: 
                          name: 
                            type: string
                            example: "東京地方"
                          code: 
                            type: string
                            example: "130010"
                      #
                      weatherCodes: 
                        type: array
                        items: 
                          type: string
                          example: "202"
                      weathers: 
                        type: array
                        items: 
                          type: string
                          example: "くもり 夕方 一時 雨"
                      winds: 
                        type: array
                        items: 
                          type: string
                          example: "南の風"
                      waves: 
                        type: array
                        items: 
                          type: string
                          example: "0.5メートル"
                      #
                      pops: 
                        type: array
                        items: 
                          type: string
                          example: "10"
                      #
                      temps: 
                        type: array
                        items: 
                          type: string
                          example: "10"
                      #
                      reliabilities: 
                        type: array
                        items: 
                          type: string
                          example: "A"
                      #
                      tempsMin: 
                        type: array
                        items: 
                          type: string
                          example: "11"
                      tempsMinUpper: 
                        type: array
                        items: 
                          type: string
                          example: "12"
                      tempsMinLower: 
                        type: array
                        items: 
                          type: string
                          example: "10"
                      tempsMax: 
                        type: array
                        items: 
                          type: string
                          example: "21"
                      tempsMaxUpper: 
                        type: array
                        items: 
                          type: string
                          example: "24"
                      tempsMaxLower: 
                        type: array
                        items: 
                          type: string
                          example: "18"
          tempAverage: 
            type: object
            properties: 
              areas: 
                type: array
                items: 
                  type: object
                  properties: 
                    area: 
                      type: object
                      properties: 
                        name: 
                          type: string
                          example: "東京"
                        code: 
                          type: string
                          example: "44132"
                    min: 
                      type: string
                      example: "7.0"
                    max: 
                      type: string
                      example: "16.5"
          precipAverage: 
            type: object
            properties: 
              areas: 
                type: array
                items: 
                  type: object
                  properties: 
                    area: 
                      type: object
                      properties: 
                        name: 
                          type: string
                          example: "東京"
                        code: 
                          type: string
                          example: "44132"
                    min: 
                      type: string
                      example: "13.5"
                    max: 
                      type: string
                      example: "37.1"

\```

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?