5.1さらうどん

@giginetの技術ブログ。ゲーム開発、iOS開発、その他いろいろ

WezTermの組み込みMultiplexerでClaude CodeのAgent Teamsを起動する

WezTermでTeamが動いた!!!

開発環境現状確認にも書いたとおり、MultiplexerとしてtmuxではなくWezTerm + 標準のMultiplexerを使っている。

良い感じに動いているが、唯一の弱点として、Claude CodeのTeam機能がPaneを開いてくれない問題がある。解決できたので記事にしておく。

tmuxのshimsを作る

Claude Code自身に解決を頼んだところ試行錯誤して作ってくれた。結論としては簡単で、WezTerm内でtmuxコマンドを叩いたときにwezterm cliを代わりに実行する薄いshimsを書くだけだった。

github.com

最後に忘れずに.claude/settings.jsonteammateModetmuxにする(標準はauto)。

{
  "teammateMode": "tmux"
}

メチャクチャニッチだけど、同じ環境の人はぜひ参考にしてみてください。これZellijユーザーとかにも応用利きそう。

追記: PATHの優先順位に注意

上記のコミットに加え、単に.zshrcでPATHを書き換えてもWEZTERM_PANEが読めず、本物のtmuxが優先されてしまうことがあった。

おそらく実行順序の問題なので、.zshenvに以下を追加して、shimsが確実に優先されるようにしたら直った。

export PATH="$HOME/.bin:$PATH"

AIエージェントでポートフォリオを作ろう!

前から登壇やメディアでの露出、会社のブログ記事の執筆などの情報をまとめたペライチのページを作りたかった。 また、技術顧問などのポジションの募集は常にしているため、レジュメ的なものが欲しかったのもある。

作ろうと思いつつ、残念ながらWebデザインは大昔に諦め、最近のWebフロントの技術全般にも疎いため腰が重く、なかなか手を付けられずにいた。世の中に無数にあるStatic Site Generatorのうち、どれがいいんだろうなあ〜などと技術選択で悩んでたりしていたら、世はAI時代になり、そんなことを考える必要がなくなった。

結局、寝付けない日におもむろにプロンプトを打ち込んだら情報収集含めて2時間ぐらいでできた。破壊的イノベーションだ。

できたもの

ポップな感じにしてと言ったらアイコンから配色してくれた

というわけでこういうページができた。以前から押さえていて使っていなかったgiginet.meのドメインを活用できてよかった。

AI Agentを使った情報収集

今回、ポートフォリオを実装するに当たって、以下のような情報ソースをAI Agentに収集させている。

  • GitHub
  • はてなブログ(このブログ)のRSS
  • Speaker Deck / SlideShare
  • connpass
  • YouTube上の登壇動画
  • 会社の技術ブログ
  • 執筆した書籍
  • メディア掲載、イベント出演など(技術記事に載ったり、ラジオに出たり!)

後半の網羅性のない情報は、片っ端からURLを思い出して引っ張ってきて、テキストファイルに羅列した。

Perplexity MCPでエゴサする

僕は普段からPerplexity MCPを常用しており、常にuserスコープで繋いで少額突っ込んでいるのだが、今回エゴサに力を発揮した。

これによって自分が忘れていた登壇情報や、掲載記事などを引っ張ってくることができた。

昔の執筆記事もすぐに探せた

connpass APIを使った登壇情報の収集

上記の情報ソースのうち、connpassだけはWebスクレイピングを禁止しているようで、AI経由で一切情報が取得できなかった。というわけでconnpass APIを使い過去のイベント情報を一括で取得することにした。

connpassのAPI利用は、個人での使用は申請すれば数日待てばキーが発行される。あとはAPIリファレンスをSkill化したら過去の登壇情報を取得してくれた。

connpassのAPI利用について — connpassご利用ガイド ドキュメント

キーとAPIドキュメントを渡しただけ

