この記事は CyberAgent Developers Advent Calendar 2025 8日目の記事です。

1. はじめに

こんにちは!

CIU(CyberAgent group Infrastructure Unit) Computing & Web Serviceセクション の近藤です。普段の業務では、CyberAgent のプライベートクラウドである “Cycloud” の IaaS 基盤の開発・運用を担当しています。

IaaS 基盤と言うと、インフラ運用が中心でモダンなソフトウェア開発とは距離がある、というイメージを持たれる方もいるかもしれません。しかし Cycloud ではインフラ基盤自体も Kubernetes / OpenStack といった大規模OSSを利用して構築されていたり、独自のシステムや周辺ツールを Go / Python 等を用いて開発することも多々あり、ソフトウェア開発も盛んに行われています。

さらに最近では組織全体として AI Coding Agent (以下 AI) の利用も推進され、部分的なコード実装だけでなく、テストや Lint、レビューといった一連の開発フローを AI に任せる動きも増えており、開発スピードと品質の両立が図られています。

そこで本記事では、私が個人的に取り組んでいる 「AI を単なる “補助ツール” ではなく、一連の開発フローを任せられる “部下” として扱うための開発環境づくり」 をテーマとして、

  • AI Coding Agent を用いた開発フロー
  • それを支える開発環境をどう作っているか

について、具体例を交えて紹介していきます。

主な開発ツール一覧

  • Claude Code
  • git-worktree-runner
  • Zsh
  • Neovim
  • tmux
  • dotfiles

2. Claude Code を「AI専用コンソール」として使う

2-1. CLI ベースの開発スタイル

私は AI Coding Agent として主に Claude Code を利用しており、ターミナル上の CLI で 「AI専用コンソール」 として立ち上げています。 世の中には GUI のエディタ組み込みの AI 製品もいくつか存在しますが、私が CLI ベースの AI を好む主な理由としては:

  • ターミナル上のみへの開発環境の集約
  • 様々な環境で同じ開発体験を実現
  • ベンダーロックインの低減

といったあたりです。

私は普段の開発に tmux / Neovim を使用しており、CLI ベースの AI との親和性が高いです。GUI ベースの AI 組み込みのエディタも試してみたのですが、自分の使い方ではエディタ自体の使い勝手が合わず、生産性が落ちてしまうのを体感し、ターミナル上で完結する CLI ベースの AI と Neovim を併用するスタイルに落ち着きました。

また、ターミナル上で完結するスタイルの恩恵として、新しい PC やリモート環境でローカルと同じ開発環境をサクッと立てられることや、CLI ベースであれば他の AI とも比較的容易に切り替えできて、ベンダーロックインをある程度低減できるといったメリットも感じています。

2-2. tmux + Neovim + Claude Code

普段の開発は tmux を用いてプロジェクトごとのセッション、タスクごとのウィンドウを管理し、Neovim と Claude Code を画面分割して表示するスタイルでやっています。

tmux + Neovim + Claude Code の開発スタイル。tmuxで画面を分割し、画面上部に Neovim、下部に Claude Code を表示している。

 

tmux では以下のようなキーバインドの設定をし、vim 上のバッファー移動と同じ感覚で エディタと AIコンソールを手癖で移動できるようにしています。

tmux 側のキーバインド設定 (抜粋):

# prefix キーを C-q に変更
set -g prefix C-q

# Vim 風ペイン移動
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

 

環境によっては画面分割するとスペースが足りなくて見辛かったり、人間側で細部の修正をする際にエディタだけに集中したいようなこともあります。そのような時は tmux の Ctrl-z のキーバインドを使うことで一時的に選択したペインを全画面表示にすることができて便利なため多用しています。

3. AI に長時間タスクを任せる

ここからは、実際に AI を開発の中でどのように利用しているかや、その中で実践している生産性向上のための工夫について紹介していきます。

3-1.「頻繁すぎる AI のアウトプットレビュー地獄」からの脱却

AI に限ったことではないですが、他人のアウトプットを確認もせずにそのまま信用してはいけません。必ず別の人間が責任を持ってレビューを行うプロセスが必要になります。 とはいえ、AI が出してくる頻繁かつ大量のアウトプットを人間が全て確認したり、毎回テストを実行して実行時のログを眺め、AI にフィードバックを書いて修正させ… ということをしていては生産性は上がらず、人間が他の作業に集中して取り組むこともできません。

人間が他の作業をできず AI のレビューにつきっきりになってしまっては、むしろ最初から自分で書いた方が早かった、という経験をした方も多いと思います。

そこで私は以下のような工夫をして、AI に時間をかけてでも品質の高いアウトプットを出力させ、人間が AI のアウトプットをレビューする頻度と量を削減しています。

  1. Lint / Test / レビュー を自動で AI に実行させる
  2. 何らかのエラーが出たらその原因特定と修正まで自動でやらせる
  3. 上記をエラーが出なくなるまで繰り返させる

