“欲しい道具は自分で作る”——AIと一緒に小さな業務改善ツールを量産した話 <vibe coding>

こんにちは、makeshop事業本部開発部の鈴木(佳)です。

開発をしていると、「これ、地味に面倒だな」という小さな不便に毎日ぶつかります。GitHubのPRをSlackに貼るとき、URLとタイトルを別々にコピーして整える。自分が今週どのPRに関わっていたか、GitHubを何往復もして思い出す。——どれも一つひとつは数十秒の話ですが、塵も積もればそれなりの時間です。

以前なら「ツールを作るほどではないか」と見送っていたこの手の不便を、最近はAIと一緒にその場でサクッと作って解消するようになりました。本記事では、私が実際に作った3つの小さな業務改善ツールと、その「作り方」を紹介します。

なぜ作ったのか

ツールを自作するハードルは、AIによって明確に下がりました。Chrome拡張のマニフェストの書き方も、Viteのプロジェクト構成も、うろ覚えで大丈夫です。「GitHubのPRページにSlack共有ボタンを足したい」と言葉で伝えれば、たたき台が出てくる。あとは動かしながら直していくだけ。

「作るほどでもない」の基準が下がった——これが一番大きな変化でした。以下、軽いものから順に紹介します。

ツール1:GitHub → Slack リンクコピー(Chrome拡張)

最初に作ったのは、GitHubのPR/Issueページに「Slackにコピー」ボタンを追加するChrome拡張です。ボタンを押すと、タイトルにURLが埋め込まれたリンクがクリップボードに入り、Slackに貼るとタイトル文字列がそのままクリッカブルなリンクになります。

#nnnn 〇〇のモーダルでエラーが表示されない不具合
  ↑ この文字列全体が、IssueのURLへのリンクになって貼り付く

仕組みは Manifest V3 のコンテンツスクリプトで、ページのアクション欄にボタンを差し込んでいるだけです。少し工夫したのは、クリップボードに HTML形式とプレーンテキスト形式の両方を書き込んでいる点。これでSlackがリッチテキストのリンクとして解釈してくれます。

btn.addEventListener('click', () => {
  const { url, title } = getSlackLink();
  // HTML形式で書くと、Slackがリッチテキストのリンクとして貼り付ける。
  // HTMLは文字列連結せずDOMで組み立てる(title内の < > & " によるHTML崩れを防ぐ)
  const a = document.createElement('a');
  a.href = url;
  a.textContent = title;
  const htmlBlob = new Blob([a.outerHTML], { type: 'text/html' });
  // text/htmlが効かない貼り付け先用のフォールバックは「素のテキスト+URL」
  const textBlob = new Blob([`${title} ${url}`], { type: 'text/plain' });
  navigator.clipboard.write([
    new ClipboardItem({ 'text/html': htmlBlob, 'text/plain': textBlob })
  ]).then(() => showToast('Slackリンクをコピーしました'));
});

もう1つ、GitHubはSPA(ページ遷移してもリロードされない)なので、MutationObserver でDOMの変化を監視し、ページが切り替わってもボタンを差し直すようにしています。

const observer = new MutationObserver(() => {
  if (document.getElementById('ghslack-copy-btn')) return;
  injectButton();
});
observer.observe(document.body, { childList: true, subtree: true });

ツール2:Redmine → Slack リンクコピー(横展開)

ツール1が便利だったので、同じ発想を社内のRedmine(チケット管理)にも横展開しました。チケットページに同じく「Slackにコピー」ボタンを足すだけの拡張です。

一度パターンを確立すると、対象サイトのDOM構造に合わせてセレクタを差し替えるだけで横展開できます。「同じ不便は、同じ型で潰す」。AIに「ツール1と同じ仕組みをRedmine向けに」と頼めば、骨格はすぐに出てきます。

ツール3:GitHub Activity Portal(自分の活動ダッシュボード)

3つ目は少し大きめで、自分が今週・先週に携わったPR/Issueを一覧できるポータル画面を作りました。技術スタックは React + Vite + Tailwind CSS です。

主な機能はこんな感じです。

機能 内容
一覧・絞り込み 今週/先週の切り替え、PR/Issueのタイプ絞り込み、ステータス・関与・レビュー状態でのフィルタ
プレビュー PR/Issueの本文・コメントをMarkdownレンダリングしてポップアップ表示
PR操作 コンフリクト有無・承認状況・未解決スレッド数をリアルタイム表示。ブラウザからそのままマージ
CI/デプロイ HEADコミットのCI/Actions実行状況、マージ済みPRはデプロイ状況を表示
メモ 重要なPR/Issueをピン留め、カードにメモ(URLは自動リンク化)

「自分の関与PRを横断的に見たい」「コンフリクトが起きていないかGitHubを開かずに知りたい」という日々の不便を、1画面に集約したものです。認証はGitHubのPersonal Access Token、あるいはDevice Flowに対応させ、ローカルで動かせるようにしています。

このくらいの規模になると一気には作れませんが、それでもAIと「まずPR一覧の取得→次に絞り込みUI→次にプレビュー」と機能を1つずつ足していく進め方で、無理なく形にできました。

AIとの作り方=バイブコーディング

3つに共通する作り方を一言で言うと、「自然言語で要件を伝えて、たたき台を出してもらい、動かしながら直す」 の繰り返しです。いわゆる vibe coding(バイブコーディング)。

私が意識しているのは次のあたりです。

  • 最初の一歩を小さく … 「ボタンを1個足す」「PRを1件取得する」から始める。完成形を一気に頼まない。
  • 動かして直す … 実際にブラウザで動かし、ズレた挙動をそのままAIに伝えて修正する。
  • 権限は最小限に … Chrome拡張のマニフェストでは、対象URLと必要な権限だけに絞る。AIの初稿は権限を盛りがちなので、ここは自分でレビューする。

技術的な正しさ(マニフェストの書式、クリップボードAPIの作法)はAIが面倒を見てくれるので、私は「何が欲しいか」と「権限・セキュリティの妥当性」に集中できます。

小さく作る価値

これらは派手なツールではありません。が、自分が毎日使うものを、自分で改善できるという感覚は、想像以上に効きます。「面倒だな」と思った瞬間に「じゃあ直すか」と動ける。その回転の速さこそ、AI時代の開発者の強みだと思っています。

そして、自分のために作った小さなツールは、たいてい隣の人も同じ不便を抱えています。チームに配ると、ちょっとした感謝とともに広がっていきます。

おわりに

「ツールを作るほどではない」——その基準を、一度見直してみてください。AIと一緒なら、その「ほど」のラインはかなり下がっています。今日あなたが「地味に面倒」と感じた作業は、もしかすると30分で道具にできるかもしれません。

まずはChrome拡張1個、ボタンを1つ足すところからどうぞ。自分の手で日々の不便を潰す感覚は、なかなかクセになります。

参考リンク


※ 本記事は社内での取り組みを一般化して紹介しています。ツールは個人運用のもので、社内固有のホスト名・チケット番号は例示・抽象化しています。