Speaker Deckに掲載されているスライドと、上記のPerplexityによる検索と、connpass APIによるイベント情報を突き合わせることで、半自動で過去の登壇情報が完成した。

登壇の度にSpeaker Deckに上げてたのが綺麗に整理された

デザインの微調整

デザインセンスはないので、ほとんどAIにおまかせして、ガッと出してもらい、細かい点に注文を付けた。その時にPlaywright MCPを繋いでおくだけで自動でCSSを良い感じにしてくれて特にやることはなかった。これはWebデザイナーは大変な時代だ・・・・・・。

デプロイとGitHub Actionによる動的コンテンツの自動化

デプロイはGitHub Pages。DNSの設定方法も聞いたら教えてくれたので、その通りレコードを張っただけ。

ポートフォリオには、ブログの最新エントリや、GitHubのスター数が載るようになっている。ページ自体はペライチだが、GitHub Actionsで定期的にブログのRSSやGitHub APIを監視し、更新があったら自動更新するようになっている(というか特に頼んでないのにしてくれた)。この記事も一覧に載ることだろう。

ポートフォリオを作ろう!

省力化してできたので、ブログも軽く書いてみた。ぜひお試しください。

Claude CodeのSubagentとcontext: forkは何が違うのか

Claude Code機能多すぎ問題

2週間ほど前、会社のブログに「LINE iOSアプリ開発を高速化するClaude Code基盤の設計思想」という記事を書いた。

この記事では、ビルド実行のようなタスクをSubagentに分離し、高度な操作をSkillsで隠蔽する方法を紹介している。

---
name: module-builder
description: Build specific modules for the app
tools: Bash, Read, Grep, Glob
skills: creating-xcode-build-scheme
---

<!-- Subagent -->

# mobule-builder

しかし、わずかここ数週間ほどの間でcontext: forkという新たなSkillのオプションが導入された*1。これを使うと、Skill実行をメインContextからフォークした別Contextを持つエージェントに委譲できる。

---
name: building-module
context: fork
---

<!-- Skill -->

今まではSkillは全てメインエージェント上で実行されていたが、これにより、Subagent + Skillといった複雑な組み合わせを使わずとも、軽量な操作であればSkill単体で完結できるようになった。実質Subagent。

それに加えて、ContextをフォークしたSkillにもSubagentを指定する手段も提供された。agent:オプションだ。これはforkしたSkillを任意のSubagentで実行できるようにするオプション。

---
name: building-module
context: fork
agent: module-builder
---

<!-- Skill -->

すなわち、SkillをSubagent化して実行する方法に、現状3つの手段があることになる。

  1. SubagentからSkillを実行する(skills:)
  2. Skillをフォークしたコンテキストを持つサブエージェントで実行する(context: fork)
  3. Skillを指定したSubagentで実行する(context: fork + agent:)

全部同じじゃないですか!

Subagent + Skill vs context: fork

いちいちSkillとSubagentを別けて作るのは面倒だし、もはや全部context: forkで良いのでは?などと思っていたが、公式ドキュメントにそれっぽい記述があった。

これらの指定の比較。読んでもよくわからない

これを見てみてもいまいちピンとこない。Taskとは?Claude's delegation messageとは?

Skillの分類 - Reference ContentsとTask Contents

これを理解するには、どうやらスキルコンテンツの種類を知る必要があるようだ。Skillが持つプロンプトは大きくReference ContentsとTask Contentsに大別できる。

Reference Contentsは、Agentに現在の作業に適応する知識を渡すタイプのSkill。特定の作業を行う際に、プロンプトが常に読み込まれ知識として利用される。 例えば、コーディング規約やドメイン知識、スタイルガイドといった、常に知っておくべき知識が該当する。

一方でTask Contentsは、Agentに特定の作業手順を実行させるタイプのSkill。「PRを開く」とか、「特定のコードを生成する」と言った能動的に実行するタスクリストがこちらに当たり、最近Skillに統合された従来のCustom Slash Commandsはこちらに分類される。

