「記事は読んだけれど、実際に自分の手で動かすと、どこで詰まるのか分かりません」
「いきなり本番のリポジトリで試すのは怖いです。安全に試せる練習台はありませんか」
Claude Code は、読んだだけでは身につきません。計画を読んで1か所直す、差分を読んで指摘する、巻き戻す、確認の画面で「常に許可」を選ぶ。1度でも自分で操作すると、第1〜7回の内容が自分の手の感覚になります。
第8回と第9回は、この連載の演習です。自分専用の環境に練習用のリポジトリを作り、手順1〜6を順に試します。全体で約30分です。前編の第8回では、準備(環境・モデルとモード・準備プロンプトの全文)と、手順1〜3(CLAUDE.md の下書き、プランモードでの計画、実装と検証)を扱います。手順4〜6、早く終わったら、4D での振り返り、自己点検、連載の結びは、後編の第9回です。各手順の後には、「筆者の環境ではこうなった」の囲みを載せます。
この回でやること
演習は、自分の環境に練習用のリポジトリ(~/practice)を作り、第1〜7回の内容を一度ずつ手で確かめます。流れは次の図のとおりです。前編(この回)は準備から手順3まで、手順4以降は第9回です。

演習の画面は、Claude デスクトップアプリの Code タブを前提に書きます。CLI の操作は「CLI では」と添えます。数値と仕様は2026年10月時点です。
筆者の記録の読み方
各手順の後に、「筆者の環境ではこうなった」の囲みを付けます。筆者が試した記録は2種類あります。
- 記録A:2026-10-18。筆者の PC(Ubuntu 26.04.1)、Claude Code 2.1.289 の CLI、ansible-core 2.20.1、ansible-lint、個人のアカウント。フォルダーは
~/practice(Code タブの「ローカル」に当たる)。対話の画面ではなく、非対話のclaude -pで、権限モードを--permission-modeで指定し、--resumeで同じ会話を続けて試した - 記録B:2026-10-04。筆者の Code タブ(Claude Code 2.1.284)で確かめたもの。
/rewindと「常に許可」は、-pでは試せないので、こちらの結果を使う
確認の画面が出る操作は、-p では「承認が要る」として実行されずに終わります(Code タブなら確認の画面が出る所です)。囲みで「承認が要って止まった」とあるのは、この意味です。公式の headless のページにも、承認が要る操作は拒否される、という趣旨の記述があります(--permission-prompts none の説明)。
Code タブと CLI の操作の対応は、次のとおりです。
| 操作 | Code タブ | CLI(対話) | -p(筆者の記録A) |
|---|---|---|---|
| モードの切り替え | 入力欄の下の表示から切り替える(第2回の「Codeタブでのプランモード」) | Shift+Tab(第2回の「Codeタブでのプランモード」の「CLI では」) | --permission-mode(default・acceptEdits・plan・auto・dontAsk・bypassPermissions。manual は default の別名) |
| プランの承認 | 計画を読んで、承認のボタンで実装に進む | 画面で承認して実装に進む | ボタンが無く、「この内容でよければ実装に進む」と返ってくる |
| 差分を見る | 増減の行数の表示(+12 -1 など)か Ctrl+Shift+D で差分ビュー(第7回の「Codeタブの差分ビュー」) | /diff、または git diff | git diff |
| 巻き戻し | 入力欄が空のときに Esc 2回(第3回の「巻き戻しメニュー」) | Esc 2回、または /rewind | 試せない |
| 確認の画面の「常に許可」 | 選択肢に「常に許可」(.claude/settings.local.json に保存) | 「Yes, and don’t ask again」に当たる選択肢 | 承認が要るものは拒否される |
出典:https://code.claude.com/docs/en/best-practices 、https://code.claude.com/docs/en/permissions
費用の目安は、後編の第9回にまとめて載せます。
準備
環境を選ぶ
環境は2択です。自分専用の検証用ホストに SSH で接続するか、手元の Linux・macOS の「ローカル」で行います。どちらも自分専用の環境で行い、本番や共用のホストは使わないでください。Claude は、あなたのユーザーの権限で操作します。
SSH の検証用ホスト
- 用意するもの:自分専用の検証用ホスト(手元の VM など)。SSH の鍵でログインできること。公式の説明では接続先は Linux・macOS・Windows ですが、Ansible を動かすので、この演習は Linux か macOS のホストで行う
- 接続の追加:Code タブで新しいセッションを始める前に、入力欄の下の環境のメニューを開き、いちばん下の「New environment」を選ぶ。開いた画面の「SSH」のタブで「Host」の一覧から「Add SSH connection…」を選ぶ(公式の英語の説明。日本語の画面の表示は筆者は確かめていない)。SSH host に
ユーザー@ホスト名(または~/.ssh/configに書いたホストの名前)、鍵のパス(公式の画面では「SSH key (optional)」。例:~/.ssh/id_ed25519)を入れて「Add SSH connection」を選び、ホストのフォルダーを選んで「Create environment」を押す。初回は、ホストに Claude Code が自動で入る - 入力欄の下に環境のメニューが無いときは、前の画面の作り(デスクトップアプリが v2.37337.0 より古い)です。公式は、アプリを更新するよう案内している
- 筆者は、個人のアカウントでこの SSH 接続を確かめていません。公式の SSH の節には、Pro・Max で使えるかどうか、preview(試験提供)の表示があるかどうかの記載が見つかりませんでした。SSH の環境を作れない場合は、次の「ローカル」で試してください
- SSH の鍵と
~/.ssh/configは、連載「SSH入門」第5回の「ssh-keygen で鍵を作る」、第7回の「~/.ssh/config の例と ssh -G」と「鍵の登録(ssh-copy-id)」を参照
手元の Linux・macOS の「ローカル」
- Ansible が手元に入っていれば、「ローカル」でも同じ手順を試せる。筆者の記録Aは、この形(CLI)
- Claude デスクトップアプリの Linux 版は、公式の説明ではベータ。Debian 系でない Fedora・Arch などでは、公式は CLI を使うよう案内している(https://code.claude.com/docs/en/desktop-linux )
- Windows の人:公式は、WSL 2 なら Windows のデスクトップアプリで、ディストリビューションの中のセッションを動かすよう案内している。筆者は WSL で同じ手順が通るかを確かめていない。Local・WSL・SSH・Cloud の違いは、連載「Claude活用入門」第2回の「どこで動くか」を参照
入れるもの
ホスト(かローカル)に、ansible-core と git、できれば ansible-lint も入れておきます。
# RHEL系
$ sudo dnf install -y ansible-core git
# Ubuntu
$ sudo apt install -y ansible git
ansible-lint は、Ubuntu 26.04 ではパッケージ(ansible-lint)があります。RHEL 系の入れ方は、筆者は確かめていません。筆者の環境(Ubuntu 26.04.1)は、ansible-core 2.20.1 でした(記録A)。
モデルとモード
練習用のリポジトリを開いた新しいセッションで、最初のプロンプトを送る前に、入力欄の下の表示を「手動」・既定のモデル(Opus 5.5)・Effort は中にします。
- モデルと Effort:第1回の「モデルとEffortの選び方(公式の推奨)」のとおり、公式の既定(Opus 5.5・Effort medium)から始めます。うまくいかなければ、モデルを替えずに Effort を high に上げて比べます。筆者の記録Aも、モデルを指定せずに起動して Opus 5.5 でした。使用量の枠が気になる Pro の人は、Sonnet 5.5 でもかまいません(連載「Claude活用入門」第3回の「作業別の設定の例(筆者の例)」)
- モードは最初に「手動」にする:v2.1.283 以降、CLI と VS Code では新しいセッションが「自動」(auto mode)から始まります(連載「Claude活用入門」第5回の「権限と auto mode」)。筆者の個人のアカウントの Code タブでも「自動」から始まりました(第5回の「Code タブでの権限の操作」)。演習は、確認の画面を見るために「手動」から始めます
準備プロンプト
次のプロンプトを、自分の環境のセッションに送ります。Claude が ~/practice に、NTP の role・stg と prod のインベントリ・第6回の「Ansibleの作業での設定例(筆者の例)」と同じ権限設定を持つ練習用のリポジトリを作ります。

使い方
- 自分の環境(作った SSH の環境、または「ローカル」)で新しいセッションを作る。フォルダーはホームにする
- モードを「編集を受け入れる」にして、下のプロンプトをそのまま送る
.claude/settings.jsonの書き込みは確認が出るので、内容を見てから「一度だけ許可」を選ぶ- 終わったら、
~/practiceを開いた新しいセッションで、手順1を始める
送るプロンプト
練習用のリポジトリを作ってください。内容は書いてあるとおりにし、省略や変更はしないでください。
1. ~/practice を作り、次の各ファイルを、記載の内容そのままで作る
2. ~/practice で git init し、全ファイルをコミットする(user.name=practice、user.email=practice@example.invalid)
3. 最後に git log --oneline と、ansible-playbook --version 2>&1 | cat の1行目を報告する
--- ファイル: .claude/settings.json ---
{
"permissions": {
"allow": [
"Bash(ansible-lint *)",
"Bash(ansible-inventory *)",
"Bash(ansible-playbook --syntax-check *)",
"Bash(ansible-playbook --check --diff *)",
"Bash(git diff *)",
"Bash(git status *)"
],
"ask": [
"Bash(ansible-playbook * inventory/prod*)",
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./**/vault_pass*)",
"Bash(ansible-vault decrypt *)",
"Bash(ansible-vault view *)"
]
}
}
--- ファイル: .gitignore ---
.env
vault_pass.txt
.claude/settings.local.json
.ansible/
--- ファイル: site.yml ---
- name: NTPの設定
hosts: ntp
become: true
roles:
- ntp
--- ファイル: inventory/stg/hosts.ini ---
[ntp]
stg-server01 ansible_host=192.0.2.11
--- ファイル: inventory/prod/hosts.ini ---
[ntp]
prod-server01 ansible_host=192.0.2.21
--- ファイル: roles/ntp/tasks/main.yml ---
- name: chronyの参照先を設定する
ansible.builtin.lineinfile:
path: /etc/chrony.conf
regexp: '^server '
line: "server ntp1.example.jp iburst"
--- ファイル: .env ---
DUMMY_TOKEN=this-is-a-dummy-value
--- ファイル: vault_pass.txt ---
dummy
roles/ntp/tasks/main.yml は、参照先が1台(ntp1.example.jp)のままです。手順2で、これを3台にします。NTP の時刻源を何台にするかは、連載「NTP入門」第3回の「何台の時刻源を使うか」を参照してください(2台は1台と大差ない、という話です)。
読者向けの注意
- ホストのアドレスは文書用の 192.0.2.x(RFC 5737 の TEST-NET-1。文書用に確保された範囲)です。そのため、
--check --diffや本実行は、ホストに接続できず unreachable で終わります。この演習の目的は、権限の確認画面・計画・差分・巻き戻しの動きを見ることです - Claude Code から ansible 系のコマンドを実行すると、「Ansible requires blocking IO」で止まることがあります(筆者は Code タブと CLI の
claude -pの両方で確認しました)。2>&1 | catを付けるか、出力をファイルにリダイレクトすると動きます。終了コードはcatの0になるので、成否は PLAY RECAP で判断させてください。端末から自分で打つときは起きませんでした。公式の ansible-core の文書や Claude Code の issue では、この現象の記述を見つけられていません - ansible-lint を実行すると、
chronyの参照先を設定するというタスク名がname[casing]で指摘されます。筆者の実測では、この規則が指摘するのは英小文字で始まる名前(chrony…)で、日本語の文字で始まる名前は指摘されません(第4回の「補足:日本語のタスク名と ansible-lint の name[casing]」)。結果は、手順3の囲みと第9回の「早く終わったら」に載せます .envとvault_pass.txtはダミーです。Read(./.env)などの deny ルールの確認に使います
筆者の環境ではこうなった(記録A:準備)
ホームのフォルダーで、準備プロンプトをそのまま送った(--permission-mode acceptEdits)。
確認が要ったもの:.claude/settings.jsonの書き込み、git init・git config・git add・git commit、ansible-playbook --version。ほかのファイルは確認なしで作られた。git のコマンドも、「編集を受け入れる」では確認が出た(受け入れるのはファイルの編集だけ)。
Claude は、「全ファイルをコミット」と指示しても、.envとvault_pass.txtは.gitignoreに入っているのでコミットされない、と気づいて、それでよいかを聞いてきた。それで正しい(ダミーの秘密を Git に入れない練習にもなる)。
コミット後のgit ls-files:.claude/settings.json、.gitignore、inventory/prod/hosts.ini、inventory/stg/hosts.ini、roles/ntp/tasks/main.yml、site.yml。ansible-playbook --versionの1行目はansible-playbook [core 2.20.1]。
CLI だけの注意:初めてのフォルダーを「信頼」する前は、.claude/settings.jsonの allow のルールが無視された(表示:Ignoring 6 permissions.allow entries from .claude/settings.json: this workspace has not been trusted.)。対話の画面で一度開いて、信頼の確認に答えると効く。
手順1〜6
手順1〜3の表と、各手順の後の筆者の記録です。手順4〜6と「早く終わった人」は、第9回で扱います。
| 手順 | やること | 確認すること |
|---|---|---|
| 1 | /init で CLAUDE.md の下書きを作り、第4回の「書くこと・書かないこと」の「書かない」に当たる行を削る | 何行になったか。/context の Memory files に出ているか |
| 2 | 「プラン」モードで「NTPの参照先を3台にする」計画を出させ、計画を読んで1か所直させる | 計画にない変更や、検証の手順の欠けがないか |
| 3 | 「編集を受け入れる」に切り替えて実装させ、ansible-lint と –check –diff まで実行させる | 実行したコマンドと結果(証拠)を見せたか |
手順1:/init で CLAUDE.md を作り、書かないことを削る
~/practice を開いた新しいセッションで /init を実行し、第4回の「書くこと・書かないこと」の「書かない」に当たる行を削ります。最後に /context の Memory files を確かめます。
筆者の環境ではこうなった(記録A)
/initの下書きは37行(英語で書かれた)だった。中身は、概要(ansible.cfg が無いので-iが要る)、ファイルごとの説明(site.yml・roles/ntp/tasks/main.yml・2つのインベントリ)、「タスク名は日本語」、コマンド5つ(lint、syntax-check、ansible-inventory --graph、--check --diff、--limitの例)、安全のルール(settings.json の説明、.env を読まない)。
筆者が削ったもの(15行):/initの定型の前置き、ファイルごとの説明(読めば分かる)、ansible-inventory --graphと--limitの例(一般的な使い方)、settings.json の中身の説明(ファイルを読めば分かる・設定が強制する)。
残したもの:-iが必須なこと(推測できない)、stg と prod は-iのパスだけで決まること(落とし穴)、lineinfileは最後に一致した1行だけ置き換えること(落とし穴)、タスク名は日本語(標準と違う規約)、コマンド3つ(lint・syntax-check・stg への--check --diff)、完了の定義(stg で--check --diffしてから prod を提案)、.env と vault_pass.txt を読まないこと。
結果は37行から22行。/contextの Memory files の欄には、Project ~/practice/CLAUDE.md 290(トークン)と出た。コンテキスト全体は 26k / 1m(3%)だった。
最初に2台で試した回(1回目)は Claude の返答が英語になり、3台の回(2回目)は日本語だった(CLAUDE.md を英語のまま残したためかもしれないが、確かめていない)。
手順2:「プラン」モードで計画を出させ、1か所直させる
モードを「プラン」にして「NTPの参照先を3台にしてください。」と頼み、計画を実際に読んで1か所直させます。承認は直した後です。
筆者の環境ではこうなった(記録A)
「NTPの参照先を3台にしてください。」をプランモードで送ると、ファイルは何も変えず、計画(~/.claude/plans/の md)を書いた。
計画の中身:roles/ntp/defaults/main.ymlにntp_servers(ntp1〜ntp3.example.jp)を作る。タスクを2つにする。①replaceで、リストに無いserver行を削除する「管理対象外のserver行を削除する」、②lineinfileをloopで回し、サーバーごとに自分の行だけを対象にserver <host> iburstを置く。どちらも冪等。pool行は触らない。確認は stg で lint → syntax-check →--check --diff、prod はその後に提案。
Claude は自分から、「3台のホスト名は?(仮に ntp1〜ntp3.example.jp)。stg と prod で違うなら対応表を」「設定を変えたときに chronyd を再起動する handler を足すか?」と聞いてきた。また、lineinfileは最後に一致した1行しか置き換えない、という落とし穴を計画の前提に書いていた(手順1で CLAUDE.md に残した行)。
筆者が直させた1か所:①の削除のタスクは、依頼(参照先を3台にする)に無い変更なので外させた。計画にない変更の例。本番で既存のserver行を消すのは、別の変更として扱うべき。ホスト名は仮のまま、handler は今回は足さない、と答えた。
直した後の計画は、タスクを1つのままloopにする(regexpは'^server {{ item | regex_escape }} ')。「削除のタスクを外したので、ほかの server 行・pool 行があれば残り、参照先は3台より多くなる。stg の--check --diffで分かるので、そこで報告する」と明記された。-pにはプランの承認のボタン(ExitPlanMode)が無く、「この内容でよければ実装に進む」と返ってきた。画面なら、承認のボタンで進める。
最初に2台で試したときも流れは同じで、2回とも、頼んでいない削除が計画に入った。
手順3:「編集を受け入れる」で実装させ、lint と –check –diff まで
「編集を受け入れる」に切り替えて実装させ、ansible-lint と --check --diff まで実行させて、コマンドと結果(証拠)を見せさせます(第7回の「Ansibleでの検証の型」の①〜③)。
筆者の環境ではこうなった(記録A)
実装の差分は、roles/ntp/tasks/main.ymlの変更と、新しいroles/ntp/defaults/main.yml(ntp_serversに ntp1.example.jp・ntp2.example.jp・ntp3.example.jp)。下の「roles/ntp/tasks/main.yml の差分」を参照。
Ansible が「Ansible requires blocking IO on stdin/stdout/stderr」(stderr がノンブロッキング)で起動しなかった。Claude が自分で回避した。</dev/null 2>&1 | catを付ける、出力をファイルにリダイレクトする(> …/*.log 2>&1 < /dev/null)、の2通りで回避した。CLI(-p)でも起きた。回避の仕方は毎回同じとは限らない。CLAUDE.md の「環境の癖」に書いておく価値がある。
確認が要って止まったもの:ansible-lint; echo "exit=$?"のように、終了コードをechoで表示するコマンド。allow のルール(Bash(ansible-lint *))があっても確認になった(-pでは拒否)。Claude は、その後、別の形で実行し直した。追加の実測(2026-10-18、--permission-mode default)では、ansible-lint --version; echo doneとansible-lint --version && echo okは確認なしで実行され、echo "exit=$?"を付けたものだけが止まった。筆者の実測では、echoやつなぎ方ではなく、$?の展開が原因と見られる(公式の裏付けは見つけていない。第6回の「前方一致の落とし穴と、denyの限界」)。
報告の最初の段落で、「stg への--check --diffは接続できず、実際の差分はまだ確認できていない」「lint も1件で不合格」と書いた(「できました」で終わらない)。「残っていること」に、stg での差分確認、prod は stg の確認まで提案しないこと、lint の抑止は必要なら、を挙げた。コミットはしなかった。
Claude が見せた証拠は、次の3つです。
$ ansible-lint
(終了コード 2、違反1件)
name[casing]: All names should start with an uppercase letter.
roles/ntp/tasks/main.yml:1:9 Task/Handler: chronyの参照先を設定する
Failed: 1 failure(s), 0 warning(s) in 4 files processed of 9 encountered.
$ ansible-playbook --check --diff -i inventory/stg/hosts.ini site.yml
(終了コード 4)
fatal: [stg-server01]: UNREACHABLE! => {"msg": "... ssh: connect to host 192.0.2.11 port 22: Connection timed out"}
stg-server01 : ok=0 changed=0 unreachable=1 failed=0
$ ansible-playbook --syntax-check -i inventory/stg/hosts.ini site.yml
playbook: site.yml
Claude は、lint の指摘について「タスク名は変更前と同じなので、前から出ていたはず。CLAUDE.md の『タスク名は日本語』とぶつかるので直していない。.ansible-lint の skip_list で抑止できる」と説明しました(指摘の理由は、タスク名が英小文字の chrony で始まるためです。上の「読者向けの注意」)。stg への --check --diff については「192.0.2.11 はドキュメント用のアドレス(TEST-NET-1)で届かない」と説明しました。3つ目の構文確認は、Claude が自分で追加して実行したものです。
roles/ntp/tasks/main.yml の差分は、次のとおりです。
- name: chronyの参照先を設定する
ansible.builtin.lineinfile:
path: /etc/chrony.conf
- regexp: '^server '
- line: "server ntp1.example.jp iburst"
+ regexp: '^server {{ item | regex_escape }} '
+ line: "server {{ item }} iburst"
+ loop: "{{ ntp_servers }}"
考えてみよう
- 準備プロンプトが作る
.claude/settings.jsonで、ansible-playbook --check --diffは allow、prod のインベントリを指す実行は ask になっています。第6回の「ルールは前方一致」の考え方で、ansible-playbook site.yml --check --diffはどちらに当たるでしょうか。どちらにも当たらないなら、どう扱われますか。 - 手順2の計画に、頼んでいない変更(既存の
server行の削除)が入っていたら、どう直させますか。第2回の「計画は「実際に読む」」の考え方で答えてみてください。 - 手順3で、Claude の報告が「できました」だけだったら、何を見せさせますか。
ヒント:1つ目は第6回の「ルールは前方一致」、2つ目は手順2の囲み、3つ目は第7回の「要約ではなく差分から読む」を見直してください。
まとめ
- 演習は、自分専用の環境(SSH の検証用ホストか「ローカル」)で、準備プロンプトが作る練習用のリポジトリで行う。本番や共用のホストは使わない
- 始めは「手動」・既定のモデル(Opus 5.5)・Effort 中。うまくいかなければ、モデルを替えずに Effort を上げて比べる
- 手順1:
/initの下書きを読み、書かないことを削る(筆者は37行から22行) - 手順2:プランモードで計画を読む。筆者の環境では頼んでいない削除が計画に入ったので、外させた
- 手順3:実装させ、lint と
--check --diffのコマンドと結果を見せさせる。ansible 系のコマンドは2>&1 | catかファイルへのリダイレクトが要ることがある
次回の第9回は、手順4から続けます。巻き戻し、差分のレビュー、権限の「常に許可」を試し、4D で振り返ります。
連載「Claude Code実践入門」全9回
- 任せる前に知っておくこと
- 作業範囲を決める
- 走らせながら操縦する
- CLAUDE.mdを育てる
- 権限モードとauto mode
- allow・ask・denyのルールと設定ファイル
- 検証で終わらせる
- 演習(前編):準備から実装と検証まで(この記事)
- 演習(後編):巻き戻し・差分・権限と振り返り


コメント