Phonebook について
Phonebookは、既存のSwiftUI `#Preview`とJetpack Compose `@Preview`から静的ギャラリーを作るセルフホスト可能なコマンドラインツール兼MCPサーバーです。UIプレビューをデザイナーと共有するアプリチーム向けに、各プラットフォームのレンダリング機能を利用します。
主な機能
- 01既存のUIプレビューを再利用
- 02静的HTMLギャラリーの生成
- 03コンポーネントと状態ごとのカード分類
- 04Android・iOSのレンダリング手順
- 05セットアップとプレビュー範囲の確認
活用シーン
- 01アプリのプレビュー画面をデザイナーと共有
- 02プレビューやダーク表示が不足したコンポーネントの特定
- 03変更ファイル内のプレビューだけを再生成
MCP 対応
`npx @stag-build/phonebook mcp`でPhonebookのMCPサーバーを起動します。ツールを通じてコーディングエージェントがセットアップ確認、プレビュー範囲の分析、ガイダンス取得、生成、ギャラリー構築を行えます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
5掲載時のツール一覧 · 1 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| dir | string | いいえ | phonebook.config.jsonを含むプロジェクトディレクトリ |
| paths | array | いいえ | これらのファイルまたはディレクトリ内で宣言されたコンポーネントのみを報告します。パスはプロジェクトディレクトリを基準とします。プロジェクト全体は引き続きスキャンされます。 |
| changed | boolean | いいえ | 未コミットのgit変更があるファイル内のコンポーネントのみを報告します。つまり、直前に編集した内容です。gitリポジトリ外では無視されます。pathsも指定された場合は組み合わせて適用されます。 |
詳細
Emerge Tools Snapshots に代わるセルフホスト可能なオープンソースのツールです。既存の Compose @Preview と SwiftUI #Preview を収集し、閲覧可能な静的 HTML ギャラリーにします。SaaS アカウントは必要ありません。
Phonebook は、チームがすでに用意しているスクリーンショットを Storybook 風のコンポーネントギャラリーにします。新しいテストコードや、手作業で管理するデザイントークンは不要です。コードベースにすでにあるものを静的サイトとしてレンダリングするため、デザイナーは何もインストールせずに閲覧できます。各リポジトリで Phonebook を個別に実行します。v1 は単一プラットフォーム対応のため、1 つの Android リポジトリ(または 1 つの iOS リポジトリ)から 1 つのバンドルとサイトが生成されます。
機能
- 新しいテストコードは不要 — すでに記述した
@Preview/#Previewを再利用します - SaaS アカウント不要 — セルフホスト可能で、CI またはローカル環境ですべて実行できます
- MCP を第一に考えた設計 — コーディングエージェントがセットアップの確認、カバレッジの分析、不足しているプレビューの追加、ギャラリーのビルドを行えます
- スマートなコンポーネント分類 — プレビュー名から
コンポーネント / 状態のカードを推定します。アノテーションは不要です - クロスプラットフォーム — Android(Roborazzi + ComposablePreviewScanner。JVM 上で動作し、エミュレーター不要)と iOS(SnapshotPreviews。シミュレーター上で動作)に対応
- バージョンを考慮したセットアップ —
init/doctorはプロジェクトの Kotlin バージョンに基づいてライブラリのバージョンを解決し、分かりにくいコンパイラークラッシュが発生する前に Kotlin と Roborazzi のメタデータの不整合を検出します
デモ