これは、ゲームにおけるパッシブスキルとアクティブスキルのようなものだと考えると理解しやすい。

Subagentが主か、Skillが主か

このSkillの分類を理解すると、それぞれの指定の意味が見えてくる。要はSubagentとSkillのどちらを主体に据えるかという点だ。

従来のSubagentへのskill:指定は、Subagentの中にSkillの知識を展開するという挙動になる。すなわち、Reference Contentsを持ったSkillを隔離されたContextに展開し、その中で作業をさせるイメージ。

このとき、実行する操作は、SKILL.mdではなく、サブエージェントを立ち上げる際にメインエージェントから渡されるプロンプトに従うことになる。そのため、Task Contentsの実行には向かないかもしれない*2。上記の表にある"Claude's delegation message"はこのような挙動を指しているのだろう。

一方で、Skillへのcontext: forkの指定は、Skillの実行をメインエージェントから分離するために使う。Skillから新しいサブエージェントを立ち上げるという挙動になるため、逆にSkillが主となる。

上述のドキュメントにはcontext: forkでは、Reference Contentsは上手く動作しないと警告されている。Task Contentsを持つSkillにのみ適応するのが無難そうだ。

agent:の指定

agent:オプションは、Skillからサブエージェントを立ち上げる際に、そのSubagentを指定するためのオプションだ。利用例によると、サブエージェントの利用するモデルやパーミッションを細かく切り替えたい場合に使うようだが、ほとんどの場合は組み込みSubagent(Explore, Plan, general-purpose)で十分な気がする。

ここのSubagentに与えたプロンプトは、上記の表によるとシステムプロンプトと同格の扱いになるようだが、Skillの方に書く場合とどれぐらいの違いがあるかはよくわからなかった。

context: forkはTask Contentsにのみ使う

現状の使い分けとしては、Reference ContentsはSubagent + Skillを使い、Task Contentsはcontext: forkも選択肢に入る、という理解であっていそう。

これまでの話を表にざっくりまとめると以下のようになる。

Subagent + Skill context: fork context: fork + agent:
Contextの引き継ぎ 新しいContextが生成される メインContextがフォークされる メインContextがフォークされる
システムプロンプト SubagentのMarkdown 組み込みAgentのSystem Prompt SubagentのMarkdown
実行するタスク 元請けのメインエージェントが決める SKILL.md内で定義された内容 SKILL.md内で定義された内容
追加で読み込まれるプロンプト SKILL.md + CLAUDE.md CLAUDE.md CLAUDE.md + SubagentのMarkdown
向いている用途 Reference Contents。Subagentの中でルールに従って処理をさせる Task Contents。明確なTaskリストをSubagentで実行させる Task Contents。Subagentの挙動をさらに細かくカスタムしたい場合

これであってるかな?

最初の記事に戻ると、現在ではビルドのようなタスクはTask Contentsと言えるので、context: forkで十分で、「ビルド設定ファイルの編集」のような知識を伴う操作はSubagent + Skillで実装するのが良さそうだ。この場を借りてお詫びして訂正いたします*3

ほぼ日刊Claude Code

本記事は、1/27現在の最新版、2.1.20時点での情報を元にしている。

Claude Codeのアップデートは比喩ではなく日々配信されていて、もはや日刊Claude Codeの様相を呈している。数日で環境がコロコロ変わるし、キャッチアップが追いつかない!

今回の記事の内容はあまり日本語の情報を見かけたことがないので調べて役立ったし、Skillの実装やレビューも感覚でやっていたので、ちゃんとした論拠ができて良かった。公式ドキュメントはちゃんと読むものだなあ。

*1:1/8配信の2.1.1から実装されたらしい

*2:この点については定かではない。従来はcontext: forkがなかったことを考えると、Task Contentsを持ったSkillの実装もできそう

*3:社の記事を書いた段階ではcontext: forkはまだ実装されていなかった記憶