3-2. Makefile で「最低限の品質チェック」をコマンド化

Makefile ではなくても構いませんが、プロジェクトごとに「最低限これが通っていればレビューに出してよい」というコマンドを用意します。

Makefileの例:

.PHONY: lint
lint: ## Run linters (golangci-lint and staticcheck).
	golangci-lint run
	staticcheck ./...

.PHONY: test
test: ## Run all tests.
	go test -cover ./...

 

これらのコマンド をコードの編集後には必ず実行するように指示しておくことで、AI が最終的に提出するアウトプットが予め定めた最低限の基準を満たすことを保証できます。

AGENTS.mdでの指示例 (抜粋):

## Coding Style

### Go Code Style

...

**Formatting & Linting**: After every Go code change, run the following commands.

```bash
make fmt          # Format Go code with gofmt and goimports.
make lint         # Run linters (golangci-lint and staticcheck).
```

## Testing Guidelines

Every change must pass `make test`. ```bash make test # Run all tests. ```

3-3. Claude Code の permissions 設定

AI が自分でフィードバックループを回せるようにするためには、人間と同様に必要なツールを自動で使えるようにする必要があります。AI がツールを使うたびにいちいち手動で承認をしていては生産性など上がりません。

しかし、当然ながら任意のコマンドを AI に許可などしてはいけません。特に削除系の操作や外部システムに対して操作をする CLI ツールの使用には注意が必要です。

この課題を解決するために、Claude Code では設定ファイル (.claude/settings.json) で、承認なしで実行してよいコマンドや絶対に実行してはいけないコマンドを明示的に制御できます。

参考:CLI 設定のドキュメント
https://code.claude.com/docs/en/settings

 

プロジェクトによらず実行しても良い read 系の操作は ~/.claude/settings.json で許可し、make コマンド等のプロジェクトごとに設定したいコマンドを <PROJECT_ROOT>/.claude/settings.json で許可するようにしています。

グローバル設定 (抜粋):

{
  "permissions": {
    "allow": [
      "Bash(mkdir:*)",
      "Bash(ls:*)",
      "Bash(tree:*)",
      "Bash(grep:*)",
      "Bash(sort:*)",
      ...
      "Bash(git status:*)",
      "Bash(git diff:*)",
      ...
      "Bash(gh repo list:*)",
      "Bash(gh repo view:*)",
      ...
      "mcp__context7",
      "mcp__serena"

    ],
    "deny": [
      "Bash(sudo:*)",
      "Bash(rm -rf:*)",
      ...
    ],
    ...
  }
}

プロジェクト設定 (抜粋):

{
  "permissions": {
    "allow": [
      "Bash(make help)",
      "Bash(make fmt)",
      "Bash(make lint)",
      "Bash(make build)",
      "Bash(make test)",
      "Bash(make proto)",
      "Bash(make proto-fmt)",
      "Bash(make proto-lint)",
      "Bash(make sql-generate)",
      "Bash(make sql-fmt)",
      "Bash(make sql-lint)"
    ],
    ...
  }
}

これにより、AI が基本的なコードリーディングや編集だけでなく、自動で実行するように指示した Lint / Test といった一連の作業も人間の介入なく実行でき、AI による長時間の自律的な開発とアウトプットの品質向上を実現できます。

4. hooks とデスクトップ通知による割り込み処理

Claude Code には hooks という機能があり、セッションの状態に応じて任意のコマンドを実行できます。

参考:Claude Code Hooks reference
https://code.claude.com/docs/en/hooks

 

設定例(settings.json より抜粋):

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c \\\\"~/bin/claude_notify.sh Notification\\\\""
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c \\\\"~/bin/claude_notify.sh Stop\\\\""
          }
        ]
      }
    ]
  }
}

ここでは、AI が人間に対して何らかの指示や承認を仰いだり (Notification)、タスクが完了したタイミング (Stop) でスクリプトを呼び出しています。

 

実際に実行しているスクリプトは以下のようなものです:

#!/bin/bash
# ~/bin/claude_notify.sh

TYPE="$1"
INPUT="$(cat -)"

# 作業ディレクトリ
WORKDIR=$(echo "$INPUT" | jq -r '.cwd')

# transcript から最後の assistant メッセージを取得
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path')

MSG=""
if [[ -n "$TRANSCRIPT_PATH" && "$TRANSCRIPT_PATH" != "null" ]]; then
    JSON="$(tac "$TRANSCRIPT_PATH" | jq -rn '
        inputs
        | select(.message?.role? == "assistant")
        | select(.message?.content?[0]?.text != null)
        | (., halt)
    ')"
    if [[ -n "$JSON" && "$JSON" != "null" ]]; then
        MSG="$(echo "$JSON" | jq -r '.message.content[0].text')"
    fi