samples/ios から生成したギャラリーです。アプリ独自の #Preview から コンポーネント / 状態 のカードを分類しており、追加のアノテーションは不要です。
仕組み
phonebook generateはプラットフォームのプレビュー描画エンジンを実行し、出力を バンドル(manifest.json+images/)に収集します。- Android:Roborazzi + ComposablePreviewScanner を Robolectric 経由で JVM 上で実行します。エミュレーターは不要で、Linux CI でも動作します。
- iOS:SnapshotPreviews をシミュレーター上で
xcodebuild test経由で実行します。macOS が必要です。
phonebook buildはそのバンドルを静的サイトに変換します。デフォルトでは、画像を再利用してコピーせずに、バンドルディレクトリ内へ直接index.htmlを書き込みます。そのため、サイトは<bundle>/index.htmlに生成されます。代わりに-o <dir>を指定すると、すべてのファイルを独立したサイトディレクトリにコピーします(別の場所で公開する場合や、後で複数のバンドルを結合する場合に便利です)。プレーンな HTML/CSS/JS で、file://または任意の静的ホストから動作します。
インストール
npm
npm install -g @stag-build/phonebook
Homebrew
brew install stag-build/phonebook/phonebook
先に tap を追加してからインストールすることもできます:
brew tap stag-build/phonebook
brew install phonebook
Formula のソース:stag-build/homebrew-phonebook。
インストール不要(npx)
npx @stag-build/phonebook <cmd>
ほとんどの人は CLI を直接実行しません。Phonebook は、MCP サーバーを介してコーディングエージェント(Claude Code、Codex など)から操作するように作られています。エージェントがプレビューを追加し、セットアップを確認して、ギャラリーを生成します。CLI はそのエンジンとして、エージェントから呼び出されます。
サーバーは npx @stag-build/phonebook mcp で実行できます。インストールは不要です。以下からクライアントを選んでください。
Claude Code
claude mcp add phonebook -- npx -y @stag-build/phonebook mcp
Codex CLI
~/.codex/config.toml に追加します。
[mcp_servers.phonebook]
command = "npx"
args = ["-y", "@stag-build/phonebook", "mcp"]
Claude Desktop
Claude Desktop の設定ファイルに追加します(macOS の場合は ~/Library/Application Support/Claude/claude_desktop_config.json)。
{
"mcpServers": {
"phonebook": {
"command": "npx",
"args": ["-y", "@stag-build/phonebook", "mcp"]
}
}
}
Cursor
.cursor/mcp.json(プロジェクト用)または ~/.cursor/mcp.json(グローバル用)に追加します。
{
"mcpServers": {
"phonebook": {
"command": "npx",
"args": ["-y", "@stag-build/phonebook", "mcp"]
}
}
}
Xcode (Codex Agent) — Xcode 26.3+
プロジェクトのワークスペースのルートにある .codex/config.toml に追加します。Xcode のエージェントは最小限の PATH で実行されるため、コマンドでは npx をシェルでラップし、先に一般的な Homebrew/nvm の場所を追加しています。
[mcp_servers.phonebook]
command = "/bin/zsh"
args = [
"-lc",
"PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin; npx -y @stag-build/phonebook mcp"
]
enabled = true
Xcode (Claude Code Agent) — Xcode 26.3+
mcpServers ブロックを ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/.claude.json に追加します。
{
"mcpServers": {
"phonebook": {
"command": "/bin/zsh",
"args": [
"-lc",
"PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin; npx -y @stag-build/phonebook mcp"
]
}
}
}
Android Studio(Gemini Agent Mode): まだサポートされていません。MCP 連携はリモートの httpUrl サーバーにのみ接続し、Phonebook のようなローカルの stdio プロセスには接続できないためです。代わりに、Android リポジトリから上記のターミナルベースのクライアント(Claude Code、Codex CLI)のいずれかを使用してください。
次に、Android または iOS のリポジトリでチャットを開き、次のように依頼します。
「phonebook MCP を使って、デザイナー用のカタログを作成してください。」
エージェントがセットアップの確認、不足しているプレビューの補完、生成、サイトのビルドまで、残りの作業を処理します。より具体的な依頼に使えるツールとして、check_setup(phonebook doctor と同じセットアップ診断)、analyze_coverage(プレビューまたはダークバリアントが不足しているコンポーネントの分析)、get_preview_guidance、run_generate、run_build も用意されています。
クイックスタート:Android
まず phonebook init を実行します。プロジェクトの Kotlin バージョンを検出し、それに互換性のあるライブラリバージョンを解決した手順を表示します(例:Kotlin 2.0 のプロジェクトでは Roborazzi 1.60.0、Kotlin 2.2 以降では最新バージョンが選ばれます)。以下のバージョンは、最新の Kotlin を使用するプロジェクト向けです(動作する完全な例は samples/android/app/build.gradle.kts を参照してください)。
// app/build.gradle.kts
plugins {
id("io.github.takahirom.roborazzi") // root build.gradle.kts: version "1.72.0" apply false
}
roborazzi {
generateComposePreviewRobolectricTests {
enable = true
packages = listOf("dev.stag.phonebook.sample") // your app's package
}
}
dependencies {
testImplementation("org.robolectric:robolectric:4.14.1")
testImplementation("io.github.takahirom.roborazzi:roborazzi:1.72.0")
testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.72.0")
testImplementation("io.github.sergio-sastre.ComposablePreviewScanner:android:0.9.3")
testImplementation("io.github.takahirom.roborazzi:roborazzi-compose-preview-scanner-support:1.72.0")
testImplementation("androidx.compose.ui:ui-test-junit4") // version from your Compose BOM, or pin one
}
settings.gradle.kts の隣に phonebook.config.json を追加します。
{
"appName": "My Android App",
"platform": "android",
"android": { "modules": [":app"], "variant": "debug" }
}
次に、Phonebook を含むリポジトリから、以下を実行します。
npx @stag-build/phonebook generate -C /path/to/your/android/repo
npx @stag-build/phonebook build -C /path/to/your/android/repo
phonebook-out/index.html を開きます。
generate --changed(または --files A.kt,B.kt)を指定すると、指定したファイルで宣言されているプレビューだけを、追加のセットアップなしでレンダリングします。この実行に限り、Phonebook は Gradle に init スクリプトを渡してプレビューテスターを差し替え、要求されたプレビューを保持し、そのパッケージだけをスキャンします。どちらのファイルもソース内ではなく、build/phonebook/ に書き込まれます。プロジェクトで独自の testerQualifiedClassName を設定している場合は、そちらが優先され、このモジュール内のすべてのプレビューがレンダリングされます。
クイックスタート:iOS
SnapshotPreviews の SPM パッケージをプロジェクトに追加し、SnapshotTest をサブクラス化する小規模な XCTest ターゲットを作成します(動作する完全な例は samples/ios を参照してください)。
// PhonebookSnapshotTests.swift
import Foundation
import SnapshottingTests
final class PhonebookSnapshotTests: SnapshotTest {
override class func snapshotPreviews() -> [String]? {
guard let raw = ProcessInfo.processInfo.environment["SNAPSHOTS_ONLY_FILTER"], !raw.isEmpty else {
return nil // record every #Preview
}
return raw.components(separatedBy: "\n")
}
}
SNAPSHOTS_ONLY_FILTER を読み取ることで、phonebook generate --changed(または --files A.swift,B.swift)は、直前に編集したファイル内のプレビューだけをレンダリングできます。この変数が設定されていない場合は、これまでどおりすべての #Preview が記録されます。
.xcodeproj の隣に phonebook.config.json を追加します。
{
"appName": "My iOS App",
"platform": "ios",
"ios": {
"project": "MyApp.xcodeproj",
"scheme": "MyApp",
"simulator": "iPhone 17 Pro"
}
}
スキームでスナップショットテストのターゲットをビルドしてテストできるようにしてください(サンプルの PhonebookSample.xcscheme を参照)。その後、次を実行します。
npx @stag-build/phonebook generate -C /path/to/your/ios/repo
npx @stag-build/phonebook build -C /path/to/your/ios/repo
phonebook-out/index.html を開きます。
命名規則
Phonebook は、既存のプレビュー名からスクリーンショットを component / state カードに分類します。アノテーションは不要です。ルールと例について詳しくは、docs/naming-convention.md を参照してください。
設定
phonebook.config.json:
| キー | 型 | デフォルト | 備考 |
|---|---|---|---|
appName | string | — | 必須です。ギャラリーのヘッダーに表示されます。 |
platform | "android" | "ios" | — | 必須です。 |
output | string | "phonebook-out" | バンドルの出力ディレクトリです。設定ファイルからの相対パスです。 |
android.modules | string[] | [":app"] | 記録する Gradle モジュールです。 |
android.variant | string | "debug" | ビルドバリアントです。Phonebook は <module>:recordRoborazzi<Variant> を実行します。 |
ios.project | string | — | .xcodeproj へのパスです。設定ファイルからの相対パスです。project または workspace のいずれかが必須です。 |
ios.workspace | string | — | .xcworkspace へのパスです。設定ファイルからの相対パスです。 |
ios.scheme | string | — | 必須です。SnapshotPreviews のテストターゲットを含むスキームです。 |
ios.simulator | string | "iPhone 17 Pro" | -destination に使用するシミュレーターのデバイス名です。 |
ios.onlyTesting | string | 自動検出 | -only-testing: フィルターです。generate がアプリのテストスイート全体ではなく、スナップショットクラスだけを実行するようにします。SnapshotTest のサブクラスから自動的に導出されます。すべて実行するには "" を設定します。 |
Android のプレビューは Android Studio と同様にレンダリングされます。独自のサイズを指定していない @Preview はコンテンツに合わせて表示され、フルスクリーン(fillMaxSize)のコンテンツは Robolectric の画面いっぱいに表示されます。Roborazzi のデフォルトは Pixel 4a です。generateComposePreviewRobolectricTests ブロックで robolectricConfig を設定すると、このデフォルトが置き換わるため、"qualifiers" to "RobolectricDeviceQualifiers.Pixel4a"(または Android Studio のスマートフォン用に "\"w411dp-h891dp-port\"")を含めてください。そうしないと、フルスクリーンのプレビューは 320×470dp の画面にレンダリングされます。phonebook doctor がこの点を指摘します。
generate と build はどちらも -C <dir>(phonebook.config.json を含むプロジェクトディレクトリ)を受け付けます。generate は、バンドルの出力先を上書きする -o <dir> と、プレビューが記録されない実行を許容する --allow-empty を受け付けます。build はオプションでバンドルのパスを指定できます。指定しない場合は、プロジェクトのバンドルディレクトリを使用します。また、サイトの出力先として -o <dir> を指定できます。-o を指定しない場合、build は index.html をバンドルディレクトリに直接書き込み、その中の images/ をそのまま再利用します(コピーしません)。上記のクイックスタートではこの方法を使用しています。バンドルの画像を別の独立したサイトディレクトリにコピーするには、-o <dir> を指定してください。
phonebook init と phonebook doctor
phonebook init はプラットフォームを検出し、phonebook.config.json と依存関係/セットアップ用のスニペットを作成します。ライブラリのバージョンはプロジェクトの Kotlin バージョンに合わせて解決され、アプリのパッケージも入力されます。ビルドファイルが編集されることはありません。
iOS の場合は、xcrun simctl list devices available でインストール済みデバイスを確認してから、phonebook init --simulator "<device name>" を実行し、選択したシミュレーターを記録します。phonebook.config.json がすでに存在する場合、同じコマンドで更新されるのは ios.simulator のみなので、セットアップを再試行する場合にも使えます。--simulator は Android では使用しません。
phonebook doctor は、generate に必要な設定がすべて行われているか確認します。確認対象は、プラグインとテスト依存関係(使用している場合は Gradle のバージョンカタログを通じて解決)、スキャナーの packages 値、Kotlin/Roborazzi の互換性、ツールチェーン(JDK/Xcode/シミュレーター)です。--deep を追加すると、テストソースもコンパイルします。時間はかかりますが、静的チェックの結果と実際の状態が食い違う場合に、確実な判断材料になります。iOS で SnapshotPreviews がリンクされているものの、SnapshotTest サブクラスがまだ存在しない場合、doctor は追加先となる正確なターゲットとフォルダー(.pbxproj を解析して特定)を示すため、場所を示さずに「クラスを追加してください」とだけ伝えることはありません。
phonebook init --write-snapshot-class は、ファイルを変更しないという init のルールの唯一の例外です。doctor の iOS チェックでリンク先のターゲットが特定され、かつそのターゲットのソースフォルダーが Xcode のファイルシステム同期グループのいずれかである場合、<folder>/PhonebookSnapshots.swift を直接書き込みます。同期フォルダーは Xcode によって自動的に検出されるため安全で、project.pbxproj の編集も発生しません。それ以外の場合(SnapshotPreviews がまだ設定されていない、同期グループを使用していないプロジェクト、またはサブクラスがすでに存在する場合)は、理由を示して処理を拒否します。
phonebook mcp は MCP サーバーを起動します。セットアップ方法とプロンプトの例については、上記の「コーディングエージェントでの使用」をご覧ください。
要件
Android:JDK 17 以降。エミュレーターは不要です。Roborazzi は Robolectric を使って JVM 上でレンダリングするため、generate は Linux CI で実行できます。
iOS:Xcode がインストールされた macOS と、起動済みまたは起動可能なシミュレーター(generate は名前付きのシミュレーターの実行先に対して xcodebuild test を実行します)。CI では macOS ランナーが必要です。
CI のレシピは docs/ci.md、命名規則は docs/naming-convention.md をご覧ください。
ロードマップ
v1 以降(M5)。まだ実装されていません:
- 生成されたギャラリーでの検索とフィルター
- 横並び表示による複数バンドルのマージ(クロスプラットフォームサイト向け)
- 2 回の実行間のバージョン差分表示(この機能を可能にするため、マニフェストにはすでにコミットと画像のハッシュが含まれています)
- CI レシピのドキュメントの追加
ライセンス
MIT — LICENSE をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。