fi

osascript -e "display notification \\\\"$MSG\\\\" \\\\
    with title \\\\"Claude Code ($TYPE)\\\\" subtitle \\\\"$WORKDIR\\\\""

 

hooks で定義した command には session のメタデータを含む json 形式の文字列が標準入力で渡されます:

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Notification",
  "message": "Claude needs your permission to use Bash",
  "notification_type": "permission_prompt"
}

参考:Claude Code Hooks reference
https://code.claude.com/docs/en/hooks#notification-input

 

この中から session の詳細情報を含むファイルパスが格納されている transcript_path を抽出します。そのファイルの中身もまた複数の json 文字列になっているため、中身をこねくり回してプロジェクトのパスや最後のメッセージを取り出し、デスクトップ通知として表示させます (ちなみに音も鳴ります)。

Claude Code デスクトップ通知。 タイトル:Claude Code (Notification) サブタイトル:(~/dev/test-worktrees/feature01) 内容:The file doesn't exist anymore. Let me create it again.

 

これにより、AI に長時間のタスクを任せている間は別の作業をしておき、通知が来たタイミングで AI のセッションに戻る、という人間側の負荷が少ない開発フローを実現できます。

5. git worktree × Claude Code で並列タスクを回す

5-1. git worktree を用いた開発スタイル

同じリポジトリで複数のタスクを並列に進めたい場面は多いです。

  • 0 → 1 の開発で設計書を元に複数コンポーネントを同時に開発させる
  • 機能追加をしながらリファクタリングも行う

このような場合、同じブランチで複数の作業を進めてしまうと PR の粒度が大きくなってしまってレビュー負荷が高くなったり、AI が把握するコンテキストが汚れてアウトプットの品質が低下するといったデメリットがあります。

そのため私は git worktree を用いてタスクごとにブランチ・ディレクトリを分割し、複数タスクを並列で AI に実行させる開発フローをとっています。

git worktree を使うことで、

  • ブランチごとに独立したディレクトリを作成
  • 各 worktree で独立した Claude Code セッションを起動

のような形にタスク単位で AIセッション を分離することができます。

5-2. git-worktree-runner の活用

git worktree は標準機能だけで使うこともできるのですが、worktree 用のディレクトリの管理や AIセッション へのシームレスな移動の手間が大きいです。

そこで私は CIU の AI推進チーム の方に教えてもらった git-worktree-runner を活用しています。

主な機能:

  • worktree の作成・削除
  • worktree 用のディレクトリ管理
  • worktree 上での AI Agent 実行

参考:git-worktree-runner
https://github.com/coderabbitai/git-worktree-runner

 

これをを導入することで、

  • git gtr new <branch> で worktree 作成
  • git gtr ai <branch> でその worktree に対応した Claude Code セッション起動

といった操作が一コマンドで実行できるようになり、タスク・worktree・AIセッション 間の紐付けを手軽に実行することができます。

5-3. シェル関数によるラッパー

git-worktree-runner 単体でも十分に便利なのですが、いちいち複数のサブコマンドを打ったりするのは正直ちょっと面倒です。

そのため、 よくあるユースケースをラッパーのシェルの関数として定義して簡単に実行できるようにしています。

# worktree 一覧
function gls {
    local branch="$1"
    git gtr list "$branch"
}

# worktree に移動
function gcd {
    local branch="$1"
    if [[ "$branch" == main || "$branch" == "" ]]; then
        cd "$(git worktree list | grep -E '\\[main\\]$' | awk '{print $1}')"
    else
        cd "$(git gtr go "$branch" 2>&1 | tail -n1)"
    fi
}

# worktree 作成+ Claude Code 起動
function gai {
    local branch="$1"

    if [[ "$branch" == "main" ]]; then
        echo "Cannot use 'main' as worktree branch. Specify a feature branch." >&2
        return 1
    fi

    if ! git gtr list | grep -Eq "^$branch"; then
        echo "Worktree '$branch' does not exist. Creating new worktree." >&2
        git gtr new "$branch"
    fi

    git gtr ai "$branch"
}

例えば gai feature/new-api のように打つだけで、

  1. worktree 作成
  2. 対応する Claude Code セッション起動

まで一気に実行したり、gcd feature/new-api で作成した worktree に移動したり、gcd main で大元の main ブランチに簡単に移動することができます。

 

gai コマンドの利用例:

gai コマンド (その1)。gls コマンドで Git Worktrees を一覧し、gai feature01 コマンドで feature01 worktree 上に AIセッション を起動。

gai コマンド (その2)。gai コマンドにより指定した worktreeで Claude Code セッションが起動している。

6. dotfiles による 設定の一元管理とセットアップ

これまで様々な設定やスクリプトを紹介してきましたが、新しい PC やリモートサーバー環境でこれら全ての設定を毎回一から構築するのは正直かなりの手間です。それだけで日が暮れてしまいます。

そのため、”dotfiles” を使うことでそれらの管理とセットアップを行なっています。

参考:ようこそdotfilesの世界へ
https://qiita.com/yutkat/items/c6c7584d9795799ee164

 

dotfiles 構成 (抜粋):

.
├── bin
│   ├── claude_notify.sh    # デスクトップ通知スクリプト
│   ├── git-gtr             # git-worktree-runner
├── claude
│   ├── agents              # subagents管理
│   ├── assets              # AI用のリファレンス等
│   ├── commands            # custom slash command
│   ├── skills              # skill管理
│   ├── CLAUDE.md           # グローバルのインストラクション
│   └── settings.json       # グローバル設定
├── tmux                    # tmux 設定
└── setup.sh                # 環境セットアップスクリプト

 

新しい環境でも、dotfiles のリポジトリを clone してきてセットアップスクリプトを実行するだけでサクッと普段と同様の開発環境を実現できます。下記は各設定ファイルやスクリプトを環境で使えるようにするためのシンボリックリンクを貼る処理の例です。

~/dotfiles/setup.sh (抜粋):

#!/bin/bash

PAIRS=(
    "$PWD/bin:$HOME/bin"
    "$PWD/claude/settings.json:$HOME/.claude/settings.json"
    "$PWD/claude/CLAUDE.md:$HOME/.claude/CLAUDE.md"
    "$PWD/claude/commands:$HOME/.claude/commands"
    "$PWD/claude/agents:$HOME/.claude/agents"
    "$PWD/claude/skills:$HOME/.claude/skills"
    "$PWD/zsh/.zshrc:$HOME/.zshrc"
    "$PWD/zsh/.zsh_aliases:$HOME/.zsh_aliases"
    "$PWD/zsh/.zsh_functions:$HOME/.zsh_functions"
    "$PWD/tmux/.tmux.conf:$HOME/.tmux.conf"
)

for PAIR in "${PAIRS[@]}"; do
    SOURCE_PATH="${PAIR%%:*}"
    TARGET_PATH="${PAIR##*:}"

    if [ -e "$TARGET_PATH" ]; then
        echo "'$TARGET_PATH' already exists. Skip."
        continue
    fi

    TARGET_DIR="$(dirname "$TARGET_PATH")"
    mkdir -p "$TARGET_DIR"

    ln -s "$SOURCE_PATH" "$TARGET_PATH"
    echo "Created symbolic link: $TARGET_PATH -> $SOURCE_PATH"
done

 

このように、開発環境に関わる設定やスクリプトをすべて dotfiles に集約しておくことで、どのマシンでも短時間で同じ開発体験を再現でき、AI Coding Agent を含めた「自分仕様の開発フロー」を再現性高く持ち運べるようにしています。

7. まとめ

この記事では、AI Coding Agent を単なる “補助ツール” ではなく、長時間のタスクを任せられる “部下” として扱うことを目指した開発環境や、生産性向上のための工夫を紹介しました。

  • 「Lint・Test・CI チェックのループ」を AI に自動実行 させることで、AI による低品質のアウトプットの抑制と、人間が頻繁にレビューをする手間を削減。
  • hooks 機能によるデスクトップ通知の仕組みを整え、AI の長時間タスクの完了や入力待ちを人間がポーリングするのではなく割り込みで検知。
  • git-worktree-runnerシェル関数 を組み合わせて、AI によるシームレスな複数タスクの並列実行を実現。
  • これらの設定やスクリプトを dotfiles に集約し、新しいマシンやリモート環境でも同じ開発体験を素早く再現。

様々な工夫を紹介してきましたが、重要なポイントは AI を 一定の品質基準と開発フローを自律的にこなしてくれる“部下” として扱えるよう、常に開発環境をブラッシュアップし続けていくことです。各個人にとっての理想の環境は一朝一夕で作れるものではありません。継続的に育てていくという意識が重要です。

今後は個人での開発環境の継続的な整備はもちろん、組織としての AI 開発フローの基盤作り、運用への AI の導入 (いわゆる AIOps) も引き続き進めていきたいと思います。

本記事の内容が、読者の AI Coding Agent を用いた開発への第一歩になれば幸いです。最後まで読んでいただきありがとうございました。

アバター画像
2024年度新卒エンジニアでCIUに所属し、プライベートクラウドのIaaS基盤の開発・運用に従事。OpenStack、Kubernetes等のインフラ基盤の運用はもちろん、GoやPythonを使ったソフトウェア開発も好き。 Cloud Operator Days 2025 クロージングイベント 登壇。