mcpField
S
setup

setup

github.com/davepoonエージェントワークフロー3.7k74 回インストール1 日前に更新
リポジトリ

setup について

setupは、コマンドラインツール、チャネル、MCP、プロジェクトレジストリを設定するclaude-ops向け対話型ウィザードです。既存の状態を検出して選択された設定を案内し、すべてのBash呼び出しをバックグラウンドで実行します。

主な機能

  1. 01CLI・チャネル・MCP・プロジェクト設定の確認
  2. 02CLIのインストールと連携設定の案内
  3. 03チャネル資格情報と設定の保存
  4. 04プロジェクトレジストリとデーモンの設定
  5. 05独立した診断タスクの並列実行

活用シーン

  1. 01claude-opsの初回設定
  2. 02未設定のチャネルやMCPの構成
  3. 03特定の設定セクションの再実行
  4. 04管理対象プロジェクトのレジストリ作成

MCP 対応

既存のMCP サーバーを検出し、Linear、Sentry、Vercel、GmailのMCP サーバーを設定する選択肢を提示します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/davepoon/buildwithclaude --skill setup

インストール後、Claude Code で/setupを入力して読み込まれたか確認します。

詳細

OPS ► セットアップウィザード

claude-ops プラグインの 対話型設定ウィザードを実行しています。ユーザーは、プラグインを動作させるために必要な手順をすべて案内してほしいと考えています。CLI のインストール、環境変数の設定、チャネルの設定、プロジェクトレジストリへの登録、設定の保存などを行います。


ルール 0 — すべての Bash 呼び出しで run_in_background: true を指定する

これは必須です。このセットアップウィザード全体で、Bash ツールを呼び出すたびに必ず run_in_background: true を設定してください。例外は一切ありません。以下に適用されます。

  • 認証情報のスキャン、CLI のインストール、OAuth フロー、npm/brew のインストール
  • デーモンの起動、デーモンの再読み込み、launchctl コマンド
  • Keychain への書き込み、Doppler クエリ、Chrome の履歴クエリ
  • 自動リンクスクリプト、同期/バックフィル、スモークテスト
  • ファイルの書き込み、設定の書き込み、環境変数の追記
  • 実行速度に関係なく、あらゆるコマンド

バックグラウンドコマンドの実行中は、すぐに次の独立した手順に進むか、ユーザーに次の質問をしてください。結果は <task-notification> が届いたときに処理します。セットアップウィザードでは、(ctrl+b to run in background) を絶対に表示してはいけません。このプロンプトがユーザーに表示された場合、このルールに違反しています。

ルール 1 — Bash 呼び出しは簡潔に

すべての Bash ツール呼び出しには、短い description パラメーターを必ず含めてください(5~10 語。例:「不足している CLI をインストール」「Telegram の認証情報を Keychain で調査」「デーモンを再読み込み」)。これは、生のコマンドの代わりにユーザーに表示されます。セットアップはすっきりと静かに進め、ユーザーにはシェルスクリプトではなく進行状況のタイトルを表示してください。


その他の厳守事項:

  • これは 会話 であり、スクリプトのダンプではありません。すべての決定には AskUserQuestion を使用してください — 構造化された選択肢で済む場合に、散文で尋ねてはいけません。
  • ユーザーがまだオプトインしていないアクションは、AskUserQuestion で確認してください(例: 「すべて設定」ですべてをカバーします — その後にアクションごとの確認は不要です)。
  • ユーザーが辞退したセクションはスキップしてください。しつこく尋ねないでください。
  • チャネルや連携を自動でスキップしてはいけません。 ユーザーが選択したすべてのチャネル/サービスには、スキップを選択肢の一つとして含む明示的な AskUserQuestion を必ず行ってください。認証情報が見つからない場合は、[手動で貼り付け] / [徹底調査] / [スキップ] の選択肢を提示してください。スモークテストが失敗した場合は、再試行、再設定、スキップのどれにするかをユーザーに尋ねてください。スキップが許容される唯一の方法は、ユーザーが「スキップ」オプションを選ぶことです。スキャンで何も見つからなかったからといって、サービスを黙って飛ばしてはいけません — まさにそのときにこそ、ユーザーに尋ねる必要があるのです。
  • すでに設定済みのものを最初に表示し、ユーザーが不足分だけを埋められるようにしてください。
  • ユーザーの実名やメールアドレスは、ユーザーがこのセッションで明示的に提供しない限り、出力に表示してはいけません。 表示名を埋めるために、メモリ、既存の設定、環境変数から読み取らないでください。
  • AskUserQuestion の 1 回の呼び出しにつき最大 4 つの選択肢です。 ツールスキーマは options 配列の項目数を <=4 に強制します。あるステップで 4 つを超える選択肢が挙げられている場合は、まず設定済みの項目を除外し、残りを論理的にグループ化して、それぞれ 4 つ以下の選択肢の複数の連続した呼び出しにまとめてください。バッチ間をつなぐ最後の選択肢として [その他のオプション...] を使用してください。
  • 可能な場合は、すべての診断/プローブコマンドを並列で実行してください。1 つのメッセージ内で複数の Bash ツール呼び出しを使用してください。独立しているプローブを逐次実行しないでください(例: gog auth status と wacli doctor と keychain スカウトはすべて同時に実行すべきです)。
  • すべての書き込みは以下のいずれかのパスに対して行われます — それ以外はありません:
    • $PREFS_PATH — ユーザーごとの設定 + シークレット。${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json に解決されます。Claude Code のプラグインデータディレクトリにあるため、プラグインの再インストールやバージョンアップにも耐えます。git にコミットされることはありません。
    • ${CLAUDE_PLUGIN_ROOT}/scripts/registry.json — ユーザーごとのプロジェクトレジストリ(ソースリポジトリでは gitignore されています)。親ディレクトリが存在しない場合は mkdir -p してください。
    • ${CLAUDE_PLUGIN_ROOT}/.mcp.json — ${user_config.*} プレースホルダーを追加するためだけに使用し、トークンをハードコードしてはいけません。
    • ユーザーのシェルプロファイル(~/.zshrc など)— 追記のみで、決して書き換えないでください。
  • すべてのウィザードステップの冒頭で、$PREFS_PATH の親ディレクトリが存在することを確認してください: mkdir -p "$(dirname "$PREFS_PATH")"。Claude Code はプラグインのインストール時に ~/.claude/plugins/data/ops-ops-marketplace/ を作成しますが、それを前提にしないでください。

Agent Teams のサポート

CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 が設定されている場合、複数の「徹底調査」認証情報エージェントを同時に必要とするときは Agent Teams を使用してください。これにより以下が可能になります:

  • 認証情報スカウトが Doppler、キーチェーン、ブラウザプロファイル、パスワードマネージャーを横断して並列で実行されます
  • エージェントが発見事項を共有します(例: Doppler エージェントが部分的な設定を見つける → キーチェーンエージェントはそのサービスをスキップすべきだと把握します)
  • 調査の途中で指示を出せます: 「Telegram トークンを見つけたので、その調査を停止して」

チームのセットアップ(フラグが有効で、複数の徹底調査がトリガーされた場合のみ):

TeamCreate("setup-hunters")
Agent(team_name="setup-hunters", name="hunt-telegram", model="haiku", ...)
Agent(team_name="setup-hunters", name="hunt-sentry", model="haiku", ...)
Agent(team_name="setup-hunters", name="hunt-shopify", model="haiku", ...)

各エージェントは発見事項を報告します。結果をマージし、確認のためにユーザーに提示してください。

フラグが設定されていない場合は、run_in_background: true を指定した独立したファイア・アンド・フォーゲットのサブエージェントを使用してください。


セットアップエージェントの委任パターン

セットアップ中にユーザーが複雑な連携固有の質問をした場合(例: 「/ops:ecom はマルチストア構成をどのように処理しますか?」)、セットアップエージェントはより深いコンテキストのために、関連するスキルの SKILL.md を読み込めます:

cat "${CLAUDE_PLUGIN_ROOT}/skills/ops-ecom/SKILL.md"

以下の各サブステップには、関連するスキルファイルへの > **詳細解説:** ポインターが含まれています。このウィザードで運用の詳細を重複させるのではなく、これらのポインターに従ってください。


ステップ 0 — 事前確認(読み進めている間にバックグラウンドで実行)

${CLAUDE_PLUGIN_ROOT}/bin/ops-setup-preflight &>/dev/null &

事前確認データ:すべてのプローブ結果は /tmp/ops-preflight/ にキャッシュされています。診断コマンドを実行する前に、結果がすでに存在するか確認してください。

  • CLI の状態:cat /tmp/ops-preflight/clis.txt
  • Slack:cat /tmp/ops-preflight/slack.json
  • Telegram:cat /tmp/ops-preflight/telegram.txt
  • gog/Gmail:cat /tmp/ops-preflight/gog-gmail.json
  • gog/Calendar:cat /tmp/ops-preflight/gog-cal.json
  • WhatsApp:cat /tmp/ops-preflight/wacli-doctor.json および wacli-chats.json
  • MCP サーバー:cat /tmp/ops-preflight/mcp-servers.txt
  • GitHub:cat /tmp/ops-preflight/gh-auth.txt
  • AWS:cat /tmp/ops-preflight/aws-identity.json
  • プロジェクト:cat /tmp/ops-preflight/projects.txt
  • 既存のレジストリ:cat /tmp/ops-preflight/existing-registry.json
  • 既存の設定:cat /tmp/ops-preflight/existing-prefs.json
  • Doppler:cat /tmp/ops-preflight/doppler.json

読み込む前に /tmp/ops-preflight/.complete が存在するまで待ってください(2〜3 秒以内に準備できるはずです)。キャッシュ済みのプローブは絶対に再実行せず、代わりにキャッシュファイルを読み込んでください。


ステップ 0b — 現在の状態を検出

検出スクリプトを実行し、その JSON 出力を解析してください(または、利用可能な場合は事前確認キャッシュから読み込んでください)。

${CLAUDE_PLUGIN_ROOT}/bin/ops-setup-detect 2>/dev/null

CLAUDE_PLUGIN_ROOT が設定されていない場合は、~/.claude/plugins/cache/ops-marketplace/ops/<latest-version>/ にある最新のインストール済みキャッシュディレクトリを使用してください。解決したパスは、セッションの残りの間 PLUGIN_ROOT として保存してください。

また、PREFS_PATH も一度だけ解決し、その値を全体で再利用してください。

PREFS_PATH="${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json"
mkdir -p "$(dirname "$PREFS_PATH")"

カテゴリごとに1行で、簡潔な状態ヘッダーをユーザーに表示してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► SETUP WIZARD
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Shell:       zsh → ~/.zshrc
 Core CLIs:   ✓ jq  ✓ git  ✓ gh  ✓ aws  ✓ node
 Channels:    ✓ wacli  ✓ gog  ○ telegram (no token)
 Secrets:     ✓ doppler (project: my-app, config: dev)
 MCPs:        ✓ linear  ✓ sentry  ○ slack  ○ vercel
 Registry:    19 projects
 Preferences: not set
──────────────────────────────────────────────────────

存在/設定済みには ✓、不在/未設定には ○、不具合には ✗ を使用してください。


Step 1 — 設定するセクションを尋ねる

まず、「すべてセットアップする」オプションを提示します。

How would you like to run setup?
  [Set up everything — install CLIs, configure all channels, MCPs, registry, daemon, preferences (Recommended)]
  [Pick sections — choose which parts to configure]
  [Re-run a specific section — I know what I need]

ユーザーが「すべてセットアップする」を選択した場合、すべてのバッチの全セクションを選択し、順に実行します(Step 2 → 2b → 2c → 3 → 4 → 5 → 5b → 6 → 7)。すでに完全に設定済みのセクションはスキップします。各ステップでは、利用可能な場合は「すべて設定」の高速パスを使用します。

ユーザーが「特定のセクションを再実行する」を選択した場合、セクション名(cli、daemon、channels、mcp、registry、prefs、env、ecom、mktg、voice、revenue)を一覧にした単一の AskUserQuestion を表示し、そのステップに直接移動します。

ユーザーが「セクションを選択する」を選択した場合、以下のバッチ選択に進みます。

multiSelect: true を指定して AskUserQuestion を使用します。対応が必要なセクションのみ提示します(すでに緑色のものはスキップします)。AskUserQuestion で選択肢として提示できるのは最大 4 件なので、論理的なグループに分けてバッチ処理します。

Batch 1 — 基本セットアップ(早めに実行し、残りのセットアップ中にデーモンがキャッシュを事前にウォームアップできるようにします):

OptionHeaderDescription
CLI をインストールcli不足しているコマンドラインツールを Homebrew 経由でインストールします
バックグラウンドデーモンdaemonops-daemon を早めにインストールし、残りのセットアップ中にブリーフィングキャッシュを事前にウォームアップします
MCP を設定mcpLinear、Sentry、Vercel、Gmail の MCP サーバーを有効にします
レジストリを構築registryClaude が管理するプロジェクトを登録します

Batch 2 — チャネルとプラグイン:

OptionHeaderDescription
チャネルを設定channelsTelegram、WhatsApp、Email、Slack のトークンを設定します
コンパニオンプラグインpluginsプロジェクトのロードマップ追跡用に GSD をインストールします
設定を保存prefsオーナー名、タイムゾーン、デフォルトの優先順位を設定します
シェル環境envシェルプロファイルで CLAUDE_PLUGIN_ROOT をエクスポートします

Batch 3 — 追加項目(未設定の場合のみ表示):

OptionHeaderDescription
eコマースを設定ecomShopify ストアの URL と管理者トークン、ShipBob を設定します
マーケティングを設定mktgKlaviyo、Meta Ads、GA4、Search Console のキーを設定します
音声を設定voiceBland AI、ElevenLabs、Groq API キーを設定します
収益を設定revenueリアルタイムの MRR 追跡用に Stripe と RevenueCat のキーを設定します

各バッチを個別の AskUserQuestion 呼び出しとして提示します。すべての項目がすでに緑色のバッチはスキップします。すべてのバッチの選択を集め、選択された各セクションを順に実行します。


Step 2 — CLI をインストール(選択された場合)

不足している CLI が複数ある場合は、まず一括インストールを提示します。

Missing CLIs detected: jq, gh, wacli. What would you like to do?
  [Install all missing CLIs (Recommended)]
  [Pick which to install]
  [Skip CLI installation]

ユーザーが「すべてインストール」を選択した場合、追加の確認なしに不足しているツールをすべて順にインストールします。「インストールするものを選ぶ」を選択した場合は、ツールごとに尋ねます。

Install jq?           [Yes, install now] [Skip]
Install gh?           [Yes, install now] [Skip]
Install wacli?        [Yes, install now] [Skip — manual install required]

各 Yes に対して、次を実行します。

${PLUGIN_ROOT}/bin/ops-setup-install <tool>

成功または失敗を報告します。macOS で Homebrew が見つからない場合は、処理を中止し、まず https://brew.sh からインストールするようユーザーに伝えます。brew を自動でインストールしようとしてはいけません。

インストール後、ステータスを更新するために ops-setup-detect を再実行してから続行します。


Step 2b — コンパニオンプラグイン(選択された場合)

GSD(Get Shit Done)

GSD は、プロジェクトのロードマップ追跡機能を追加するサードパーティ製の Claude Code プラグインです。インストールすると、claude-ops ダッシュボード(/ops:go、/ops:projects、/ops:next、/ops:yolo)に、プロジェクトごとの進行中のフェーズ、進捗状況、次のアクションが自動的に表示されます。インストールされていない場合、これらのセクションは単に省略されます。

GSD がすでにインストールされているか確認します。

find ~/.claude -name "gsd-progress" -path "*/skills/*" 2>/dev/null | head -1 | grep -q . && echo "installed" || echo "not_installed"

インストールされていない場合は、AskUserQuestion で確認します。

GSD adds project roadmap tracking to your ops dashboards.
  /ops:go shows active phases and progress per project
  /ops:projects shows GSD state alongside CI/PR status
  /ops:next factors in GSD work priority

  [Install GSD (latest)] [Skip — I don't need roadmap tracking]

インストールする場合は、コマンドを直接実行します。ユーザーに手動で実行するよう伝えてはいけません。

# Install GSD in one shot — no user intervention needed
claude plugin marketplace add gsd-build/get-shit-done 2>/dev/null && \
claude plugin install gsd@gsd-build-get-shit-done 2>/dev/null

claude CLI がパス内で利用できない場合は、プラグインキャッシュの仕組みにフォールバックします。

# Direct marketplace clone fallback
GSD_MARKETPLACE_DIR="$HOME/.claude/plugins/marketplaces/gsd-build-get-shit-done"
if [ ! -d "$GSD_MARKETPLACE_DIR" ]; then
  git clone https://github.com/gsd-build/get-shit-done.git "$GSD_MARKETPLACE_DIR" 2>/dev/null
fi

成功または失敗を報告します。$PREFS_PATH に plugins.gsd = "installed" を記録します。

スキップする場合:

Skipped GSD. Install later with: /plugin marketplace add gsd-build/get-shit-done

ステップ 2c — バックグラウンドデーモン(早期インストール、キャッシュの事前ウォームアップ)

なぜデーモンをこんなに早くインストールするのでしょうか? 残りのセットアップと並行してデーモンを実行すると、ブリーフィングキャッシュ(インフラ/git/PR/CI の ops-gather の結果)の事前ウォームアップを開始できます。そのため、ユーザーがステップ 7 に進んで /ops:go を実行する頃にはブリーフィングがすでにキャッシュされており、10 秒ではなく 3 秒未満で読み込まれます。チャネルに依存するサービス(wacli-sync、message-listener、inbox-digest、store-health)は、チャネルの設定後、ステップ 5b で追加されます。

プラットフォームのサポート

バックグラウンドデーモンには launchd との連携が含まれています(macOS のみ)。インストールを試みる前にプラットフォームを検出します。

case "$(uname -s)" in
  Darwin)                OS=macos ;;
  Linux)                 grep -qi microsoft /proc/version 2>/dev/null && OS=wsl || OS=linux ;;
  MINGW*|MSYS*|CYGWIN*)  OS=windows ;;
  *)                     OS=unknown ;;
esac
  • macOS(OS=macos):以下の launchctl bootstrap の手順に進みます。

  • Linux/WSL(OS=linux|wsl):launchctl は利用できません。デーモンスクリプト(${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon.sh)は bash で問題なく動作しますが、ユーザーサービスとしてインストールするには、Linux では systemd --user、WSL ではカスタムの cron/at ラッパーが必要です。この対応は今回のパッチの対象外です。今後の作業として記録してください。現時点では、次の内容を出力します。

    ○ Background daemon — skipped (Linux/WSL install via systemd --user is pending; see docs/daemon-guide.md).
      You can still launch it manually with:  nohup ${CLAUDE_PLUGIN_ROOT}/scripts/ops-daemon.sh &
    

    $PREFS_PATH に daemon.enabled = false と daemon.skip_reason = "platform:<os>" を書き込み、ステップ 3 に進みます。

  • Windows(ネイティブ、OS=windows):デーモンはインストールされません。○ Background daemon — not supported on native Windows. Use WSL or run ops-daemon.sh manually. を出力して続行します。

OS=macos の場合、デーモンがすでにインストールされているか確認します。

launchctl print gui/$(id -u)/com.claude-ops.daemon 2>/dev/null | head -1

すでに読み込まれている場合は、✓ Background daemon already running — will reconcile services in Step 5b. と出力し、ステップ 3 に進みます。

それ以外の場合は、AskUserQuestion で確認します。

Install the ops background daemon now?
  Starts pre-warming briefing cache while you finish the rest of setup.
  Auto-heals on failure. Single launchd agent (com.claude-ops.daemon).
  Channel services (wacli-sync, message-listener) added after channels are set up.
  [Yes — install now]  [Skip — I'll run it manually later]

Yes の場合、インストールを実行します(run_in_background: true を使用します — RULE ZERO)。

# Always resolve CLAUDE_PLUGIN_ROOT to the CURRENT installed version — never hardcode a version number.
# If CLAUDE_PLUGIN_ROOT is not set, detect it from the plugin cache:
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(ls -d "$HOME/.claude/plugins/cache/ops-marketplace/ops"/*/ 2>/dev/null | sort -V | tail -1)}"
DAEMON_SCRIPT="${PLUGIN_ROOT}/scripts/ops-daemon.sh"
chmod +x "$DAEMON_SCRIPT"
PLIST_TEMPLATE="${PLUGIN_ROOT}/scripts/com.claude-ops.daemon.plist"
PLIST_DEST="$HOME/Library/LaunchAgents/com.claude-ops.daemon.plist"
DATA_DIR="${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}"
LOG_DIR="$DATA_DIR/logs"
mkdir -p "$LOG_DIR"

# Resolve bash 4+ (required for associative arrays in ops-daemon.sh).
# macOS ships bash 3; Homebrew installs bash 5 at /opt/homebrew/bin/bash.
BASH_PATH="/bin/bash"
if [[ -x /opt/homebrew/bin/bash ]]; then
  BASH_PATH="/opt/homebrew/bin/bash"
elif [[ -x /usr/local/bin/bash ]]; then
  BASH_PATH="/usr/local/bin/bash"
fi

# Generate plist
sed -e "s|__DAEMON_SCRIPT_PATH__|$DAEMON_SCRIPT|g" \
    -e "s|__BASH_PATH__|$BASH_PATH|g" \
    -e "s|__PLUGIN_ROOT__|$PLUGIN_ROOT|g" \
    -e "s|__LOG_DIR__|$LOG_DIR|g" \
    -e "s|__HOME__|$HOME|g" \
    "$PLIST_TEMPLATE" > "$PLIST_DEST"

# Write a minimal initial services config — only the services that don't depend on
# channels yet. `briefing-pre-warm` runs ops-gather every 2 minutes so the next
# /ops:go is instant. `memory-extractor` runs but stays idle until channels exist.
SERVICES_CONFIG="$DATA_DIR/daemon-services.json"
cat > "$SERVICES_CONFIG" <<JSON
{
  "services": {
    "briefing-pre-warm": {
      "enabled": true,
      "command": "${CLAUDE_PLUGIN_ROOT}/bin/ops-gather",
      "cron": "*/2 * * * *",
      "_note": "Pre-warms /ops:go cache. Runs every 2 minutes."
    },
    "memory-extractor": {
      "enabled": true,
      "command": "${CLAUDE_PLUGIN_ROOT}/scripts/ops-memory-extractor.sh",
      "cron": "*/30 * * * *",
      "health_file": "~/.claude/plugins/data/ops-ops-marketplace/memories/.health",
      "_note": "Idle until channels are configured; will extract profiles once wacli/gog are live."
    }
  }
}
JSON

# Remove the old standalone wacli keepalive if present
launchctl bootout gui/$(id -u)/com.claude-ops.wacli-keepalive 2>/dev/null || true
rm -f "$HOME/Library/LaunchAgents/com.claude-ops.wacli-keepalive.plist"

# Load daemon in background — does NOT block the wizard
launchctl bootout gui/$(id -u) "$PLIST_DEST" 2>/dev/null || true
launchctl bootstrap gui/$(id -u) "$PLIST_DEST"

ステップ 5b で再インストールではなくサービスの調整を行うよう、$PREFS_PATH に daemon.enabled = true と daemon.installed_at_step = "2c" を書き込みます。

次の内容を出力します。

✓ Background daemon — installed. Pre-warming briefing cache in parallel while you finish setup.
  Channel-dependent services will be added after channels are configured (Step 5b).

すぐにステップ 3 に進みます。デーモンの起動確認を待ってはいけません。ヘルスファイルの確認はステップ 5b まで保留されます。

詳細情報: バックグラウンドデーモンの運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/docs/daemon-guide.md を参照してください。このウィザードより詳しい情報が必要な場合、セットアップエージェントはそのファイルを直接読み込めます。


ステップ 3 — チャネルを設定する(選択した場合)

まず、個別に選択する前に、手早く「すべて設定」するオプションを提示します。AskUserQuestion を使用します。

How would you like to configure channels and integrations?
  [Configure all — set up every available channel and service (Recommended)]
  [Pick individually — choose which channels to configure]
  [Skip all — configure channels later]

ユーザーが「すべて設定」を選択した場合、以下の各チャネルのサブフローを順番にすべて実行します(Telegram → WhatsApp → Email → Slack → Notion → Calendar → Doppler → Vault)。すでに設定済みのチャネルはスキップします。ユーザーが「すべてスキップ」を選択した場合は、ステップ 4 に進みます。

ユーザーが「個別に選択」を選択した場合は、multiSelect: true を指定した AskUserQuestion でチャネルを尋ねます。AskUserQuestion で指定できるオプションは最大 4 つなので、2 つのグループに分けます。すでに設定済みのチャネルはスキップし、対応が必要なものだけを表示します。

バッチ 1 — メッセージング:

オプションヘッダー説明
Telegramtelegram/ops-comms telegram 用のボットトークン + オーナー ID
WhatsAppwhatsappwacli doctor + 自動修復 + バックフィル
Emailemail/ops-inbox email 用の gog CLI → Gmail MCP フォールバック
SlackslackSlack MCP サーバー(Claude Code が管理)

バッチ 2 — ナレッジとサービス:

オプションヘッダー説明
NotionnotionNotion MCP — ワークスペースの検索、コメント、タスク、ナレッジベース
Calendarcalendargog calendar → Google Calendar MCP フォールバック — ブリーフィング用のスケジュールコンテキスト
Dopplerdopplerシークレットマネージャー — すべての ops スキルで使用するデフォルトのプロジェクト + 設定を指定
Vaultvaultパスワードマネージャー — 1Password、Dashlane、Bitwarden、または macOS Keychain

各バッチは個別の AskUserQuestion 呼び出しとして提示します。すべての項目が設定済みのバッチはスキップします。選択された各チャネルについて、対応する以下のサブフローを実行します。


共通:インストールを提案する前にホスト OS を検出する

claude-ops ウィザードは、macOS、Linux(主要なすべてのディストリビューション + WSL)、Windows(ネイティブ + WSL)で実行されます。インストールコマンドを表示する前に、スキルはホスト OS を検出し、OS に適したバージョンを選択する必要があります。Windows ユーザーに brew install … コマンドを表示してはならず、macOS ユーザーに winget install … コマンドを表示してはなりません。

最小限の検出スニペット(bash — macOS、Linux、WSL、MSYS/Cygwin で動作):

case "$(uname -s)" in
  Darwin*) OS=macos ;;
  Linux*)
    if grep -qi microsoft /proc/version 2>/dev/null; then OS=wsl
    elif [ -f /etc/os-release ]; then
      . /etc/os-release
      case "$ID" in
        arch|manjaro) OS=arch ;;
        fedora|rhel|centos|rocky|almalinux) OS=fedora ;;
        debian|ubuntu|pop|linuxmint) OS=debian ;;
        alpine) OS=alpine ;;
        opensuse*|sles) OS=suse ;;
        *) OS=linux ;;
      esac
    else OS=linux; fi ;;
  MINGW*|MSYS*|CYGWIN*) OS=windows ;;
  *) OS=unknown ;;
esac

パッケージマネージャーの選択順(最初に利用可能なものを選択):

  1. brew(macOS + Linuxbrew)— macOS では優先します。
  2. OS 標準のマネージャー — apt-get(debian/ubuntu)、dnf(fedora/rhel)、pacman(arch)、zypper(suse)、apk(alpine)。
  3. winget(Windows 10 1809 以降)→ scoop → choco → Windows では最後の手段としてソースからビルド。

優先するマネージャーがインストールされていない場合、フローを中断せず、次に利用可能なオプションに進みます。以下の [今すぐインストール — …] という AskUserQuestion プロンプトでは、OS に応じたコマンド表を使用し、検出された OS に一致する行のみを表示します。

OS 間で共通に使用する正式な検出ロジックには、JSON 出力で os、pkg_mgr、arch、keyring_backend、shell、browser_profiles_found を出力する bin/ops-setup-detect を再利用します。


共通: 手動トークンよりも OAuth を優先する

チャネルでブラウザベースの OAuth フローが利用可能な場合は常に、まずそれを提示し、手動トークン入力はそのフォールバックとして後ろに配置してください。OAuth はより安全で(スコープが限定され、取り消し可能で、dotfiles にシークレットを置く必要がありません)、通常はユーザーにとってもより迅速です。

チャネルOAuth の経路手動フォールバック
メール (gog)gog auth add <email> --services gmail,calendar,drive,contacts,docs,sheets(ブラウザ)該当なし — gog は OAuth 専用
カレンダー (gog)同じ gog auth add で --services に calendar を含める該当なし
Slackclaude mcp add slack(Claude Code 経由で OAuth を処理)自動スキャン + 手動貼り付けによるボットトークン
Linearclaude mcp add linearAPI キー
Sentryclaude mcp add sentryDSN / 認証トークン
Vercelclaude mcp add vercelパーソナルアクセストークン
Telegram❌ OAuth なし(Bot API は設計上トークンのみ)自動スキャン + 手動貼り付け(唯一の選択肢)
WhatsAppwacli auth による QR ペアリング(OAuth に似た UX)該当なし — ペアリング済みセッションのみ

チャネルが OAuth をサポートしている場合、デフォルトの AskUserQuestion はそれを最初に提示するべきです:

[Connect via OAuth (recommended)]  [Enter a token manually]  [Skip]

ユーザーが「手動」を選んだ場合、またはチャネル(Telegram、ローカルツール)に OAuth の経路がない場合にのみ、以下の認証情報自動スキャンフローに進んでください。



ユニバーサル認証情報自動スキャン

ユーザーにいかなる認証情報も尋ねる前に、このスキャンシーケンスを実行してください。これはすべてのステップに適用されます — チャネル、eコマース、マーケティング、音声、および MCP。すでにユーザーのシステム上にあるキーを見つけるようユーザーに求められることがあってはなりません。

重要 — 報告する前にすべてのソースを使い果たしてください。 すべてのスキャンソース(以下の 1〜10)を 1 つのバッチで実行し、その後、統合された結果を分析してください。環境変数と Dashlane だけを確認した後に「認証情報が見つかりません」と報告しないでください — Chrome の履歴、.env ファイル、Doppler、およびキーチェーンに答えがあるかもしれません。API トークンは見つからないものの、ストア/サービスの識別情報が見つかった場合(例: Chrome の履歴にあるストア URL、Dashlane のログインエントリ)、見つけたものを報告し、識別情報を事前入力した状態でトークンのステップに進んでください。ユーザーが「見つけて」または「利用可能なすべてのソースを確認して」と言うのは、あなたの検索が十分に徹底していなかったことを意味します — プログラムで見つけられるものをユーザーに探させることは決してしないでください。

各変数名(例: TELEGRAM_BOT_TOKEN、SHOPIFY_ACCESS_TOKEN、KLAVIYO_API_KEY)について:

  1. 現在のシェル環境 — printenv <VAR>。実行中のシェルには、エクスポートされた環境変数、Doppler による注入、dotenv で読み込まれたファイルが引き継がれます。最も正確である可能性が高い方法です。
  2. シェルのプロファイルファイル — ~/.zshrc、~/.bashrc、~/.zprofile、~/.config/fish/config.fish、~/.envrc(direnv)を検索し、<VAR>= または export <VAR>= を探します。値の横にファイルパスを表示し、ユーザーが出どころを確認できるようにします。
  3. Doppler(すべてのプロジェクト) — command -v doppler が成功する場合:
    for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
      doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
        jq -r --arg var "$VAR" --arg proj "$proj" \
        'to_entries[] | select(.key == $var) | "\(.value.computed) (doppler:\($proj)/prd)"'
    done
    
    prd で失敗した場合は、デフォルトのプロジェクト設定(dev/staging)も試します。ソース情報 (project: <slug>, config: <config>) を表示します。
  4. Dashlane CLI — command -v dcli が成功する場合:
    dcli password "$SERVICE_KEYWORD" --output json 2>/dev/null
    
    サービスのキーワードを対応付けます:shopify → SHOPIFY 変数、klaviyo → KLAVIYO 変数、bland / bland-ai → BLAND 変数など。
  5. macOS Keychain — 特定のサービスの場合:
    security find-generic-password -s "$SERVICE" -w 2>/dev/null
    
    一般的なパターンに一致するサービス名を使用します(例:shopify-admin-token、klaviyo-api-key、bland-ai-api-key)。
  6. OpenClaw の設定 — ~/.openclaw/openclaw.json が存在する場合:
    jq -r --arg var "$VAR" '.agents.defaults.env[$var] // empty' ~/.openclaw/openclaw.json 2>/dev/null
    
  7. インストール済みの MCP 設定 — 検出された各 .mcp.json を読み取ります。各サーバーエントリーについて、.env と .args で変数名、または対象に該当しそうなリテラル値を確認します。ソースとして MCP サーバー名を表示します。
  8. プラグインの設定 — 既存の $PREFS_PATH で、該当するセクション内のキー(例:.ecom.shopify.admin_token、.marketing.klaviyo.api_key)を確認します。見つかった値が doppler: 参照でなければ、ソースとして表示します。
  9. Chrome の履歴 — ウェブ管理画面があるサービス(Shopify、Klaviyo など)について、Chrome の History SQLite DB を検索し、アカウントやストアの識別に役立つ管理 URL を探します:
    sqlite3 ~/Library/Application\ Support/Google/Chrome/Default/History \
      "SELECT DISTINCT url FROM urls WHERE url LIKE '%<service_domain>%' ORDER BY last_visit_time DESC LIMIT 10" 2>/dev/null
    
    URL から識別子(例:*.myshopify.com のストアスラッグ、アカウント ID)を抽出します。
  10. プロジェクトの .env ファイル — ~/Projects/*/.env* をスキャンし、変数名またはサービスのドメインパターンを探します。他のプロジェクトの認証情報を再利用できることがよくあります。

自動スキャン用の環境変数 → サービスキーワード対応表:

変数名サービスキーワード(Dashlane/Keychain)
SHOPIFY_ACCESS_TOKEN、SHOPIFY_ADMIN_TOKEN、SHOPIFY_STORE_URLshopify
KLAVIYO_API_KEY、KLAVIYO_PRIVATE_KEYklaviyo
META_ACCESS_TOKEN、FACEBOOK_ACCESS_TOKEN、META_AD_ACCOUNT_IDmeta、facebook
GA4_PROPERTY_ID、GA_MEASUREMENT_IDgoogle-analytics、ga4
BLAND_AI_API_KEY、BLAND_API_KEYbland-ai、bland
ELEVENLABS_API_KEYelevenlabs
GROQ_API_KEYgroq
SHIPBOB_ACCESS_TOKENshipbob
TELEGRAM_BOT_TOKEN、TELEGRAM_API_ID、TELEGRAM_API_HASHtelegram
SLACK_BOT_TOKEN、SLACK_MCP_XOXC_TOKENslack

調査結果の提示には AskUserQuestion を使用します(1 回の呼び出しにつき選択肢は最大 4 つ):

Found credential for SHOPIFY_ACCESS_TOKEN:
  [A] shell env + ~/.zshrc + Dashlane — shpat_508b...682e  (matched across 3 sources)
  [B] Doppler (project: mystore, config: prd) — shpat_9f2c...a17b  (different!)
  [C] Enter a different one

プロンプトのルール:

  • トークンはすべて、先頭 8 文字と末尾 4 文字を表示し、値全体は決して表示しません。
  • 一致したソースは必ず 1 つの選択肢にまとめ、末尾に (matched in env + ~/.zshrc + Dashlane) を付けます。4 つの選択肢の上限を守るため、これは重要です。
  • ソース間で値が異なる場合は、異なる値ごとに別の選択肢として表示します。異なる値が 3 つを超える場合(まれ)は、複数回に分けて [More sources...] を付けます。
  • ${user_config.*}、<your-token>、CHANGE_ME などのプレースホルダー値や空文字列は、「見つからない」とみなします。
  • 最後の選択肢として、必ず [Enter a different one] を含めます。
  • どのソースにも値が見つからない場合は、AskUserQuestion で次の選択肢を提示します:
<SERVICE_NAME> — no credential found after scanning all sources.

  [I have it — let me paste it]
  [Deep hunt — spawn an agent to find it]
  [Skip this service]
  • 「I have it」 → サービスのダッシュボードで認証情報を確認する方法を案内してから、自由入力を受け付けます。

  • 「Deep hunt」 → 次の指示に従う Haiku サブエージェントをバックグラウンドで起動します:

    <CREDENTIAL_NAME>(<SERVICE_NAME> の認証情報)を探します。徹底的に検索します。
    1. すべての Doppler プロジェクトと設定(dev/stg/prd/ci)
    2. ~/Projects/ 以下のすべての .env* ファイルを再帰的に検索
    3. macOS キーチェーン(さまざまなサービス名パターンで security find-generic-password を実行)
    4. Dashlane CLI(dcli password <service> と関連キーワード)
    5. Chrome ブラウザー — Kapture/Playwright MCP 経由で <service_admin_url> にアクセスし、必要に応じてログインして、設定ページから認証情報を取得
    6. すべてのシェルプロファイルファイル(~/.zshrc、~/.bashrc、~/.zprofile、~/.envrc、~/.config/fish/*)
    7. 利用可能な場合は 1Password CLI(op item list --tags <service>)
    8. aws cli が認証済みの場合は AWS Secrets Manager / SSM Parameter Store
    
    認証情報が見つかった場合はその値を返します。見つからなかった場合は、確認した場所と見つかった内容(部分一致、期限切れトークン、形式の異なる値など)を詳しく報告します。
    

    Agent(subagent_type: "general-purpose", model: "haiku") を run_in_background: true で使用します。検索中に次のサービスへ進みます。エージェントから結果が返ったら、確認のためにユーザーへ提示します。

  • 「スキップ」 → $PREFS_PATH にスキップとして記録し、次へ進みます。

選択時は、選択された値を信頼できる情報源として使用し、ユーザーの同意を得たうえで、必要に応じて他の情報源にも反映します(例:「~/.zshrc と Doppler も同じ値に更新しますか?」)。ユーザーが同意しない限り、反映しないのがデフォルトです。


共通:認証情報の自動スキャン

このセクションは Telegram と Slack のチャンネルトークンにのみ適用されます。 それ以外のすべての手順については、上記の認証情報のユニバーサル自動スキャンセクションを参照してください。同じパターンがすべての箇所に適用されます。

ユーザーにトークンの貼り付けを求める前に、上記の認証情報のユニバーサル自動スキャンの手順を使ってトークンを検索します。見つかった内容をユーザーに提示し、確認または変更を求めます。確認なしにトークンを使用してはいけません。


3a — Telegram(ops-telegram-autolink によるユーザー認証)

ユーザーが「すべてのチャンネル」を選択した場合でも、Telegram のフローを開始する前に必ず確認してください。 AskUserQuestion を使用します。

Set up Telegram personal account access?
  [Yes — enter my phone number and authenticate]
  [Skip Telegram]

ユーザーがスキップした場合は、$PREFS_PATH に channels.telegram = "skipped" を記録して次へ進みます。Telegram を未設定として暗黙に記録してはいけません。明示的にスキップすることで、後続の実行時にステータスヘッダーで ○ telegram (no token) が対応項目として表示されるのを防ぎます。

レート制限ガード:開始前に、$PREFS_PATH で channels.telegram が .status == "rate_limited" のオブジェクトかどうかを確認します。型ガードを使用します:if (channels.telegram | type) == "object" and .channels.telegram.status == "rate_limited"(jq:if (.channels.telegram | type) == "object" then .channels.telegram.status else "skipped" end)。retry_after が未来の時刻の場合は、ユーザーに AskUserQuestion を提示します。

Telegram is rate-limited until [time]. What would you like to do?
  [Wait and retry after cooldown — re-run /ops:setup telegram after [time]]
  [Skip Telegram for now]

レート制限期間中に send_password を実行してはいけません。すぐに失敗し、クールダウンが延長される可能性があります。ユーザーが「スキップ」を選択した場合は、$PREFS_PATH にスキップを記録して次のチャンネルへ進みます。

ボットはユーザーの DM を読めないため、/ops-inbox telegram には個人アカウントの MCP が必要です。このプラグインには bin/ops-telegram-autolink.mjs が含まれており、次の処理を行います。

  1. スカウト対象の情報源(キーチェーン → ~/.claude.json → シェルプロファイル → Doppler)を検索し、以前に取得した TELEGRAM_API_ID / TELEGRAM_API_HASH / TELEGRAM_SESSION を探します。
  2. 見つからない場合は、my.telegram.org にプレーンな HTTP リクエストを送信します(ブラウザーは使用しません。my.telegram.org はサーバー側で HTML を生成し、JavaScript を必要としません)。ブリッジファイルから取得した電話番号コードでログインし、必要に応じてアプリを作成して、api_id と api_hash を取得します。
  3. gram.js の client.start() を実行してセッション文字列を生成し、同じファイルを介して 2 つ目のコードを受け渡します。
  4. stdout に最終 JSON を出力します:{api_id, api_hash, phone, session}。

サブフロー(上記でユーザーが「はい」を選択した場合のみ実行):

  1. まずスカウトします。 以前に取得した Telegram 認証情報がキーチェーンにあるか確認します。

    for svc in telegram-api-id telegram-api-hash telegram-phone telegram-session; do
      security find-generic-password -s "$svc" -w 2>/dev/null && echo "FOUND: $svc"
    done
    

    ~/.claude.json mcpServers.telegram.env.TELEGRAM_API_ID も確認します。4 つすべてが見つかり、保存されている TELEGRAM_SESSION が StringSession としてデコードできる場合は、ユーザーに "✓ Telegram already configured (api_id=XXXXXXX, phone=+XX...)" と伝え、手順 8 に進みます。

  2. AskUserQuestion を使って、ユーザーに電話番号を尋ねます。自由入力の選択肢を 1 つだけ指定します。国別のプリセットや電話番号の例は提示せず、直接入力を促す選択肢を 1 つだけ指定してください。

    Enter your Telegram phone number (include country code, e.g. +31612345678):
      [Enter phone number — type your full number starting with +]
    

    ユーザーはこの選択肢を選び、「その他」の自由入力欄に電話番号を入力します。^\+\d{7,15}$ に一致することを検証してください。電話番号は初回実行時の抽出で一度だけ使用され、ローカルにのみ保存されることを説明してください。

  3. 2 つのコードについて警告します。 AskUserQuestion を使って、ユーザーに次のように伝えます:"Telegram will send TWO codes to your Telegram app — one for my.telegram.org web login, then a second one for gram.js auth. Have your Telegram app ready." 選択肢は [I'm ready]、[Cancel] です。

  4. 制限的なファイル権限を設定して、自動リンクスクリプトをバックグラウンドで起動します。

    (umask 077 && node "${CLAUDE_PLUGIN_ROOT}/bin/ops-telegram-autolink.mjs" --phone "$PHONE" 2>/tmp/ops-telegram-autolink.log 1>/tmp/ops-telegram-autolink.out &)
    echo $! > /tmp/ops-telegram-autolink.pid
    

    Bash ツールの run_in_background: true を使用します。umask 077 によって、すべてのブリッジファイル(ログ、出力)がモード 0600 で作成されます。.out ファイルには、gram.js セッション文字列を含む認証情報の完全な JSON が保存されます。全ユーザーから読み取り可能な場合、ローカルの任意のプロセスが Telegram アカウントへの長期間有効なアクセス権を持ち出せてしまいます。

  5. stderr ログをポーリングして、need_code イベントを確認します。 3 秒ごとに /tmp/ops-telegram-autolink.log を読み取り、まだ回答していない最新の {"type":"need_code", ...} の行を探します。見つけたら、次のようにします。

    • どのコードかを確認します。channel: "web_login"(1 つ目)または channel: "gram_auth"(2 つ目)です。
    • 自由入力欄を使って AskUserQuestion で "Enter the code Telegram just sent to your Telegram app:" と尋ねます。「数字のみ」とは言わないでください。Telegram のウェブログインコードには、文字、ハイフン、アンダースコアが含まれる場合があります(例:Zv_-ef77YSU)。自動リンクのブリッジファイルは、3~20 文字の英数字、ハイフン、アンダースコアからなる文字列を受け付けます。
    • 制限的な権限を設定して、コードを /tmp/telegram-code.txt に書き込みます。Bash: (umask 077 && printf '%s' "$CODE" > /tmp/telegram-code.txt)。umask 077 は必須です。これを設定しないと、(/tmp が drwxrwxrwt である)macOS ではファイルが全ユーザーから読み取り可能な状態で作成され、2 秒のポーリング時間内にローカルの任意のプロセスが競合してコードを読み取る可能性があります。
    • 10 秒以内にコードが読み取られたことを確認します。ls /tmp/telegram-code.txt 2>/dev/null を実行してください。10 秒後もファイルが残っている場合、スクリプトの検証用正規表現でコードが拒否されています。ログでエラーを確認してください。スクリプトを再実行したり、新しいコードを要求したりしないでください。ログイン試行を 1 回消費してしまいます。
    • 次のイベントを待ちます。
    • {"type":"need_password"} が表示された場合は、2FA を処理します。AskUserQuestion でユーザーに尋ね、(umask 077 && printf '%s' "$PW" > /tmp/telegram-password.txt) を使って /tmp/telegram-password.txt に書き込みます。コードファイルと同様に、権限を厳格化してください。2FA パスワードはワンタイムコードよりはるかに機密性が高い情報です。
  6. スクリプトの終了を待ちます。 プロセスが実行中でなくなるまでポーリングします(ps -p "$(cat /tmp/ops-telegram-autolink.pid)")。/tmp/ops-telegram-autolink.out を読み取ります。ここには api_id、api_hash、phone、session を含む JSON が 1 行だけ出力されるはずです。セキュリティに関する注意:セットアップスキルでは、次のように自動リンクを起動しているはずです。(umask 077 && node "${CLAUDE_PLUGIN_ROOT}/bin/ops-telegram-autolink.mjs" --phone "$PHONE" 2>/tmp/ops-telegram-autolink.log 1>/tmp/ops-telegram-autolink.out &)。これにより、.log ファイルと .out ファイルのモードは 0600 になります。stat -f '%Lp' /tmp/ops-telegram-autolink.out で確認し、600 が出力される必要があります。認証情報をメモリに読み込んだら、直ちに .out ファイルを shred -u(Linux)または rm -P(macOS)で削除します。

    エラーからの復旧 — 重要:ログイン試行を消費しないでください。 send_password の呼び出しはそれぞれ、Telegram のレート制限(8 時間あたり約 3~5 回)にカウントされます。自動リンクに失敗した場合:

    • "could not extract ... after 6 extraction strategies" / 抽出失敗: HTML 解析は失敗しましたが、ログインは成功しています。スクリプトを再実行しないでください。代わりに、エラーに html_snippet が含まれているか確認してください。このスニペットには、タグを除去したページテキストが表示されます。「api_id」付近に 5〜12 桁の数字があり、「api_hash」付近に 32 文字の 16 進数がある場合は、スニペットから grep/regex で直接抽出してください。スニペットにログインページやリダイレクトが表示される場合は、抽出中にセッションが期限切れになっています。
    • rate-limited: $PREFS_PATH に channels.telegram.status = "rate_limited" と channels.telegram.retry_after (現在時刻 + 8 時間) を記録します。次のチャネルに進んでください。以降の /ops:setup 実行時には retry_after を確認し、クールダウンが終了していなければ Telegram をスキップしてください。
    • コードファイルが消費されていない: /tmp/telegram-code.txt が書き込み後 10 秒以上経っても存在する場合、検証用 regex がそれを拒否しています。ファイルの内容とログを確認してください。ユーザーに別のコードを尋ねないでください。元のコードは依然として有効であり、ブリッジを修正するだけで済みます。
    • 一般的なルール: 1 回のセットアップセッションで send_password を試行できるのは最大 2 回です。1 回目の試行がレート制限以外の理由で失敗した場合は、再度試す前に根本原因を診断してください。2 回目の試行が失敗した場合は、状態を保存して次に進んでください。
  7. キーチェーン + 設定に永続化します。 macOS のみ:

    security add-generic-password -U -s telegram-api-id -a "$USER" -w "$API_ID"
    security add-generic-password -U -s telegram-api-hash -a "$USER" -w "$API_HASH"
    security add-generic-password -U -s telegram-phone -a "$USER" -w "$PHONE"
    security add-generic-password -U -s telegram-session -a "$USER" -w "$SESSION"
    

    次に、$PREFS_PATH を channels.telegram = {backend: "gram.js", api_id: "...", phone: "...", status: "configured"} で更新します。api_hash やセッションを preferences.json に書き込まないでください — これらはキーチェーンにのみ保存します。preferences.json には機密でないメタデータのみを保存します。

  8. MCP サーバーを自動構成します。 ユーザーが手動で何も貼り付けなくて済むように、認証情報をプラグインのユーザー設定に直接書き込みます:

    # Read existing user config or create empty
    USER_CONFIG="${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/user-config.json"
    mkdir -p "$(dirname "$USER_CONFIG")"
    
    # Write Telegram credentials to user config
    jq -n \
      --arg api_id "$API_ID" \
      --arg api_hash "$API_HASH" \
      --arg phone "$PHONE" \
      --arg session "$SESSION" \
      '{telegram_api_id: $api_id, telegram_api_hash: $api_hash, telegram_phone: $phone, telegram_session: $session}' \
      > "${USER_CONFIG}.tmp"
    
    # Merge with existing config if present
    if [ -f "$USER_CONFIG" ]; then
      jq -s '.[0] * .[1]' "$USER_CONFIG" "${USER_CONFIG}.tmp" > "${USER_CONFIG}.new" && mv "${USER_CONFIG}.new" "$USER_CONFIG"
      rm -f "${USER_CONFIG}.tmp"
    else
      mv "${USER_CONFIG}.tmp" "$USER_CONFIG"
    fi
    chmod 600 "$USER_CONFIG"
    

    telegram サーバーのエントリが存在する場合は、~/.claude.json の MCP サーバー設定も更新します — 認証情報を環境変数として注入します:

    # Update .claude.json mcpServers.telegram.env with actual values
    CLAUDE_JSON="$HOME/.claude.json"
    if [ -f "$CLAUDE_JSON" ] && jq -e '.mcpServers.telegram' "$CLAUDE_JSON" >/dev/null 2>&1; then
      jq --arg id "$API_ID" --arg hash "$API_HASH" --arg phone "$PHONE" --arg session "$SESSION" \
        '.mcpServers.telegram.env.TELEGRAM_API_ID = $id | .mcpServers.telegram.env.TELEGRAM_API_HASH = $hash | .mcpServers.telegram.env.TELEGRAM_PHONE = $phone | .mcpServers.telegram.env.TELEGRAM_SESSION = $session' \
        "$CLAUDE_JSON" > "${CLAUDE_JSON}.tmp" && mv "${CLAUDE_JSON}.tmp" "$CLAUDE_JSON"
    fi
    

    出力:

    ✓ Telegram configured automatically.
      API ID:  [api_id]
      Phone:   [phone]
      Session: stored in keychain + MCP config
      Restart Claude Code to activate the Telegram MCP server.
    
  9. スモークテスト (任意)。 環境変数をインラインで設定した状態で node ${CLAUDE_PLUGIN_ROOT}/telegram-server/index.js を 3 秒間起動します。認証エラーが出力されなければ、セッションは機能しています。

ユーザー向けのプライバシーに関する注意 (開始時に一度表示):

  • 電話番号とすべての認証情報はお使いのマシン上に留まります。ウィザードは、HTTP ログインフローの間に Telegram 自身のサーバーに送信する以外、それらをどこにも送信しません。
  • 別のプロジェクト用に gram.js / Telethon セッションがすでにある場合は、これをスキップして、それらの値を /plugin settings に手動で貼り付けることができます。
  • Telegram が「Sorry, too many tries. Please try again later.」と返した場合、お使いのアカウントは約 8 時間レート制限されます — ウィザードはこれを回避できません。待ってから再試行してください。

詳細: この統合の完全な運用指示、CLI リファレンス、トラブルシューティングについては ${CLAUDE_PLUGIN_ROOT}/skills/ops-comms/SKILL.md を参照してください。セットアップエージェントは、このウィザードが提供する以上の詳細が必要な場合、そのファイルを直接読み込むことができます。

3b — WhatsApp (診断 + 自己修復 + バックフィル)

WhatsApp は、最も頻繁にサイレントに壊れるチャネルです。ウィザードは単にステータスを報告して諦めるのではなく、自動診断、ドクター、修正を行う必要があります。このサブフロー全体を上から下まで実行し、システムが正常であるか、ユーザーが修復を辞退した場合にのみ停止してください。

ステップ 3b.1 — 存在確認

command -v wacli を実行します。見つからない場合は、AskUserQuestion で尋ねます: [インストールドキュメントを表示]、[WhatsApp をスキップ]。インストールドキュメントの場合、次を出力します:

wacli is not on Homebrew. Install:
  git clone https://github.com/Lifecycle-Innovations-Limited/wacli ~/src/wacli
  cd ~/src/wacli && go build -o /usr/local/bin/wacli ./cmd/wacli

そしてこのサブフローを停止します。

ステップ 3b.2 — 状態の収集

これらを並行して実行します:

wacli doctor --json 2>&1
wacli auth status --json 2>&1
wacli messages list --after="$(date -v-1d +%Y-%m-%d 2>/dev/null || date -d '1 day ago' +%Y-%m-%d)" --limit=5 --json 2>&1
wacli chats list --json 2>&1 | head -c 4000

解析:

  • doctor.data.authenticated (bool)
  • doctor.data.lock_held + doctor.data.lock_info (PID + acquired_at タイムスタンプ)
  • doctor.data.fts_enabled (bool — false の場合、検索は低下しますが、致命的ではありません)
  • messages.data.messages の長さ → これが主要な健全性シグナルです。認証済みで過去 24 時間のメッセージがゼロ = 壊れています。
  • chats の数と、そもそも値が入ったかどうか
ステップ 3b.3 — 診断と分類

次のルールを順番に適用します。最初に一致した時点で停止します。

A. 未認証 doctor.authenticated: false の場合 → 「WhatsApp には QR コードでのペアリングが必要です。別のターミナルで wacli auth を実行し、スマートフォンで QR コードをスキャンしてください(WhatsApp → リンク済みデバイス → デバイスをリンク)。その後、/ops:setup whatsapp を再実行してください。」と出力します。このサブフローはここで終了です。QR コードのスキャンを自動化しようとしてはいけません — ターミナルに向けてユーザーのスマートフォンのカメラをかざす必要があります(ルール 2 の例外)。

B. 同期が停止している(古いロック) lock_held: true で、lock_info.acquired_at が 2 分以上前であり、ロック保持プロセスの PID がまだ存在する(ps -p <pid>)場合:

  1. 既存プロセスの標準エラー出力の末尾から、バックグラウンドで wacli sync(timeout 15 wacli sync 2>&1)を実行します — または、そこに tee できない場合は次の手順に進みます。
  2. AskUserQuestion で質問します:「wacli sync プロセス(pid=N)が Xm 間、ストアロックを保持しています。停止している可能性が高いです。終了しますか?」→ [pid N を終了して同期を再起動]、[実行したままにする]。
  3. 終了する場合:kill <pid> を実行します(最初から -9 は使わないでください)。3 秒待ちます。まだ実行中なら kill -9 <pid> を実行します。ps -p <pid> で確認します。
  4. 終了後、wacli doctor --json を再実行してロックが解除されたことを確認します。次のルールに進みます。

C. アプリ状態キーの不整合(最重要) timeout 15 wacli sync 2>&1 | tee /tmp/wacli-sync-probe.log を実行します(ロックが解除されている必要があるため、B の後に実行してください)。出力を次の文字列で検索します。

  • didn't find app state key → セッションキーの不整合です。再ペアリングが必要です
  • failed to decode app state → 同じ種類のエラーです
  • Failed to do initial fetch of app state → 同じ種類のエラーです

いずれかが一致した場合:

  1. 診断結果をそのまま出力します。
    ⚠  WhatsApp session is authenticated but the app-state decryption keys
       are out of sync with your primary device. This happens when the
       linked-device session is partially wiped on the phone side.
       Symptom: sync runs but 0 messages come through.
       Fix: logout this session and re-pair via QR.
    
  2. AskUserQuestion で質問します:[ログアウトして再ペアリングの手順に進む]、[スキップ — 手動で修正する]。
  3. ログアウトする場合:wacli auth logout --json を実行し、結果を表示します。その後、次を出力します。
    Now run `wacli auth` in a separate terminal (QR-based auth — requires your phone camera).
    A QR code will appear — scan it from WhatsApp → Settings → Linked Devices → Link a device.
    When it says "Connected", come back and type "done".
    
  4. AskUserQuestion でユーザーの確認を待ちます:[完了 — 再ペアリング済み]、[キャンセル]。
  5. 完了した場合、ステップ 3b.2 を再実行して状態を再収集し、ルール D に進みます。

D. 認証済み、ロック解除済み、最近のメッセージなし、キーエラーなし 通常はキャッシュがまだない状態です。ステップ 3b.4(バックフィル)に進みます。

E. 正常(メッセージが流れている) messages.data.messages に過去 24 時間以内のエントリが 1 件以上ある場合、✓ の概要を出力し、ステップ 3b.5 に進みます。

ステップ 3b.4 — 履歴のバックフィル(バックグラウンド、非表示)

再ペアリング直後は必ず実行し、ルール D に一致した場合も実行します。ユーザーが明示的に拒否した場合を除き、スキップしてはいけません。

バックフィルはバックグラウンドで行う最適化です。詳細な出力や不安をあおるステータスメッセージを表示してはいけません。非致命的なエラーは表示せず、黙って実行します。

  1. 新しい順に上位 10 件のチャットを読み込みます。
    wacli chats list --json 2>&1 | jq -r '[.data[] | select(.jid) | {jid, name, last_msg: .last_message_ts}] | sort_by(.last_msg) | reverse | .[0:10]'
    
  2. ユーザーに「最近のチャット 10 件で履歴のバックフィルを実行しています。バックグラウンドで実行されます。」と伝えます。チャットごとの進捗や、メッセージが 0 件だった結果は表示しないでください。
  3. 各チャット JID に対して、順番に実行します(バックフィルはストアロックを共有するため、並列実行できません)。
    wacli history backfill --chat="<jid>" --count=50 --requests=2 --wait=30s --idle-exit=5s --json 2>&1
    
  4. チャットごとの出力はすべて抑制してください。 コマンドが 0 以外の値で終了した場合、エラーを黙って無視します。バックフィルの失敗はユーザーに知らせる事象ではありません。「同期したメッセージ数:0」、エラートレースバック、デバイス接続に関する説明を表示してはいけません。
  5. ループの完了後、最終的なヘルス概要(ステップ 3b.6)だけを出力します。
ステップ 3b.5 — FTS インデックスの確認(任意)

doctor.fts_enabled: false の場合、次を出力します。

ℹ  Full-text search is disabled — `wacli messages search` will use SQL LIKE (slower).
   This is a non-fatal known-limitation. See wacli docs to enable FTS5.

この確認で処理を止めてはいけません。

ステップ 3b.6 — 状態の記録

$PREFS_PATH に channels.whatsapp = "wacli" を書き込み、最後に ✓ の概要を出力します。

✓ WhatsApp — wacli authenticated, N chats

この概要行にメッセージ数やバックフィルの結果を含めてはいけません。

ステップ 3b.7 — 持続的な接続(キープアライブ)

認証とバックフィルが正常に完了したら、wacli の接続を維持して自動同期する持続的な接続を設定します。これにより、セッションをまたいでも WhatsApp を安定して利用できます。設定しない場合、リンク済みデバイスは約 14 日間操作がないと切断され、@lid JID から空のメッセージが返されます。

ops-daemon が設定されている場合(ステップ 5b)、wacli はデーモンサービスとして実行されます — 以下の単独の launchd による起動手順はスキップし、wacli の同期はデーモンによって管理されることをユーザーに伝えてください。デーモンはブートストラップ、自動バックフィル、ヘルスレポートを一元的に処理します。

単独の launchd による代替手順(ops-daemon を設定しない場合のみ):

1. キープアライブスクリプトをインストールします:

KEEPALIVE_SCRIPT="${CLAUDE_PLUGIN_ROOT}/scripts/wacli-keepalive.sh"
chmod +x "$KEEPALIVE_SCRIPT"

2. テンプレートから launchd plist を生成します:

PLIST_TEMPLATE="${CLAUDE_PLUGIN_ROOT}/scripts/com.claude-ops.wacli-keepalive.plist"
PLIST_DEST="$HOME/Library/LaunchAgents/com.claude-ops.wacli-keepalive.plist"
LOG_DIR="$HOME/.claude/plugins/data/ops-ops-marketplace/logs"
mkdir -p "$LOG_DIR" "$HOME/Library/LaunchAgents"

# Resolve bash 4+ (same logic as daemon plist)
BASH_PATH="/bin/bash"
if [[ -x /opt/homebrew/bin/bash ]]; then
  BASH_PATH="/opt/homebrew/bin/bash"
elif [[ -x /usr/local/bin/bash ]]; then
  BASH_PATH="/usr/local/bin/bash"
fi

sed -e "s|__KEEPALIVE_SCRIPT_PATH__|$KEEPALIVE_SCRIPT|g" \
    -e "s|__BASH_PATH__|$BASH_PATH|g" \
    -e "s|__LOG_DIR__|$LOG_DIR|g" \
    -e "s|__HOME__|$HOME|g" \
    "$PLIST_TEMPLATE" > "$PLIST_DEST"

3. エージェントを読み込みます:

# Unload if already loaded (idempotent)
launchctl bootout gui/$(id -u) "$PLIST_DEST" 2>/dev/null || true
launchctl bootstrap gui/$(id -u) "$PLIST_DEST"

4. 実行中であることを確認します:

3 秒待ってから、次を確認します:

launchctl print gui/$(id -u)/com.claude-ops.wacli-keepalive 2>&1 | head -5
cat "$HOME/.wacli/.health" 2>/dev/null

ヘルスファイルに status=connected または status=needs_reauth と表示されていれば、デーモンは動作しています。次を出力してください:

✓ WhatsApp keepalive — launchd agent installed and running
  Persistent sync active. Auto-restarts on disconnect.
  Health: ~/.wacli/.health | Logs: ~/.claude/plugins/data/ops-ops-marketplace/logs/

status=needs_reauth の場合は、ステップ 3b.3 のルール C に従って、直ちに再ペアリングの手順を開始してください。

5. キープアライブによる自動修復の仕組み:

キープアライブスクリプト(wacli-keepalive.sh)は、次の障害に自動的に対処します:

障害自動修復
孤立した wacli プロセスがロックを保持古い PID を終了し、ロックを解除します
接続の切断(WhatsApp サーバーの再起動)launchd が 60 秒以内に再起動します
アプリ状態キーの同期ずれヘルスファイルに needs_reauth を書き込みます — ops スキルがこれを検知し、QR コードの表示を促します
認証の期限切れneeds_auth を書き込みます — 同じプロンプト手順に進みます
スクリプトのクラッシュlaunchd の KeepAlive=true により直ちに再起動します(60 秒間のスロットリングあり)

6. 他の ops スキル向けヘルスファイルの仕様:

WhatsApp を使用するすべての ops スキル(ops-inbox、ops-comms、ops-go)は、wacli コマンドを実行する前に ~/.wacli/.health を確認する必要があります。status=needs_auth または status=needs_reauth の場合:

  1. 診断結果をユーザーに表示します:
    ⚠ WhatsApp needs re-authentication.
    Run `wacli auth` in a separate terminal and scan the QR code with your phone
    (QR-based auth — exception to Rule 2). Then type "done" to continue.
    
  2. AskUserQuestion を使用します:[Done — re-paired]、[Skip WhatsApp]。
  3. Done の場合:launchctl kickstart -k gui/$(id -u)/com.claude-ops.wacli-keepalive でキープアライブデーモンを再起動し、ヘルスファイルが更新されるまで 5 秒待ちます。

これにより、WhatsApp の接続が壊れた状態のままユーザーが気づかずに取り残されることはありません。すべての ops スキルが問題を表面化させ、修復できるように案内します。

詳しい説明: この連携の運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-comms/SKILL.md と ${CLAUDE_PLUGIN_ROOT}/skills/ops-inbox/SKILL.md を参照してください。このウィザードで提供される内容以上の詳細が必要な場合は、セットアップエージェントがそれらのファイルを直接読み込めます。

3c — メール

メールには、次の順序で試す 2 つのバックエンドがあります:

優先:gog CLI

gog は、ops-inbox と ops-comms がデフォルトで呼び出すメールとカレンダーの CLI です。独自の OAuth トークンを ~/.gog/token.json に持つ、単体で動作するバイナリです。読み取りと送信の両方の権限があり、Claude Desktop の設定は不要です。

  1. command -v gog で PATH 上に gog があることを確認します。
  2. インストールされている場合は、gog auth status 2>&1 || true を実行し、出力を表示します。
    • 認証状態が赤(未認証/トークンの期限切れ/終了コードが 0 以外)の場合は、Bash ツールで run_in_background: true を指定して gog auth add "$USER_EMAIL" --services gmail,calendar,drive,contacts,docs,sheets を実行します(OAuth フロー用のブラウザーが開きます)。ユーザーに「Gmail の OAuth 認証を行うためブラウザーを開きます。そこでサインインを完了してから、『done』と入力してください。」と伝えます。AskUserQuestion を使用します:[Done — authenticated]、[Skip email]。
    • 認証状態が緑の場合は、次を実行して確認します:
      gog gmail labels list --json 2>&1 | head -5
      
      これが labels 配列を含む JSON を返す場合、gog は認証済みで、Gmail API も動作しています。✓ と報告します。出力がエラーまたは空の場合は、動作していないものとして扱い、ユーザーに gog auth add <email> --services gmail,calendar,drive,contacts,docs,sheets を再実行するよう案内します。
    • $PREFS_PATH に channels.email = "gog" を記録して、ここで終了します。
フォールバック:Claude Gmail MCP コネクタ

gog が PATH にない場合は、検出器の mcp_configured 配列を確認し、gmail、google-mail、または claude_ai_Gmail(大文字と小文字を区別しない)に一致するエントリーを探します。これらは、Anthropic の Gmail コネクタまたはユーザーがインストールした Gmail MCP サーバーによく使われる名前です。

  1. Gmail MCP が設定されている場合は、AskUserQuestion で質問します。

    • [Gmail MCP を使う(読み取り専用のフォールバック)]
    • [代わりに gog をインストール — ドキュメントを表示]
    • [メールをスキップ]
  2. 「Gmail MCP を使う」を選択した場合は、$PREFS_PATH に channels.email = "mcp:<name>"(<name> は見つかった実際の MCP サーバー名)を記録し、次の警告をそのまま表示します。

    ⚠  Using the Gmail MCP connector as a fallback.
       Read operations (list inbox, search, fetch) will work.
       SEND operations will fail until you explicitly grant send permissions
       in Claude Desktop → Settings → Connectors → Gmail → Permissions.
       The ops plugin cannot grant those permissions for you — it's a Claude
       Desktop-side setting tied to your account.
       If you want unattended sending from ops-comms, install `gog` instead.
    
  3. 「代わりに gog をインストール」を選択した場合は、OS に適したインストールコマンドを表示します。

    OSコマンド
    macOS / Linuxbrewbrew install gogcli
    Windowswinget install -e --id steipete.gogcli
    Arch Linuxyay -S gogcli
    ソースからgit clone https://github.com/steipete/gogcli.git && cd gogcli && make

    ドキュメント:https://gogcli.sh/ · リポジトリ:https://github.com/steipete/gogcli

    インストール後、アカウントごとに一度認証します。

    gog auth credentials /path/to/client_secret.json
    gog auth add [email protected] --services gmail,calendar,drive,contacts,docs,sheets
    

    リフレッシュトークンは OS のキーチェーン(macOS の Keychain、Linux の Secret Service / libsecret、Windows の Credential Manager)に保存されます。その後、このサブフローを終了し、ユーザーが /ops:setup email を再実行するまで待ちます。

どちらも利用できない場合
  1. gog がなく、Gmail MCP も設定されていない場合は、AskUserQuestion で質問します。
    • [gog をインストール — ドキュメントを表示]
    • [Gmail MCP を追加 — ドキュメントを表示] → claude mcp add gmail を表示し、その後ユーザーに /ops:setup email を再実行するよう伝えます
    • [今回はメールをスキップ]
  2. ユーザーの選択にかかわらず、結果の状態を $PREFS_PATH に記録します(channels.email = "gog"、channels.email = "mcp:<name>"、またはキーを省略)。

詳しくはこちら: この統合の運用手順、CLI リファレンス、トラブルシューティングの詳細は、${CLAUDE_PLUGIN_ROOT}/skills/ops-inbox/SKILL.md と ${CLAUDE_PLUGIN_ROOT}/skills/ops-comms/SKILL.md を参照してください。このウィザードの説明だけでは不十分な場合、セットアップエージェントはこれらのファイルを直接読み込めます。

3d — Slack(scout + ops-slack-autolink)

Slack の公式 API では、便利なスコープの多くにワークスペース管理者の承認が必要です。slack-mcp-server MCP は、ユーザーごとのブラウザーセッショントークン(xoxc + xoxd)を使うため、管理者の承認は不要です。プラグインには bin/ops-slack-autolink.mjs が含まれており、次の処理を行います。

  1. フェーズ 1 — scout — 抽出済みのトークンが以下に存在するか確認します。
    • ~/.claude.json mcpServers.slack.env(Claude Code がトークンを保存する場所)
    • プロセス環境変数(SLACK_MCP_XOXC_TOKEN / SLACK_MCP_XOXD_TOKEN / SLACK_BOT_TOKEN)
    • macOS のキーチェーン(slack-xoxc、slack-xoxd)
    • シェルのプロファイルファイル(~/.zshrc、~/.bashrc、~/.zprofile、~/.envrc)
    • Doppler(doppler secrets --json)
  2. フェーズ 2 — Playwright による抽出 — 何も見つからなかった場合に限り、永続プロファイルの Chromium を起動し、https://app.slack.com/client/ を開いて、ユーザーにログインを求めます(ヘッドレス実行では既存のセッションを使用します)。その後、localStorage.localConfig_v2.teams[teamId].token から xoxc-... を、Cookie Jar から d=... Cookie(xoxd-...)を取得します。

maorfr/slack-token-extractor(Python → Node)から移植しました。

サブフロー:

  1. まず scout を実行します。 次を実行します。

    node "${CLAUDE_PLUGIN_ROOT}/bin/ops-slack-autolink.mjs" --scout-only 2>/tmp/ops-slack.log
    

    標準出力の JSON を解析します。xoxc_token と xoxd_token があり、空でない場合は、"✓ Slack already configured (source=XXX)" と報告してステップ 5 に進みます。

  2. 既存のトークンがない場合は、AskUserQuestion で質問します。

    • [Playwright でトークンを抽出(推奨)] → ヘッド付きモードで autolink を実行します。
    • [トークンを手動で貼り付けます] → 2 回の自由記述式 AskUserQuestion で xoxc-... と xoxd-... を収集します。
    • [Slack をスキップ]
  3. Playwright のパスの場合:autolink をバックグラウンドで起動します。

    (umask 077 && node "${CLAUDE_PLUGIN_ROOT}/bin/ops-slack-autolink.mjs" \
      --workspace "https://app.slack.com/client/" \
      2>/tmp/ops-slack-autolink.log 1>/tmp/ops-slack-autolink.out &)
    echo $! > /tmp/ops-slack-autolink.pid
    

    {"type":"need_login"} がログに記録されるまでポーリングします。表示されたら、AskUserQuestion を使用します。 "デスクトップで Chromium ウィンドウが開いているはずです。そこで Slack にログインしてから、[Done] を選択してください。"。「Done」を選択したら、touch /tmp/slack-login-done を実行します。スクリプトが完了すると、抽出したトークンが /tmp/ops-slack-autolink.out に書き込まれます。

  4. Playwright がインストールされていない場合(スクリプトが playwright is not installed で終了する場合)は、次の選択肢を提示します。

    • [Playwright を今すぐインストール] → cd ${CLAUDE_PLUGIN_ROOT}/telegram-server && npm install playwright && npx playwright install chromium を実行します(バックグラウンドで実行、約 150 MB のダウンロード、進捗を報告)。
    • [手動貼り付けに切り替える] → 手順 2 の手動パスに進みます。
  5. トークンを検証します。 正確な構文で Slack 認証エンドポイントを呼び出します。

    curl -s -H "Authorization: Bearer XOXC_TOKEN" -b "d=XOXD_TOKEN" "https://slack.com/api/auth.test"
    

    {"ok":true, "team_id":"T...", "user_id":"U...", "url":"https://<workspace>.slack.com/"} が返ることを確認します。ok:false の場合は、エラーを表示して再度尋ねます。

  6. 保存します。

    • キーチェーン:security add-generic-password -U -s slack-xoxc -a "$USER" -w "$XOXC"; security add-generic-password -U -s slack-xoxd -a "$USER" -w "$XOXD"。
    • $PREFS_PATH → channels.slack = {backend: "mcp:slack", team_id: "...", source: "...", status: "configured"}。生のトークンを preferences.json に保存しないでください。トークンはキーチェーンにのみ保存します。
  7. Claude Code プラグイン設定に接続します。 次の手順を表示します。

    Slack tokens saved to keychain. To activate the MCP, Claude Code needs them
    in ~/.claude.json. Since this skill can't write to ~/.claude.json directly,
    either:
      a) Run: claude mcp add slack --transport stdio -- npx -y slack-mcp-server@latest --transport stdio
         and Claude Code will prompt for the env vars.
      b) Manually paste the xoxc + xoxd into /plugin settings for the Slack MCP.
    

    (自動書き込みを行わない理由:ユーザーレベルのフィードバックによると、~/.claude.json は Claude Code の内部ファイルであり、プラグインはこれに触れてはなりません。MCP の登録は Claude Code の責任です。)

  8. スモークテスト:トークンを使用して https://slack.com/api/conversations.list?limit=1 を呼び出します。応答に ok:true と少なくとも 1 つのチャンネルが含まれることを確認します。

プライバシーに関する注意事項:

  • トークンはブラウザーのセッションがアクティブな間有効です。通常、Slack を定期的に使用していれば数週間から数か月間有効です。MCP が 401 を返し始めた場合は、/ops:setup slack を再実行してください。
  • Slack からログアウトすると d Cookie が無効になり、MCP が動作しなくなります。再抽出するには /ops:setup slack を使用してください。
  • Slack の利用規約では、自分のアカウントで個人用セッショントークンを使用することが認められています。このフローを、自分が所有していないアカウントへのアクセスに使用しないでください。

**詳細:**この連携の運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-comms/SKILL.md と ${CLAUDE_PLUGIN_ROOT}/skills/ops-inbox/SKILL.md を参照してください。このウィザードより詳しい情報が必要な場合、セットアップエージェントはこれらのファイルを直接読み込めます。

3e — Notion(MCP 連携)

Notion のフローを開始する前に、必ず確認してください — ユーザーが「すべてのチャンネル」を選択した場合も同様です。AskUserQuestion を使用します。

Set up Notion workspace integration?
  [Yes — configure Notion]
  [Skip Notion]

ユーザーがスキップした場合は、$PREFS_PATH に channels.notion = "skipped" を記録して次に進みます。

検出
  1. 既存の claude.ai Notion 連携を確認します。 検出器の mcp_configured 配列を調べ、Notion、claude_ai_Notion、または notion に一致するエントリがあるか確認します。見つかった場合は、NOTION_MCP_ENABLED=true に設定して検証に進みます。

  2. セルフホスト型 Notion MCP サーバーを確認します。 ~/.claude/settings.json に mcpServers.notion があるか、引数またはコマンドに notion を含むエントリがあるかを調べます。

セットアップ方法

方法 A — Claude.ai 連携(推奨):

既存の連携が検出されなかった場合は、AskUserQuestion を提示します。

How would you like to connect Notion?
  [Claude.ai integration (Recommended) — add via claude.ai settings]
  [Self-hosted MCP — use your own Notion API key]
  [Skip Notion]

claude.ai 連携の場合:

  1. ユーザーに次のように伝えます:「claude.ai > Settings > Integrations > Notion で Notion 連携を追加してください。ワークスペースへのアクセスを許可してから、『done』と入力してください。」
  2. AskUserQuestion を使用します:[完了 — 接続済み]、[Notion をスキップ]
  3. 「Done」が選択されたら、簡単なクエリで mcp__claude_ai_Notion__notion-search をテストして検証します。

方法 B — セルフホスト型 MCP:

  1. 既存の Notion API キーがあるかキーチェーンを調べます。
    security find-generic-password -s "notion-api-key" -w 2>/dev/null || \
    security find-generic-password -s "NOTION_API_KEY" -w 2>/dev/null || echo ""
    
  2. 見つからない場合は、ユーザーに尋ねます。
    Enter your Notion integration token (starts with ntn_):
      Create one at https://www.notion.so/my-integrations
      [Paste token now]  [Skip Notion]
    
  3. トークンを保存します。
    security add-generic-password -s "notion-api-key" -a "claude-ops" -w "$TOKEN" -U
    
  4. ~/.claude/settings.json の mcpServers.notion に MCP サーバー設定を追加します。
検証

連携をテストします(バックグラウンドで実行)。

# For claude.ai: integration auto-detected — test via MCP tool call
# For self-hosted: verify API key works
if [ -n "$NOTION_API_KEY" ]; then
  curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $NOTION_API_KEY" -H "Notion-Version: 2022-06-28" https://api.notion.com/v1/users/me | grep -q "200" && echo "OK" || echo "FAIL"
else
  echo "OK — claude.ai integration (verify via MCP tool call after restart)"
fi
確定
  1. ~/.claude/settings.json の env セクションで NOTION_MCP_ENABLED=true を設定します
  2. $PREFS_PATH に channels.notion = {"backend": "mcp:notion", "status": "configured", "source": "<claude-ai|self-hosted>"} を記録します
  3. $PREFS_PATH の default_channels 配列に "notion" を追加します
  4. 次を出力します:✓ Notion — workspace connected via [source]

詳しくは: Notion MCP ツールの詳細なリファレンスとトラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-inbox/CHANNELS.md を参照してください。

3f — カレンダー

カレンダーはメッセージングチャネルではありませんが、ほかのすべての ops スキル(ブリーフィング、/ops-next、/ops-go)では、ユーザーの予定を把握することで大きなメリットが得られます。会議によって集中作業が中断される時間、デプロイ可能な時間帯、出張日などが分かります。このウィザードでは、メールと同じ方法で設定します。まず gog calendar を使い、利用できない場合は Google Calendar MCP コネクターを代替手段として使います。

推奨:gog calendar

gog(gogcli バイナリ。ステップ 3c を参照)はすでにメールに対応しており、同じバイナリで同じ OAuth トークンを使って gog calendar も利用できます。ステップ 3c が正常に完了していれば、追加の認証は不要です。注意:gog cal は有効なエイリアスではありません。必ず gog calendar を使ってください。

  1. command -v gog で、gog が PATH にあるか確認します。
  2. インストール済みで、ステップ 3c ですでに認証済みの場合は、次を実行して確認します:
    gog calendar calendars --json 2>&1 | head -20
    
    カレンダーのメタデータを含む JSON が返された場合は、$PREFS_PATH に channels.calendar = "gog" を記録し、✓ Calendar — gog calendar と出力します。ここで終了します。
  3. gog はインストール済みだが、カレンダーのスコープがない場合(一般的なエラー:insufficient scope または 403 insufficient_permissions)は、次を出力します:
    Your gog OAuth token doesn't include the calendar scope.
    Re-add the account with the calendar service via Bash tool with `run_in_background: true`:
      gog auth add "$USER_EMAIL" --services gmail,calendar,drive,contacts,docs,sheets
    Tell the user: "Opening browser for Calendar OAuth — complete the sign-in there, then type 'done'." Use `AskUserQuestion`: `[Done — re-authorized]`, `[Skip calendar]`.
    
    スキルから再認証しようとしないでください。ブラウザーを使うフローのためです。
代替手段:Claude Google Calendar MCP コネクター
  1. gog が PATH にない場合は、検出器の mcp_configured 配列を調べ、大文字と小文字を区別せずに calendar、google-calendar、claude_ai_Calendar のいずれかに一致する項目を探します。
  2. 見つかった場合は、AskUserQuestion で次を尋ねます:
    • [Google Calendar MCP を使う(読み取り専用の代替手段)]
    • [代わりに gog をインストールする — ドキュメントを表示]
    • [カレンダーをスキップ]
  3. 「Google Calendar MCP を使う」を選択した場合は、$PREFS_PATH に channels.calendar = "mcp:<name>" を記録し、次の警告を一字一句そのまま出力します:
    ⚠  Using the Google Calendar MCP connector as a fallback.
       Read operations (list calendars, fetch events, check free/busy) will work.
       WRITE operations (create events, decline meetings, reschedule) will fail
       until you explicitly grant write permissions in
       Claude Desktop → Settings → Connectors → Google Calendar → Permissions.
       The ops plugin cannot grant those permissions for you.
       If you want ops-next to auto-block focus time or ops-comms to confirm
       meetings, install `gog` instead.
    
  4. 「代わりに gog をインストールする」を選択した場合は、ステップ 3c と同じ npm → bun → ソースクローンの順で、Bash 経由でインストールを実行します(ルール 2)。スニペットを直接記述するか、${CLAUDE_PLUGIN_ROOT}/bin/ops-setup-install gog を呼び出します(ルール 4 に従ってバックグラウンドで実行)。4 回すべて試して失敗した場合に限り、手動でのインストール手順を表示します。
どちらも利用できない場合
  1. gog がなく、Calendar MCP も設定されていない場合は、次を尋ねます:
    • [gog をインストールする — ドキュメントを表示]
    • [Google Calendar MCP を追加する — ドキュメントを表示] → claude mcp add google-calendar を出力し、その後 /ops:setup calendar を再実行するようユーザーに伝えます
    • [カレンダーをスキップ]
重要な理由(スキル内の補足)

後続のスキル(/ops-go、/ops-next、/ops-fires)は、$PREFS_PATH の channels.calendar を読み取り、今日の予定と出力を照合するかどうかを判断します:

  • ブリーフィングでは「午後 2 時に定例会議があるため、今はリファクタリングを始めないでください」と伝えます
  • /ops-next は、会議まで 30 分を切っている場合、集中作業の優先度を下げます
  • /ops-fires は、本番環境のインシデントが予定された通話中に発生した場合に警告します したがって、状況を考慮したブリーフィングを希望するユーザーにとって、このセクションは省略できません。

詳しくは: この連携の詳しい運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-go/SKILL.md を参照してください(カレンダーのコンテキストは /ops:go のブリーフィングに反映されます)。このウィザードより詳しい情報が必要な場合、セットアップエージェントはこのファイルを直接読み込めます。

3g — Doppler(シークレット管理)

Doppler は、実行時に環境変数を挿入するシークレットマネージャーです。設定すると、すべての ops スキルで、ドットファイルやキーチェーンを読み取る代わりに doppler secrets get を使ってシークレットを照会できます。ウィザードでは、インストール状況、認証状態、デフォルトのプロジェクトコンテキストを確認します。

ステップ 3g.1 — インストールの確認
command -v doppler

見つからない場合は、uname -s / $OSTYPE / $OS を使ってホスト OS を検出し、適切なインストールコマンドを選びます。AskUserQuestion で質問します。

Doppler CLI is not installed.
  [Install now — <os-specific command>]
  [Skip Doppler]

OS 固有のコマンドは次のとおりです。

OSインストールコマンド
macOS / Linuxbrewbrew install dopplerhq/cli/doppler
Debian / Ubuntucurl -Ls https://cli.doppler.com/install.sh | sudo sh
Fedora / RHELsudo rpm --import https://packages.doppler.com/public.key && sudo dnf install -y doppler
Arch Linuxyay -S doppler-cli
Alpineapk add --no-cache doppler-cli
Windows (winget)winget install Doppler.doppler
Windows (scoop)scoop bucket add doppler https://github.com/DopplerHQ/scoop-doppler.git; scoop install doppler

選択したコマンドをバックグラウンドで実行し、標準出力と標準エラー出力を取得して、成功または失敗を報告します。ユーザーがスキップした場合は、$PREFS_PATH に secrets_manager: "none" を記録して、このサブフローを終了します。

ステップ 3g.2 — 認証状態

次を実行します。

doppler me --json 2>&1

JSON を解析します。出力に "error" が含まれているか、終了コードが 0 以外の場合、ユーザーは認証されていません。次を表示します。

Doppler is not authenticated. Running `doppler login` now...

Bash ツールで doppler login を run_in_background: true にして実行します(OAuth フローのためにブラウザーが開きます)。ユーザーに「Doppler OAuth のためにブラウザーを開いています。そこでサインインを完了し、その後「done」と入力してください」と伝えます。AskUserQuestion を使用します:[完了 — 認証済み]、[Doppler をスキップ]。完了が選択されたら、確認のために doppler me --json を再実行します。認証されている場合、doppler me は name と email を含む JSON を返します。次を確認します。

✓ Doppler authenticated as <name> (<email>)

このセッション内の doppler me の出力に含まれていた場合を除き、名前やメールアドレスを表示してはいけません。

ステップ 3g.3 — プロジェクトのコンテキスト

認証済みの場合、利用可能なプロジェクトを一覧表示します。

doppler projects --json 2>&1

プロジェクトオブジェクトの配列を解析します。singleSelect を指定した AskUserQuestion で提示します。1 回の呼び出しにつき選択肢は最大 4 件です。プロジェクトが 3 件を超える場合はページ分割し、各ページでプロジェクト 3 件と [その他のプロジェクト...] を表示します。最終ページでは、常に [スキップ — デフォルトプロジェクトを設定しない] を最後の選択肢にします。

Select your default Doppler project (page 1):
  [ ] my-app
  [ ] my-api
  [ ] my-service
  [ ] More projects...

ユーザーがプロジェクトを選択したら、その設定を取得します。

doppler configs --project <selected_project> --json 2>&1

singleSelect を指定した AskUserQuestion で利用可能な設定を提示します(選択肢は最大 4 件。必要に応じてページ分割します)。

Select the default config for <project>:
  [ ] dev
  [ ] staging
  [ ] production

選択内容を $PREFS_PATH に書き込みます(上書きせず、マージします)。

{
  "secrets_manager": "doppler",
  "doppler": {
    "project": "<selected>",
    "config": "<selected>"
  }
}

確認メッセージを表示します。

✓ Doppler default context set: <project>/<config>
ステップ 3g.4 — エージェント向けの説明

このメモを表示し、セッション内で確認できるようにします。

All ops skills can now query secrets via:

  doppler secrets get <KEY> --plain --project <project> --config <config>

For example:
  doppler secrets get TELEGRAM_BOT_TOKEN --plain --project my-app --config dev

The project and config above are the defaults saved to preferences.
Individual skills can override with --project / --config flags.

詳細: Doppler に付属する専用スキルはありません。後続のスキルが $PREFS_PATH の secrets_manager / doppler.* の値をどのように使用し、実行時に doppler:KEY_NAME の参照を解決するかについては、${CLAUDE_PLUGIN_ROOT}/docs/memories-system.md(「Runtime Context」セクション)を参照してください。このウィザードより詳しい情報が必要な場合、セットアップエージェントはそのファイルを直接読み込めます。

ステップ 3g.5 — Doppler MCP サーバー

CLI の設定と認証が完了したら、公式の @dopplerhq/mcp-server MCP 統合のセットアップを提案します。これにより、シェルコマンドを実行することなく、Claude が Doppler のシークレットにツール経由で直接アクセスできるようになります。

  1. 利用可能か確認する:バックグラウンドで npx -y @dopplerhq/mcp-server --help 2>&1 を実行します。終了コードが 0 の場合、パッケージは利用可能です。

  2. サービス用トークンを生成する:ユーザーがステップ 3g.3 でプロジェクト/設定を選択している場合は、スコープを限定したトークンを生成します:

    doppler configs tokens create mcp-server-token --project <project> --config <config> --plain 2>/dev/null
    

    コマンドが失敗した場合、またはプロジェクト/設定が選択されていない場合は、次のように尋ねます:

    Doppler MCP Server needs a token. Options:
      [Generate from CLI (requires project/config)]
      [Paste a token manually]
      [Skip MCP server]
    
  3. トークンを userConfig に保存する:プラグインの userConfig 内にある doppler_token にトークンを書き込みます(実行時に ${user_config.doppler_token} を介して .mcp.json に渡されます)。選択されている場合は doppler_project と doppler_config も保存します。

  4. スモークテスト:MCP サーバーを起動できることを確認します:

    DOPPLER_TOKEN="<token>" timeout 10 npx -y @dopplerhq/mcp-server --help 2>&1
    

    終了コードが 0 の場合、サーバーは正常に動作しています。

  5. 確認:

    ✓ Doppler MCP Server configured — secrets accessible via MCP tools (mcp__doppler__*)
    
  6. エージェントへの注意事項:

    With the MCP server configured, skills can now query secrets directly via
    MCP tool calls (mcp__doppler__*) instead of shelling out to `doppler secrets get`.
    The Doppler CLI remains available as a fallback when the MCP server is unavailable.
    
3h — パスワードマネージャー(認証情報保管庫)

Ops エージェントは、ユーザーに代わって認証情報(API キー、データベースのパスワード、サービス用トークン)を頻繁に検索する必要があります。このステップでは、$PREFS_PATH に保存される標準コマンドテンプレートを介して、そうした検索を自動化できるようパスワードマネージャーを設定します。

ステップ 3h.1 — インストール済みのマネージャーを自動検出する

次のコマンドを並行して実行します:

command -v op 2>/dev/null && op account list --format=json 2>&1    # 1Password CLI
command -v dcli 2>/dev/null && dcli sync 2>&1                       # Dashlane CLI
command -v bw 2>/dev/null && bw status --raw 2>&1                   # Bitwarden CLI
security find-generic-password -s "test" 2>&1 | head -1             # macOS Keychain (always available)

各結果を解析し、authenticated、needs_unlock、not_installed、available のいずれかに分類します(Keychain は常に available です)。

ステップ 3h.2 — 検出結果を提示する

AskUserQuestion を使い、検出された項目のみを表示します。1 回の呼び出しにつき選択肢は最大 4 つです。 macOS Keychain と Skip は常に表示されるため、1 回の呼び出しで表示できる検出済みマネージャーは最大 2 つです。3 つすべての CLI(1Password、Dashlane、Bitwarden)がインストールされている場合は、2 回に分けて呼び出します:

検出された CLI マネージャーが 2 つ以下の場合(一般的なケース — 1 回の呼び出しで表示できます):

Password managers found:
  [1Password — authenticated as <account>]
  [Dashlane — needs unlock]
  [macOS Keychain — always available]
  [Skip — don't connect a password manager]

検出された CLI マネージャーが 3 つすべての場合(まれなケース — 2 回に分けて呼び出します): 呼び出し 1:

  [1Password — authenticated as <account>]
  [Dashlane — needs unlock]
  [Bitwarden — <status>]
  [More options...]

呼び出し 2:

  [macOS Keychain — always available]
  [Skip — don't connect a password manager]

インストールされていないマネージャーは表示しないでください。macOS Keychain と Skip は必ず表示します。CLI が 1 つもインストールされていない場合は、[macOS Keychain — always available] と [Skip] のみを表示します。

ステップ 3h.3 — 選択したマネージャーを設定する

1Password(op):

  1. 認証を確認します:op account list --format=json
  2. 出力が空、または終了コードが 0 以外(サインインしていない)の場合は、次のように表示します:
    1Password CLI is installed but not signed in.
    Run `op signin` via Bash tool with `run_in_background: true`, then re-run /ops:setup vault.
    
    このサブフローを終了します。
  3. 認証済みの場合は、ユーザーがデフォルトを選べるように保管庫を一覧表示します:
    op vault list --format=json
    
    AskUserQuestion(単一選択)を使って保管庫名を提示します。選択された保管庫を password_manager_config.vault に設定します。
  4. クエリ構文を記録します:
    op item get "{{name}}" --fields label=password --format=json
    

Dashlane(dcli):

  1. 認証を確認します:dcli sync
  2. dcli sync が失敗するか、未設定エラーを返す場合は、次のように表示します:
    Dashlane CLI is installed but not configured.
    Run `dcli configure` via Bash tool, then re-run /ops:setup vault.
    
    このサブフローを終了します。
  3. クエリ構文を記録します:
    dcli password --filter "{{name}}" --output json
    
  4. 保管庫の選択は不要です。Dashlane はフラットな名前空間を使用します。

Bitwarden(bw):

  1. bw status --raw を実行し、JSON の status フィールドを解析して認証を確認します。
    • "unauthenticated" → 次のように表示します:
      Bitwarden CLI はインストールされていますが、ログインしていません。
      Bash ツールで `run_in_background: true` を指定して `bw login` を実行し、その後、/ops:setup vault を再実行してください。
      
      このサブフローを終了します。
    • "locked" → 次のように表示します:
      Bitwarden の保管庫はロックされています。
      Bash ツールで `bw unlock --raw` を実行し、セッショントークンを取得して、後続のコマンド用に `BW_SESSION` としてエクスポートしてください。その後、/ops:setup vault を続行してください。
      
      このサブフローを終了します。
    • "unlocked" → 続行します。
  2. クエリ構文を記録します:
    bw get item "{{name}}" --pretty
    
  3. 保管庫の選択は不要です。Bitwarden はセッションごとにロック解除済みの保管庫を 1 つ使用します。

macOS Keychain:

  1. 認証確認は不要です。常に利用可能です。
  2. ユーザーへの注意事項:
    macOS Keychain is always available but is limited to items stored locally.
    No cross-device sync. Best for machine-specific secrets (API keys added via
    `security add-generic-password`).
    
  3. クエリ構文を記録します:
    security find-generic-password -s "{{name}}" -w
    
Step 3h.4 — 設定に書き込む

ユーザーがマネージャーを選択して設定したら、$PREFS_PATH に書き込みます。

{
  "password_manager": "<1password|dashlane|bitwarden|keychain>",
  "password_manager_config": {
    "vault": "<vault name, or omit if not applicable>",
    "query_cmd": "<template with {{name}} placeholder>"
  }
}

既存のファイルとマージします(jq '. + { ... }')。上書きはしないでください。1Password の例:

{
  "password_manager": "1password",
  "password_manager_config": {
    "vault": "Private",
    "query_cmd": "op item get \"{{name}}\" --fields label=password --format=json"
  }
}

ユーザーがスキップを選択した場合は、"password_manager": "none" と書き込みます。これにより、ユーザーが明示的に /ops:setup vault を実行しない限り、次回以降の実行で再度尋ねられることはありません。

Step 3h.5 — エージェント向けに記録する

保存後、この注記を一度だけ表示します。

All ops skills can now query credentials via your configured password manager.
The query command template is in preferences.json under password_manager_config.query_cmd.
Replace {{name}} with the item name — e.g. "GitHub PAT", "AWS root key", "my-project-db".

To query manually:
  op item get "GitHub PAT" --fields label=password --format=json   (1Password example)
  security find-generic-password -s "my-project-db" -w               (Keychain example)
ダッシュボード表示

Step 0b のステータスヘッダーを更新し、Vault のステータスを含めます。

 Vault:       ✓ 1password (vault: Private)

スキップされた場合は ○ none、マネージャーがインストール済みでもアクセスできない場合は ✗ locked を使用します。

完了時の概要(Step 8)

最終サマリーブロックに含めます。

 ✓ Vault:      1password → Private vault

password_manager が "none" または未設定の場合、この行は完全に省略します。

呼び出しのショートカット

ショートカットの表に追加します:vault、password-manager、pm → Step 3h

詳細: パスワードマネージャー連携専用のスキルは付属しません。下流のスキルが $PREFS_PATH から password_manager と関連する Vault 参照を解決する方法については、${CLAUDE_PLUGIN_ROOT}/docs/memories-system.md(Runtime Context セクション)を参照してください。プライバシーとセキュリティに関するガイダンスは、この SKILL.md に記載されています(API ハッシュ/セッション文字列はキーチェーンのみに保存し、ブリッジファイルには umask 077 を使用します)。このウィザードより詳しい情報が必要な場合、セットアップエージェントはそのファイルを直接読み込めます。


3i — Eコマース(Shopify + 動的パートナー)
Step 3i.1 — 既存の Shopify 認証情報を自動スキャンする

何かを尋ねる前に、Shopify 関連のすべての変数を対象として、ユニバーサル認証情報自動スキャンを同時に実行します。

# --- Token scan (API credentials) ---

# Scan shell env
printenv SHOPIFY_ACCESS_TOKEN SHOPIFY_ADMIN_TOKEN SHOPIFY_STORE_URL SHOPIFY_ADMIN_API_ACCESS_TOKEN 2>/dev/null

# Scan shell profiles
grep -h 'SHOPIFY\|myshopify' ~/.zshrc ~/.bashrc ~/.zprofile ~/.envrc 2>/dev/null | grep -v '^#'

# Scan Doppler across all projects
for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
  doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
    jq -r --arg proj "$proj" 'to_entries[] | select(.key | test("SHOPIFY|STORE")) | "\(.key)=\(.value.computed) (doppler:\($proj)/prd)"'
done

# Scan Dashlane for API tokens
dcli password shopify --output json 2>/dev/null | jq -r '.[] | select(.password != null and .password != "") | "\(.title): \(.url) → token found"'

# Scan macOS Keychain
security find-generic-password -s "shopify-admin-token" -w 2>/dev/null
security find-generic-password -s "shopify-access-token" -w 2>/dev/null

# Scan OpenClaw
jq -r '.agents.defaults.env | to_entries[] | select(.key | test("SHOPIFY")) | "\(.key)=\(.value)"' ~/.openclaw/openclaw.json 2>/dev/null

# Check existing prefs
jq -r '.ecom.shopify // empty' "$PREFS_PATH" 2>/dev/null

# --- Store URL discovery (even if no tokens found) ---
# Scan Chrome history for myshopify.com admin URLs
sqlite3 ~/Library/Application\ Support/Google/Chrome/Default/History \
  "SELECT DISTINCT replace(replace(url, 'https://', ''), 'http://', '') FROM urls WHERE url LIKE '%myshopify.com/admin%' OR url LIKE '%admin.shopify.com/store/%' ORDER BY last_visit_time DESC LIMIT 10" 2>/dev/null | \
  grep -oE '[a-z0-9-]+\.myshopify\.com|admin\.shopify\.com/store/[a-z0-9-]+' | sort -u

# Scan Dashlane URLs for myshopify.com store references
dcli password shopify --output json 2>/dev/null | jq -r '.[].url // empty' | grep -oE '[a-z0-9-]+\.myshopify\.com' | sort -u

# Scan project .env files for store URLs
grep -rhE 'myshopify\.com|SHOPIFY_STORE' ~/Projects/*/.env* 2>/dev/null | grep -v '^#' | head -5

重要:すべてのスキャン元を確認するまで、「Shopify の認証情報が見つかりませんでした」と報告しないでください。トークンが見つからなくても、ストア URL が見つかった場合(Chrome の履歴や Dashlane など)は、"Found Shopify store(s): <stores>. No API token found — you'll need to create one." と報告し、ストア URL を入力済みにして Step 3i.3(トークン)に進んでください。

store_url と admin_token の両方がすでに見つかった場合は、次のように表示します。

✓ Shopify — already configured (<store_url>)
  [Keep existing]  [Reconfigure]

ユーザーが既存の設定を維持する場合は、Step 3i.4 に進みます。再設定する場合、または値が見つからなかった場合は、続行します。

Step 3i.2 — Shopify ストア URL

自動スキャンで SHOPIFY_STORE_URL が見つかった場合は、ユニバーサル認証情報自動スキャンのプロンプト形式で提示します。値が見つからなかった場合に限り、自由入力で尋ねます。

Enter your Shopify store URL:
  Format: yourstore.myshopify.com
  (Do not include https://)

入力を検証します。https:// と末尾のスラッシュを削除し、結果が .myshopify.com で終わることを確認します。無効な場合は、修正方法を注記して再度尋ねます。

ステップ 3i.3 — Shopify Admin API トークン

自動スキャンで SHOPIFY_ACCESS_TOKEN、SHOPIFY_ADMIN_TOKEN、または SHOPIFY_ADMIN_API_ACCESS_TOKEN が見つかった場合は、表示を省略した形式(shpat_508b...682e)で、ユニバーサル認証情報自動スキャンのプロンプト形式を使って提示します。値が見つからなかった場合に限り、自由入力で尋ねます。

複数ストアへの対応:複数のストアが見つかった場合は、それぞれを個別に処理します。トークンがないストアについては、まず自動化された方法を試します。

  1. すべてのプロジェクトで Doppler を確認し、ストア固有の Shopify トークンを探します。
    for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
      doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
        jq -r --arg proj "$proj" 'to_entries[] | select(.key | test("SHOPIFY.*TOKEN|SHOPIFY.*ACCESS"; "i")) | "\(.key)=\(.value.computed | .[0:12])... (doppler:\($proj)/prd)"'
    done
    
  2. Shopify CLI がインストールされている場合は試します(command -v shopify)。
    shopify auth logout 2>/dev/null  # Clear stale session
    shopify auth login --store <store>.myshopify.com 2>&1  # Opens browser OAuth
    
    認証に成功したら、CLI を使ってカスタムアプリトークンを生成します。これにより、管理画面を手動で操作する必要がなくなります。
  3. ブラウザー自動化 — Kapture/Playwright MCP が利用可能な場合は、https://admin.shopify.com/store/<slug>/settings/apps/development に移動し、「Create an app」→「Configure scopes」→「Install」→「Reveal token」の手順を自動化します。スコープは read_orders,read_products,read_customers,read_inventory,read_fulfillments,read_analytics を使用します。
  4. 手動での代替手段 — すべての自動化された方法が失敗した場合に限ります。
    No automated path available for <store>.myshopify.com.
    To generate a token manually:
      1. Go to https://admin.shopify.com/store/<slug>/settings/apps/development
      2. Create an app → Configure → grant scopes → Install → copy token
      Token starts with "shpat_"
    

トークンが見つからないという理由だけでストアをスキップしないでください。必ず最初に自動化を試してください。ユーザーは認証情報の検索だけでなく、ウィザードによる認証情報の生成も期待しています。

$PREFS_PATH の ecom.shopify に保存します。Doppler 参照パターンを適用します。Doppler が設定されている場合は、次を実行します。

doppler secrets set SHOPIFY_ADMIN_TOKEN="<token>" --project <project> --config <config>

そのうえで、設定には生のトークンではなく "admin_token": "doppler:SHOPIFY_ADMIN_TOKEN" を保存します。

スモークテスト:

STORE=$(jq -r '.ecom.shopify.store_url' "$PREFS_PATH")
TOKEN=$(jq -r '.ecom.shopify.admin_token' "$PREFS_PATH")
if [[ "$TOKEN" == doppler:* ]]; then
  KEY="${TOKEN#doppler:}"
  TOKEN=$(doppler secrets get "$KEY" --plain 2>/dev/null)
fi
curl -s -H "X-Shopify-Access-Token: $TOKEN" \
  "https://$STORE/admin/api/2024-10/shop.json" | jq '.shop.name'

ショップ名の文字列が返されることを確認します。レスポンスに errors または {"shop":null} が含まれている場合は、エラーを表示し、トークンのスコープを確認するようユーザーに依頼します。✓ Shopify — 接続済み(<shop name>) と出力します。

Step 3i.4 — 動的な EC パートナー

Shopify の設定後、AskUserQuestion を使って(自由入力で)尋ねます:

Do you use any other ecommerce tools you'd like to connect?
  Examples: ShipBob (fulfillment), Recharge (subscriptions), Yotpo (reviews),
            Shippo (shipping rates), Gorgias (support), Attentive (SMS), Loop (returns)
  Type the names separated by commas, or leave blank to skip.

ユーザーがパートナー名を入力した場合は、それぞれについてループ処理します:

各パートナーについて:

  1. 認証情報を調査する — ウェブ検索:"<partner name> API authentication developer docs 2025"。以下を確認します:

    • 必要な認証情報(API キー、OAuth トークン、Webhook シークレット、ベース URL、アカウント ID など)
    • API ベース URL
    • 疎通テストに適したヘルスチェック/認証エンドポイント(例:/me、/account、/v1/ping、limit=1 を指定したリストエンドポイント)
    • 認証ヘッダーの形式(Authorization: Bearer、X-Api-Key、カスタムヘッダーなど)
  2. 各認証情報を尋ねる — AskUserQuestion を使います(認証情報フィールドごとに質問を1つ)。ドキュメントの内容に基づいて、どこで確認できるかを示します。ShipBob の例: 尋ねる前に、SHIPBOB_ACCESS_TOKEN と SHIPBOB_API_TOKEN のユニバーサル認証情報自動スキャンを実行します。見つかった場合は、取得元を明示して提示します。見つからなかった場合にのみ、手動で入力を促します:

    Enter your ShipBob Personal Access Token:
      To generate: ShipBob dashboard → Integrations → API → Personal Access Tokens → Create Token
    
  3. 疎通テスト — 手順1で見つけた認証エンドポイントを使います:

    curl -s -H "<auth_header>: $TOKEN" "<base_url>/<health_endpoint>" | jq '.<identity_field>'
    

    結果を表示します。失敗した場合は、生のレスポンスを表示し、[認証情報を再入力]/[このパートナーをスキップ] を提示します。

  4. 設定に保存する — ecom.partners.<partner_slug> の下に保存します。partner_slug はパートナー名を小文字にし、ハイフンでつないだものです:

    {
      "ecom": {
        "partners": {
          "shipbob": {
            "api_base_url": "https://api.shipbob.com/v1",
            "auth_pattern": "Authorization: Bearer <token>",
            "credentials": { "api_token": "doppler:SHIPBOB_API_TOKEN" },
            "health_endpoint": "/user",
            "configured_at": "<ISO timestamp>"
          }
        }
      }
    }
    

    Doppler が設定されている場合は、実際のシークレットを Doppler(キー:<PARTNER_SLUG_UPPER>_API_TOKEN)に保存し、設定されていない場合はインラインで保存します。auth_pattern と api_base_url の各フィールドは、今後の /ops:ecom 呼び出しでパートナーにアクセスするために使う情報です。必ず調査したドキュメントに基づいて値を設定します。

  5. 確認メッセージを表示する:

    ✓ <Partner Name> — connected
    
  6. ループ:各パートナーの処理後、AskUserQuestion で「ほかに接続する EC ツールはありますか?」と尋ねます → [はい — 追加する]/[完了]。これにより、最初のカンマ区切りのリストではなく、ユーザーが希望する場合はパートナーを1つずつ追加できます。

既知の認証パターンを持つパートナー(検索せずに以下を使用できますが、疎通テストは必ず実施してください):

パートナー認証ヘッダーベース URLヘルスチェックエンドポイント
ShipBobAuthorization: Bearer <token>https://api.shipbob.com/v1/user
RechargeX-Recharge-Access-Token: <token>https://api.rechargeapps.com/v1/shop
YotpoX-Api-Key: <app_key>https://api.yotpo.com/core/v3/stores/<id>
ShippoAuthorization: ShippoToken <token>https://api.goshippo.com/carrier_accounts
GorgiasAuthorization: Basic <base64>https://<domain>.gorgias.com/api/account
LoopX-Authorization: <secret>https://api.loopreturns.com/api/v1/warehouse
AttentiveAuthorization: Bearer <token>https://api.attentivemobile.com/v1/me

この表にないパートナーについては、認証情報を尋ねる前に、必ず最新の認証ドキュメントをウェブ検索してください。

詳細情報: EC 統合(複数ストアの Shopify、パートナーへの振り分け、ストアヘルスデーモン)の詳しい運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-ecom/SKILL.md を参照してください。このウィザードより詳しい情報が必要な場合、セットアップエージェントはこのファイルを直接読み込めます。


3j — マーケティング(Klaviyo、Meta Ads、GA4、Search Console)

サービスセレクターを表示する前に、すべてのマーケティング変数を対象に Universal Credential Auto-Scan を同時に実行します。

# Shell env
printenv KLAVIYO_API_KEY KLAVIYO_PRIVATE_KEY META_ACCESS_TOKEN FACEBOOK_ACCESS_TOKEN META_AD_ACCOUNT_ID GA4_PROPERTY_ID GA_MEASUREMENT_ID 2>/dev/null
printenv GOOGLE_ADS_DEVELOPER_TOKEN GOOGLE_ADS_CLIENT_ID GOOGLE_ADS_CLIENT_SECRET GOOGLE_ADS_REFRESH_TOKEN GOOGLE_ADS_CUSTOMER_ID 2>/dev/null

# Shell profiles
grep -h 'KLAVIYO\|META_\|FACEBOOK\|GA4\|GA_MEASUREMENT\|GOOGLE_ADS' ~/.zshrc ~/.bashrc ~/.zprofile ~/.envrc 2>/dev/null | grep -v '^#'

# Doppler across all projects
for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
  doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
    jq -r --arg proj "$proj" 'to_entries[] | select(.key | test("KLAVIYO|META|FACEBOOK|GA4|GOOGLE|GOOGLE_ADS")) | "\(.key)=\(.value.computed) (doppler:\($proj)/prd)"'
done

# Dashlane
dcli password klaviyo --output json 2>/dev/null
dcli password facebook --output json 2>/dev/null
dcli password meta --output json 2>/dev/null

# OpenClaw
jq -r '.agents.defaults.env | to_entries[] | select(.key | test("KLAVIYO|META_|FACEBOOK|GA4")) | "\(.key)=\(.value)"' ~/.openclaw/openclaw.json 2>/dev/null

結果をキャッシュし、以下の各サブステップで回答を事前入力するために使用します。以下の各サービスについて、質問する前に設定済みかどうかを確認します($PREFS_PATH の marketing.* を確認してから、上記の自動スキャン結果を確認します)。設定済みの場合は、✓ <service> — already configured と表示し、[Keep] / [Reconfigure] を提示します。

設定するマーケティング連携を、multiSelect: true を指定した AskUserQuestion の呼び出しを2回連続で行って尋ねます(Rule 1 により最大4項目)。

最初の呼び出し(主要な連携):

オプションヘッダー説明
Klaviyoklaviyoメール/SMS マーケティング — プライベート API キー
Meta AdsmetaFacebook/Instagram 広告 — アクセストークン + 広告アカウント ID
Google Adsgoogle-ads検索連動型広告 — OAuth2 + デベロッパートークン
その他...moreGoogle Analytics 4、Search Console

ユーザーが [More...] を選択した場合は、2回目の呼び出しを提示します。

オプションヘッダー説明
Google Analytics 4ga4ウェブ解析 — GA4 プロパティ ID
Google Search ConsolegscSEO データ — サイト URL(gcloud 認証を使用)
WhatsApp Business APIwaba大規模なテンプレートメッセージ配信 — ビジネストークン + ID
スキップskipマーケティングのセットアップを終了

選択されたサブステップを、選択された順に実行します。

Klaviyo

自動スキャンで KLAVIYO_API_KEY または KLAVIYO_PRIVATE_KEY が見つかった場合は、Universal Credential Auto-Scan のプロンプト形式を使って提示します。見つからなかった場合に限り、自由入力で尋ねます。

Enter your Klaviyo Private API Key:
  To generate one: Klaviyo dashboard → Settings → API Keys → Create Private Key
  Key starts with "pk_"

スモークテスト:

curl -s -H "Authorization: Klaviyo-API-Key $KEY" \
  -H "revision: 2024-10-15" \
  "https://a.klaviyo.com/api/lists" | jq '.data | length'

0以上の数値が返されることを想定します。応答に認証エラーを含む "detail" がある場合は、それを表示して再度尋ねます。

Meta Ads

自動スキャンで META_ACCESS_TOKEN または FACEBOOK_ACCESS_TOKEN が見つかった場合は、それを提示します。META_AD_ACCOUNT_ID が見つかった場合は、それも提示します。見つからなかった値に限り、自由入力で尋ねます。

以下を尋ねます。

  1. アクセストークン(説明:Meta Business Suite → Settings → System Users、または個人アカウントから、ads_read 権限を付けてトークンを生成します)
  2. 広告アカウント ID(形式:act_XXXXXXXXXX — Business Manager → Ad Accounts にあります)

スモークテスト:

curl -s "https://graph.facebook.com/v20.0/$AD_ACCOUNT_ID/campaigns?access_token=$TOKEN&limit=1" | jq '.data | length'
Google Ads

Google Ads には3つの認証情報グループが必要です。各手順を順番に案内します。

ステップ A — Developer Token: 自動スキャンで GOOGLE_ADS_DEVELOPER_TOKEN が見つかった場合は、その値を提示して [Keep] / [Reconfigure] を選べるようにします。 見つからなかった場合は、自由入力で尋ねます:

Google Ads の Developer Token(Google Ads → Tools & Settings → API Center で確認できます)。 注:新しい Developer Token は「test」モードで開始します。テストアカウントに対してのみ動作します。本番データを使用するには、https://ads.google.com/home/tools/manager-accounts/ で Basic Access を申請してください。

ステップ B — OAuth2 クライアント認証情報: 自動スキャンで GOOGLE_ADS_CLIENT_ID と GOOGLE_ADS_CLIENT_SECRET が見つかった場合は、それらを提示して [Keep] / [Reconfigure] を選べるようにします。 見つからなかった場合は、自由入力で2つの項目を尋ねます:

  1. OAuth2 Client ID(Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client ID から取得します。タイプは Desktop app で、Google Ads API が有効になっている必要があります)
  2. OAuth2 Client Secret(Client ID と一緒に表示されます)

ステップ C — Refresh Token(ブラウザー OAuth フロー): 自動スキャンで GOOGLE_ADS_REFRESH_TOKEN が見つかった場合は、その値を提示して [Keep] / [Reconfigure] を選べるようにします。 見つからなかった場合は、認証 URL を生成して OAuth フローを実行します:

AUTH_URL="https://accounts.google.com/o/oauth2/auth?client_id=${GADS_CLIENT_ID}&redirect_uri=http://localhost:8080&response_type=code&scope=https://www.googleapis.com/auth/adwords&access_type=offline&prompt=consent"
open "$AUTH_URL"  # macOS

リダイレクトを受け取るため、一時的な localhost サーバーを起動します:

# One-liner node HTTP server to capture the auth code
node -e "require('http').createServer((req,res)=>{const code=new URL(req.url,'http://localhost').searchParams.get('code');if(code){res.end('Authorization code received. You can close this tab.');process.stdout.write(code);process.exit(0)}else{res.end('Waiting for auth...')}}).listen(8080)"

run_in_background: true を指定して Bash でサーバーを実行します。認証コードが届くまで最大120秒待ちます。

localhost を使う方法が失敗した場合は、ブラウザーの URL バーにあるコード(code= パラメーター)を貼り付けるようユーザーに求めます。

コードを Refresh Token と交換します:

TOKEN_RESP=$(curl -s -X POST https://oauth2.googleapis.com/token \
  --data "code=${AUTH_CODE}" \
  --data "client_id=${GADS_CLIENT_ID}" \
  --data "client_secret=${GADS_CLIENT_SECRET}" \
  --data "redirect_uri=http://localhost:8080" \
  --data "grant_type=authorization_code")
GADS_REFRESH_TOKEN=$(echo "$TOKEN_RESP" | jq -r '.refresh_token')

GADS_REFRESH_TOKEN が null または空の場合は、エラーを表示して再試行を提案します。

警告:ユーザーの Google Cloud プロジェクトの公開ステータスが「testing」の場合、Refresh Token は7日後に期限切れになります。「OAuth アプリはテストモードです。トークンは7日後に期限切れになります。長期間有効なトークンを取得するには、Google Cloud Console → OAuth consent screen → Publish App でアプリを公開してください」と警告します。

ステップ D — Customer ID: Refresh Token を使って Access Token を取得し、アクセス可能な顧客を一覧表示します:

ACCESS_TOKEN=$(curl -s -X POST https://oauth2.googleapis.com/token \
  --data "client_id=${GADS_CLIENT_ID}&client_secret=${GADS_CLIENT_SECRET}&refresh_token=${GADS_REFRESH_TOKEN}&grant_type=refresh_token" | jq -r '.access_token')

CUSTOMERS=$(curl -s -X GET \
  "https://googleads.googleapis.com/v23/customers:listAccessibleCustomers" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "developer-token: ${GADS_DEV_TOKEN}")

複数のアカウントが返された場合は、AskUserQuestion の選択肢として提示します(ルール1に従い最大4件。超える場合はページ分割します)。アカウントが1つだけの場合は、自動選択します。customer_id として保存します(「customers/」のプレフィックスとハイフンを削除します)。

アカウントのいずれかがマネージャー(MCC)アカウントの場合は、login_customer_id も保存します。listAccessibleCustomers がマネージャーアカウントとクライアントアカウントの両方を返すかどうかで自動判定します。

ステップ E — スモークテスト:

curl -s -X GET "https://googleads.googleapis.com/v23/customers:listAccessibleCustomers" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "developer-token: ${GADS_DEV_TOKEN}"

resourceNames 配列を含む JSON が返されることを確認します。エラーが発生した場合はエラーを表示して [Retry] / [Skip] を提案します。

ステップ F — 設定に保存:

{
  "marketing": {
    "google_ads": {
      "developer_token": "<YOUR_DEVELOPER_TOKEN>",
      "client_id": "<YOUR_CLIENT_ID>.apps.googleusercontent.com",
      "client_secret": "GOCSPX-<YOUR_SECRET>",
      "refresh_token": "1//<YOUR_REFRESH_TOKEN>",
      "customer_id": "1234567890",
      "login_customer_id": "9876543210"
    }
  }
}

ステップ3iと同じ Doppler 参照パターンを使用します。Doppler が設定されている場合は、トークンを直接保存するより doppler:KEY_NAME を優先します。

次のように表示します:[Google Ads] ✓ connected — customer ID: XXXXXXXXXX

Google Analytics 4

自動スキャンで GA4_PROPERTY_ID または GA_MEASUREMENT_ID が見つかった場合は、その値を提示します。見つからなかった場合にのみ、自由入力で尋ねます。GA4 Property ID を尋ねます(GA4 ダッシュボード → Admin → Property Settings → Property ID で確認できること、数値形式であること、例:123456789 を説明します)。

gcloud が認証済みであれば、API キーは不要です。GA4 Data API は Application Default Credentials を使用します。次のコマンドで確認します:

gcloud auth application-default print-access-token 2>/dev/null | head -c 10

gcloud ADC が設定されていない場合、GA4 のクエリには手動での認証が必要になることを伝えます:gcloud auth application-default login。

Google Search Console

サイト URL を尋ねます(形式:https://example.com/ または sc-domain:example.com)。gcloud が認証済みであれば、API キーは不要です。

スモークテスト:

ACCESS_TOKEN=$(gcloud auth application-default print-access-token 2>/dev/null)
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://searchconsole.googleapis.com/webmasters/v3/sites" | jq '.siteEntry | length'
WhatsApp Business API

個人用 WhatsApp の wacli とは別です。 大規模なビジネスから顧客へのテンプレートメッセージ送信に使用します。

以下を自動スキャンします:

printenv WHATSAPP_BUSINESS_TOKEN WHATSAPP_PHONE_NUMBER_ID WHATSAPP_BUSINESS_ACCOUNT_ID 2>/dev/null
claude plugin config get whatsapp_business_token 2>/dev/null && echo "waba_token: already configured"
claude plugin config get whatsapp_phone_number_id 2>/dev/null && echo "waba_phone_id: already configured"
claude plugin config get whatsapp_business_account_id 2>/dev/null && echo "waba_account_id: already configured"

認証情報の確認場所:

  • WHATSAPP_BUSINESS_TOKEN:Meta Developer Portal → お使いのアプリ → WhatsApp → API Setup → Temporary または System User トークン
  • WHATSAPP_PHONE_NUMBER_ID:同じページ → 「From」の電話番号 → Phone Number ID
  • WHATSAPP_BUSINESS_ACCOUNT_ID:Meta Business Manager → Business Settings → WhatsApp Accounts → ID

見つからない場合は、それぞれ AskUserQuestion(自由入力)で尋ねます。保存先:

claude plugin config set whatsapp_business_token "$WABA_TOKEN"
claude plugin config set whatsapp_phone_number_id "$WABA_PHONE_ID"
claude plugin config set whatsapp_business_account_id "$WABA_ACCOUNT_ID"

スモークテスト:

curl -s "https://graph.facebook.com/v20.0/${WABA_PHONE_ID}" \
  -H "Authorization: Bearer ${WABA_TOKEN}" | jq '.display_phone_number // empty'

電話番号が返された場合は、WhatsApp Business ✓ 接続済み — 電話番号:<number> と表示します。それ以外の場合はエラーを表示します。

設定に保存する

$PREFS_PATH にマージして書き込みます:

{
  "marketing": {
    "klaviyo": { "api_key": "<pk_...>" },
    "meta": { "access_token": "<token>", "ad_account_id": "act_XXXXXXXXXX" },
    "ga4": { "property_id": "123456789" },
    "gsc": { "site_url": "https://example.com/" },
    "whatsapp_business": { "phone_number_id": "<ID>", "business_account_id": "<WABA_ID>" }
  }
}

Step 3i と同じ Doppler 参照パターンを使用します。Doppler が設定されている場合は、生のトークンより doppler:KEY_NAME を優先します。

動的なマーケティングパートナー

既知のサービスの後に、AskUserQuestion(自由入力)で尋ねます:

Any other marketing tools you'd like to connect?
  Examples: Postscript (SMS), Privy (popups), Triple Whale (attribution), Northbeam,
            Hotjar, Heap, Segment, Mixpanel, Mailchimp, ActiveCampaign, HubSpot
  Type names separated by commas, or leave blank to skip.

ユーザーがパートナー名を指定した場合は、Step 3i.4 と同じ動的なパートナーループを適用します。パートナーごとに:

  1. 認証情報を調査する:ウェブ検索で "<partner name> API authentication developer docs 2025" を検索します
  2. 認証情報を尋ねる:ドキュメントを参照した手順を添えて AskUserQuestion で尋ねます
  3. スモークテストを実施する:認証/ヘルスエンドポイントに対してテストします
  4. 設定に保存する:marketing.partners.<partner_slug> の下に保存します:
    {
      "marketing": {
        "partners": {
          "triple-whale": {
            "api_base_url": "https://api.triplewhale.com/api/v2",
            "auth_pattern": "Authorization: Bearer <token>",
            "credentials": { "api_key": "doppler:TRIPLE_WHALE_API_KEY" },
            "health_endpoint": "/attribution/get-attribution-data",
            "configured_at": "<ISO timestamp>"
          }
        }
      }
    }
    
  5. ループする:各パートナーの後に [Add another]/[Done] を提示します。

既知の認証情報パターンがあるパートナー(そのまま使用できますが、スモークテストは実施してください):

パートナー認証ヘッダーベース URLヘルスエンドポイント
HubSpotAuthorization: Bearer <token>https://api.hubapi.com/crm/v3/objects/contacts?limit=1
MailchimpAuthorization: Bearer <api_key>https://<dc>.api.mailchimp.com/3.0/ping
SegmentAuthorization: Basic <base64_key:>https://api.segment.io/v1該当なし — 書き込みキーを使用
MixpanelAuthorization: Basic <base64_secret:>https://data.mixpanel.com/api/2.0/engage?limit=1
PostscriptAuthorization: ApiKey <key>https://api.postscript.io/api/v2/shops
Triple WhaleAuthorization: Bearer <token>https://api.triplewhale.com/api/v2/attribution/get-attribution-data

この表にないパートナーについては、認証情報を尋ねる前に、必ずウェブ検索で最新の認証ドキュメントを確認してください。

詳細: マーケティング連携(Klaviyo フロー、Meta Ads、GA4、Search Console)の運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-marketing/SKILL.md を参照してください。このセットアップエージェントは、このウィザードより詳しい情報が必要な場合、このファイルを直接読み込めます。


3k — 音声(Bland AI、ElevenLabs、Groq)

サービス選択画面を表示する前に、すべての音声変数を対象に Universal Credential Auto-Scan を実行します:

# Shell env
printenv BLAND_AI_API_KEY BLAND_API_KEY ELEVENLABS_API_KEY GROQ_API_KEY 2>/dev/null

# Shell profiles
grep -h 'BLAND\|ELEVENLABS\|GROQ' ~/.zshrc ~/.bashrc ~/.zprofile ~/.envrc 2>/dev/null | grep -v '^#'

# Doppler across all projects
for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
  doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
    jq -r --arg proj "$proj" 'to_entries[] | select(.key | test("BLAND|ELEVENLABS|GROQ")) | "\(.key)=\(.value.computed) (doppler:\($proj)/prd)"'
done

# Dashlane
dcli password "bland-ai" --output json 2>/dev/null
dcli password elevenlabs --output json 2>/dev/null
dcli password groq --output json 2>/dev/null

# OpenClaw (common location for AI service keys)
jq -r '.agents.defaults.env | to_entries[] | select(.key | test("BLAND|ELEVENLABS|GROQ")) | "\(.key)=\(.value)"' ~/.openclaw/openclaw.json 2>/dev/null

これらの結果をキャッシュし、以下の各サブステップで回答の事前入力に使用します。$PREFS_PATH の voice.* にある既存の設定も確認します。キーがすでに設定されている場合は、✓ <service> — 設定済み と表示し、[Keep]/[Reconfigure] を提示します。

設定する音声サービスを、multiSelect: true を指定した AskUserQuestion で尋ねます:

オプションヘッダー説明
Bland AIblandAI による発信電話 — API キー
ElevenLabselevenlabsテキスト読み上げと音声クローン — API キー
Groqgroq高速な LLM 推論(Whisper、LLaMA)— API キー
Bland AI

自動スキャンで BLAND_AI_API_KEY または BLAND_API_KEY が見つかった場合は、汎用認証情報自動スキャンのプロンプト形式で提示します。見つからなかった場合に限り、自由入力で尋ねます:

Enter your Bland AI API Key:
  To find it: https://app.bland.ai → Settings → API Key

スモークテスト:

curl -s -H "Authorization: $KEY" "https://api.bland.ai/v1/me" | jq '.user.id'

null 以外のユーザー ID が返されることを確認します。

ElevenLabs

自動スキャンで ELEVENLABS_API_KEY が見つかった場合は、汎用認証情報自動スキャンのプロンプト形式で提示します。見つからなかった場合に限り、自由入力で尋ねます:

Enter your ElevenLabs API Key:
  To find it: https://elevenlabs.io → Profile (top-right) → API Key

スモークテスト:

curl -s -H "xi-api-key: $KEY" "https://api.elevenlabs.io/v1/user" | jq '.subscription.tier'

サブスクリプションのティアを示す文字列(例:"free"、"starter")が返されることを確認します。

Groq

自動スキャンで GROQ_API_KEY が見つかった場合は、汎用認証情報自動スキャンのプロンプト形式で提示します。見つからなかった場合に限り、自由入力で尋ねます:

Enter your Groq API Key:
  To generate one: https://console.groq.com → API Keys → Create API Key
  Key starts with "gsk_"

スモークテスト:

curl -s -H "Authorization: Bearer $KEY" \
  "https://api.groq.com/openai/v1/models" | jq '.data | length'

正の整数(利用可能なモデルの数)が返されることを確認します。

設定に保存する

$PREFS_PATH に書き込みます(既存の設定とマージ):

{
  "voice": {
    "bland": { "api_key": "<key>" },
    "elevenlabs": { "api_key": "<key>" },
    "groq": { "api_key": "gsk_..." }
  }
}

Doppler の参照パターンと同様に、Doppler が設定されている場合は、トークンを直接保存するよりも doppler:KEY_NAME を優先します。

詳細: 音声連携(Bland AI の通話フロー、ElevenLabs の TTS、Groq の文字起こし)に関する運用手順、CLI リファレンス、トラブルシューティングの詳細は ${CLAUDE_PLUGIN_ROOT}/skills/ops-voice/SKILL.md を参照してください。このウィザードより詳しい情報が必要な場合、セットアップエージェントはそのファイルを直接読み込めます。


3l — 収益(Stripe + RevenueCat)

サービスセレクターを表示する前に、すべての収益関連変数について汎用認証情報自動スキャンを同時に実行します(ルール 4 — バックグラウンドで実行):

# Shell env
printenv STRIPE_SECRET_KEY STRIPE_API_KEY REVENUECAT_API_KEY REVENUECAT_SECRET_KEY REVENUECAT_PROJECT_ID 2>/dev/null

# Shell profiles + .envrc files
grep -h 'STRIPE\|REVENUECAT\|RC_API' ~/.zshrc ~/.bashrc ~/.zprofile ~/.envrc 2>/dev/null | grep -v '^#'

# Doppler across all projects
for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
  doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
    jq -r --arg proj "$proj" 'to_entries[] | select(.key | test("STRIPE|REVENUECAT|RC_API")) | "\(.key)=\(.value.computed) (doppler:\($proj)/prd)"'
done

# 1Password
op item list --categories "API Credential" --format json 2>/dev/null | \
  jq -r '.[] | select(.title | test("stripe|revenuecat"; "i")) | .id' | \
  while read id; do op item get "$id" --format json 2>/dev/null; done

# Dashlane
dcli password stripe --output json 2>/dev/null
dcli password revenuecat --output json 2>/dev/null

# Bitwarden
bw list items --search stripe 2>/dev/null | jq -r '.[] | select(.login.password) | .login.password' | head -1
bw list items --search revenuecat 2>/dev/null | jq -r '.[] | select(.login.password) | .login.password' | head -1

# macOS Keychain
security find-generic-password -s "stripe" -w 2>/dev/null
security find-generic-password -s "revenuecat" -w 2>/dev/null

# OpenClaw
jq -r '.agents.defaults.env | to_entries[] | select(.key | test("STRIPE|REVENUECAT")) | "\(.key)=\(.value)"' ~/.openclaw/openclaw.json 2>/dev/null

結果をキャッシュします。さらに、$PREFS_PATH の revenue.stripe.* と revenue.revenuecat.* も確認します。すでに設定されている場合は、✓ <service> — すでに設定済み と表示し、[保持]/[再設定] を選択できるようにします。

どの収益連携を設定するか、multiSelect: true を指定した AskUserQuestion で尋ねます:

オプションヘッダー説明
StripestripeSaaS の収益 — MRR、課金、異議申し立てに使用するシークレットキー
RevenueCatrevenuecatモバイルのサブスクリプション — モバイル MRR に使用する API キーとプロジェクト ID
Stripe

自動スキャンで STRIPE_SECRET_KEY が見つかった場合は、汎用認証情報自動スキャンのプロンプト形式で、[この値を使用]/[別の値を貼り付け]/[スキップ] を提示します。

ルール 3 に従い、何も見つからなかった場合は次の選択肢を提示します(4 件以下):

No Stripe secret key found. How do you want to provide one?
  [Paste Stripe secret key manually]
  [Deep hunt — spawn agent]
  [Skip — use registry.json values]

[詳細を調査 — エージェントを起動] が選択されたら、ルール 3 に従ってバックグラウンド調査エージェントを起動します:

Agent(
  subagent_type: "general-purpose",
  model: "haiku",
  run_in_background: true,
  prompt: "Grep the filesystem under $HOME (excluding node_modules, .git, Library/Caches) for Stripe secret key patterns: sk_live_[A-Za-z0-9]+ and sk_test_[A-Za-z0-9]+. Also scan ~/.config, ~/.aws, ~/.docker, any .env files, and known secrets directories. Return every hit with file path + line number + 6 chars of redacted prefix (e.g. sk_live_abc***). Do not print full keys."
)

実行中は RevenueCat のブロックに進みます。エージェントから結果が報告されたら Stripe に戻り、AskUserQuestion で調査結果を提示します(ルール 1 に従って、1 回の提示は 4 件以下)。

[Stripe のシークレットキーを手動で貼り付け] が選択された場合:

Enter your Stripe Secret Key:
  Format: sk_live_XXX  (production)  or  sk_test_XXX  (test mode)
  Find it: Stripe Dashboard → Developers → API keys → Secret key → Reveal
  Prefer a Doppler reference (e.g. doppler:STRIPE_SECRET_KEY) over the raw value.

スモークテスト:

curl -s -u "$STRIPE_SECRET_KEY:" "https://api.stripe.com/v1/balance" | jq '.available | length'

0 以外の整数が返されることを確認します。{"error": ...} が返された場合は、メッセージを表示してもう一度尋ねます。

RevenueCat

自動スキャンで REVENUECAT_API_KEY と REVENUECAT_PROJECT_ID の両方が見つかった場合は、[これらの値を使用]/[別の値を貼り付け]/[スキップ] を一緒に提示します。

ルール 3 に従い、見つからなかった場合は次の選択肢を提示します:

No RevenueCat credentials found. How do you want to provide them?
  [Paste RevenueCat API key manually]
  [Deep hunt — spawn agent]
  [Skip — mobile MRR will be omitted]

[詳細を調査 — エージェントを起動] が選択されたら、バックグラウンドで起動します(ルール 4):

Agent(
  subagent_type: "general-purpose",
  model: "haiku",
  run_in_background: true,
  prompt: "Grep the filesystem under $HOME (excluding node_modules, .git, Library/Caches) for RevenueCat credential patterns: rcb_[A-Za-z0-9]+ (V2 secret), sk_[A-Za-z0-9]+ near the literal string 'revenuecat', and any env vars matching REVENUECAT_* or RC_API_*. Also look for project IDs (32-char alphanum strings) adjacent to any revenuecat match. Return each hit with file path + line number + 6-char redacted prefix. Do not print full keys."
)

[RevenueCat の API キーを手動で貼り付け] が選択された場合:

Enter your RevenueCat API Key:
  Find it: app.revenuecat.com → Project settings → API keys → Secret key
  Format: rcb_XXX (V2 secret)  or  sk_XXX (legacy secret key)

Enter your RevenueCat Project ID:
  Find it in the URL: app.revenuecat.com/projects/<project_id>/...

スモークテスト:

curl -s -H "Authorization: Bearer $REVENUECAT_API_KEY" \
  "https://api.revenuecat.com/v2/projects/$REVENUECAT_PROJECT_ID/metrics/overview" | jq '.metrics // .object'

数値の mrr またはオブジェクト記述子が返されることを確認します。レスポンスが {"code": 7243, ...}(認証エラー)の場合は、もう一度尋ねます。

環境設定に保存

$PREFS_PATH に書き込みます(マージ):

{
  "revenue": {
    "stripe": {
      "secret_key": "doppler:STRIPE_SECRET_KEY",
      "configured_at": "<ISO timestamp>"
    },
    "revenuecat": {
      "api_key": "doppler:REVENUECAT_API_KEY",
      "project_id": "<project_id>",
      "configured_at": "<ISO timestamp>"
    }
  }
}

Doppler が設定されている場合は、生のトークンより Doppler の参照(doppler:STRIPE_SECRET_KEY、doppler:REVENUECAT_API_KEY)を優先します。どちらのサービスでも、ユーザーが [Skip] を選んだ場合は {"revenue": {"<service>": "skipped"}} を保存し、次回の実行時にウィザードが再度尋ねないようにします。ただし、/ops:revenue は revenue-tracker エージェントに記載されているとおり、scripts/registry.json の revenue.mrr 値にフォールバックします。

詳細: 収益連携(Stripe の MRR/ARR クエリ、RevenueCat のサブスクリプション指標、レジストリーのフォールバック)に関する運用手順、CLI リファレンス、トラブルシューティングの全容は ${CLAUDE_PLUGIN_ROOT}/skills/ops-revenue/SKILL.md を参照してください。このウィザードで提供される以上の詳細が必要な場合、セットアップエージェントはこのファイルを直接読み込めます。


3n — 通知(fires-watcher の通知先)

CRITICAL/HIGH の障害に対するプッシュ通知を設定し、ユーザーが手動で /ops:fires を繰り返し確認する必要がないようにします。fires-watcher デーモンサービスが有効になっていることが条件です(デフォルトでは無効)。

質問する前に、通知先の自動スキャンをバックグラウンドで実行します(ルール 4 — すべて並列):

# Already-configured sinks (env + $PREFS_PATH)
printenv TELEGRAM_BOT_TOKEN TELEGRAM_NOTIFY_CHAT_ID TELEGRAM_OWNER_ID \
         DISCORD_WEBHOOK_URL NTFY_TOPIC PUSHOVER_USER PUSHOVER_TOKEN 2>/dev/null

jq -r 'to_entries
       | map(select(.key | test("telegram_bot_token|telegram_notify_chat_id|discord_webhook_url|ntfy_topic|pushover_user_key|pushover_app_token")))
       | .[] | "\(.key)=\(.value | if type == "string" and length > 6 then .[0:6] + "***" else . end)"' \
       "$PREFS_PATH" 2>/dev/null

# Macro: is the Telegram bot already configured via /ops:setup telegram?
jq -r '.telegram.bot_token // empty, .telegram.owner_id // empty' "$PREFS_PATH" 2>/dev/null

結果をキャッシュします。その後、すでに設定済みのものを選択肢の一覧から除外します(ルール 1 — 最大 4 件)。

AskUserQuestion で提示します(選択肢は最大 4 件)。最初の提示例:

選択肢ヘッダー説明
Telegram を使う(推奨)telegram3a で設定済みのボットを再利用します。追加設定は不要です。
ntfy.sh を設定するntfy無料で、アカウントも不要です。ランダムなトピックを選び、スマートフォンにアプリをインストールします。
Pushover を設定するpushover約 5 ドルの買い切りです。P0 の優先度バイパスに対応し、信頼性の高いモバイル通知を利用できます。
スキップ — 代わりに /ops:fires を確認するskipfires-watcher は無効のままになります。引き続き手動で障害を確認してください。

Telegram のボットトークンと所有者 ID が $PREFS_PATH にまだない場合は、[Use Telegram] を [Configure Telegram bot — jump to 3a] に差し替え、ここに戻る前に 3a を再度実行します。ルール 3 に従い、黙ってスキップしないでください。必ず明示的な [Skip] を提示します。

Discord も追加したいユーザー(チーム用と個人用の両方への通知を希望するユーザーは多くいます)には、2 回目の AskUserQuestion を実行します。

選択肢ヘッダー説明
Discord の Webhook も追加するdiscordX に加えて、#incidents チャンネルにも配信します。
いいえ — 選んだ通知先のみdone通知先を 1 つだけ設定します。
通知先ごとの情報取得

Telegram — $TELEGRAM_NOTIFY_CHAT_ID が空の場合は $TELEGRAM_OWNER_ID をデフォルト値にします(ボットが所有者に DM を送信します)。{"telegram_notify_chat_id": "<owner_id>"} を $PREFS_PATH に保存します。スモークテストはバックグラウンドで実行します(ルール 4):

scripts/ops-notify.sh LOW "setup test" "fires-watcher Telegram sink is live" &

ntfy.sh — ユーザーがまだトピックを持っていない場合は、ランダムなトピックを生成します。

TOPIC="claude-ops-fires-$(openssl rand -hex 6 2>/dev/null || head -c 12 /dev/urandom | base64 | tr -dc 'a-z0-9' | head -c 12)"
echo "$TOPIC"

トピックとインストール手順を表示します(ブラウザーで open https://ntfy.sh/<topic> を実行するか、ntfy モバイルアプリで QR コードをスキャンします)。ntfy_topic のキーで $PREFS_PATH に保存します。

Pushover — ルール 3 に従って、[Paste user key + app token] / [Deep hunt — spawn agent] / [Skip] を提示します。貼り付けられた場合は、スモークテストで検証します。バックグラウンドで実行してください(ルール 4):

curl -s -X POST https://api.pushover.net/1/messages.json \
  --data-urlencode "token=$PUSHOVER_TOKEN" \
  --data-urlencode "user=$PUSHOVER_USER" \
  --data-urlencode "title=claude-ops setup test" \
  --data-urlencode "message=fires-watcher Pushover sink is live" &

5 秒以内に {"status":1,...} が返ることを確認します。

Discord — ユーザーが以前の実行または issue #20 の作業で discord_default_webhook_url をすでに設定している場合は、それを再利用します。それ以外の場合は、ルール 3 に従って Webhook URL(https://discord.com/api/webhooks/...)を尋ねます。

デーモンサービスを保存して有効化する

$PREFS_PATH に書き込みます(マージし、無関係なキーは上書きしないでください)。

{
  "notifications": {
    "configured_sinks": ["telegram", "ntfy"],
    "configured_at": "<ISO timestamp>"
  },
  "telegram_notify_chat_id": "<chat_id>",
  "ntfy_topic": "<topic>"
}

次に、バックグラウンドでデーモンサービスを有効化します(ルール 4)。

jq '.services["fires-watcher"].enabled = true' \
   ~/.claude/plugins/data/ops-ops-marketplace/daemon-services.json \
  > /tmp/daemon-services.json.new && \
  mv /tmp/daemon-services.json.new ~/.claude/plugins/data/ops-ops-marketplace/daemon-services.json && \
  scripts/ops-daemon.sh restart &

再起動後、ウォッチャーが稼働していることを確認します。

cat ~/.claude/plugins/data/ops-ops-marketplace/fires-watcher.health 2>/dev/null

60 秒以内に {"status": "ok", ...} が返ることを確認してください。

詳細: シンクの優先順位の理由、デバウンスのルール、トラブルシューティングの手順については、${CLAUDE_PLUGIN_ROOT}/docs/notifications.md、${CLAUDE_PLUGIN_ROOT}/scripts/ops-fires-watcher.sh、${CLAUDE_PLUGIN_ROOT}/scripts/ops-notify.sh を参照してください。

3m — Discord(Webhook + オプションのボット)

Discord は v1 の連携機能です。Webhook による送信と REST チャンネルの読み取りに対応しています。DM とゲートウェイのサポートは v2 の課題に延期されています。送信側の Webhook は、scripts/ops-notify.sh が使用する Discord 通知シンクも提供するため、ここで設定すれば /ops:comms discord send と ops-fires アラートの両方をカバーできます。

認証情報の入力を促す前に、Discord の Universal Credential Auto-Scan を実行します(ルール 4 — 次の手順がスキャン結果に依存する場合を除き、すべての bash 呼び出しをバックグラウンドで実行します)。

# Shell env
printenv DISCORD_BOT_TOKEN DISCORD_WEBHOOK_URL DISCORD_GUILD_ID 2>/dev/null

# Shell profiles + .envrc
grep -hE 'DISCORD_(BOT_TOKEN|WEBHOOK|GUILD_ID)' ~/.zshrc ~/.bashrc ~/.zprofile ~/.envrc 2>/dev/null | grep -v '^#'

# Doppler across all projects
for proj in $(doppler projects --json 2>/dev/null | jq -r '.[].slug'); do
  doppler secrets --project "$proj" --config prd --json 2>/dev/null | \
    jq -r --arg proj "$proj" 'to_entries[] | select(.key | test("DISCORD")) | "\(.key)=\(.value.computed) (doppler:\($proj)/prd)"'
done

# 1Password
op item list --categories "API Credential" --format json 2>/dev/null | \
  jq -r '.[] | select(.title | test("discord"; "i")) | .id' | \
  while read id; do op item get "$id" --format json 2>/dev/null; done

# Dashlane / Bitwarden
dcli password discord --output json 2>/dev/null
bw list items --search discord 2>/dev/null | jq -r '.[] | select(.login.password) | .login.password' | head -1

# macOS Keychain (Darwin only — the setup wizard already guards this at the OS level)
security find-generic-password -s "discord" -w 2>/dev/null

# Claude-ops credential store (cross-OS)
"${CLAUDE_PLUGIN_ROOT}/lib/credential-store.sh" get discord bot-token 2>/dev/null

これらの結果をキャッシュしてください。また、$PREFS_PATH の discord.* と discord_webhook_url(ops-notify.sh と共有するフラットキー)も確認します。discord.bot_token、discord.default_webhook_url、discord_webhook_url のいずれかがすでに存在する場合は、✓ Discord — already configured と表示し、[Keep] / [Reconfigure] を提示します。

何か見つかった場合

Universal Credential Auto-Scan のプロンプト形式で、[Use this value] / [Paste a different one] / [Skip] を提示します。Webhook URL は見つかったもののボットトークンがない場合は、読み取りとチャンネル一覧の取得が利用できず、送信のみ可能であることを伝えます。

ルール 3 に従い、何も見つからなかった場合は明示的に尋ねます(ルール 1 に従い、選択肢は最大 4 つ)。
No Discord credentials found. How do you want to configure Discord?
  [Paste bot token]
  [Paste webhook URL only]
  [Deep hunt — spawn agent]
  [Skip — I'll configure later]

[Deep hunt — spawn agent] が選択された場合は、バックグラウンドの調査エージェントを起動します(ルール 4 — run_in_background: true)。

Agent(
  subagent_type: "general-purpose",
  model: "haiku",
  run_in_background: true,
  prompt: "Grep the filesystem under $HOME (excluding node_modules, .git, Library/Caches) for Discord credentials. Patterns: bot tokens look like base64 segments separated by dots (e.g. MTAxXXXX.YYYYYY.ZZZZZZZZZZZZ), webhook URLs start with https://discord.com/api/webhooks/ or https://discordapp.com/api/webhooks/, guild IDs are 17-20 digit snowflakes adjacent to the word 'guild' or 'server'. Also scan ~/.config, ~/.env, any .envrc files, and Doppler/1Password exports. Return every hit with file path + line number + 6-char redacted prefix. Do not print full tokens."
)

調査が進行している間に、次のセットアップ手順に進みます。エージェントから結果が返ったら Discord に戻り、AskUserQuestion で調査結果を提示します(ルール 1 に従い、選択肢は最大 4 つに分割します)。

[Paste bot token] が選択された場合:

Enter your Discord Bot Token:
  Find it: https://discord.com/developers/applications → your app → Bot → Reset Token
  Format: MTAxXXXX.YYYYYY.ZZZZZZZZZZZZZZ  (base64 dot-separated)
  Prefer a Doppler reference (doppler:DISCORD_BOT_TOKEN) over the raw value.

Enter your Discord Guild ID (optional — needed for `channels` listing):
  Enable Developer Mode in Discord → right-click server → Copy ID.

スモークテスト(ルール 4 に従い、Bash 経由でバックグラウンド実行):

curl -sS "https://discord.com/api/v10/users/@me" \
  -H "Authorization: Bot $DISCORD_BOT_TOKEN" \
  -H "User-Agent: ops-discord (claude-ops, v1)" | jq '.id // .message'

数値のスノーフレーク id が返ることを確認してください。応答が {"message":"401: Unauthorized", ...} の場合は、もう一度入力を求めてください。

[Paste webhook URL only] が選択された場合:

Enter a default Discord Webhook URL:
  Find it: Discord → Server Settings → Integrations → Webhooks → New Webhook → Copy URL
  Format: https://discord.com/api/webhooks/<ID>/<TOKEN>

スモークテスト — セットアップ中に Webhook へコンテンツを送信してはいけません。代わりに GET を実行し、URL から Webhook のメタデータを取得できることを確認します。

curl -sS -o /dev/null -w '%{http_code}\n' -X GET "$DISCORD_WEBHOOK_URL"

200(Webhook のメタデータが返された)または 401(URL は有効だがトークンが無効。ユーザーに再コピーしてもらう必要があります)が返ることを確認してください。

設定に保存する

$PREFS_PATH に書き込みます(マージ)。

{
  "discord": {
    "bot_token": "doppler:DISCORD_BOT_TOKEN",
    "guild_id": "<GUILD_ID>",
    "default_webhook_url": "doppler:DISCORD_WEBHOOK_URL",
    "configured_at": "<ISO timestamp>"
  },
  "discord_webhook_url": "doppler:DISCORD_WEBHOOK_URL"
}

Webhook をフラットな discord_webhook_url キーにも反映し、既存の fires シンクである scripts/ops-notify.sh から引き続き参照できるようにします。Doppler が設定されている場合は、トークンをそのまま保存するよりも Doppler の参照を優先します。ネイティブのキーリングがあるシステムでは、プレーンテキストの設定よりも認証情報ストア(ops_cred_set discord bot-token <value>)を優先します。ユーザーが [Skip] を選択した場合は、次回の実行時にウィザードが再度尋ねないよう、{"discord": "skipped"} を保存します。

詳細: 完全な運用手順とサブコマンドのリファレンスについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-comms/SKILL.md(Discord の送信/読み取りの各セクション)と ${CLAUDE_PLUGIN_ROOT}/bin/ops-discord を参照してください。


ステップ 4 — MCP を設定する(選択した場合)

mcp_configured に含まれていない MCP ごとに、まず一括設定を提案します。

Unconfigured MCPs: Linear, Sentry, Vercel. What would you like to do?
  [Configure all MCPs — run claude mcp add for each (Recommended)]
  [Pick which MCPs to add]
  [Skip MCP configuration]

ユーザーが「すべて設定」を選択した場合は、設定されていない MCP ごとに claude mcp add <name> を順番に実行します。「選択する」を選択した場合は、各項目を個別に表示します。

Linear:  claude mcp add linear
Sentry:  claude mcp add sentry
Vercel:  claude mcp add vercel
Slack:   claude mcp add slack
Gmail:   claude mcp add gmail   (fallback only — prefer `gog` CLI, see Step 3c)

それぞれについて [今すぐ追加]、[スキップ] を提示します。スキルから MCP を登録しようとしてはいけません。プラグインから安全に登録することはできません。

メールに関する注意: ops プラグインの主なメール経路は gog CLI(読み取りと送信に完全対応し、独自の OAuth を使用)です。Gmail MCP コネクターは代替手段として機能しますが、Claude Desktop → Settings → Connectors で追加の権限を設定しないと送信できません。ウィザードはステップ 3c でその検出を処理します。このステップでは、MCP を意図的に使いたいユーザーがここでインストールできるよう、一覧に表示するだけです。

詳細: MCP を利用する統合機能(Linear の課題フロー、トリアージの振り分け、Sentry/Vercel のインシデント)に関する運用手順、CLI リファレンス、トラブルシューティングの詳細は、${CLAUDE_PLUGIN_ROOT}/skills/ops-linear/SKILL.md、${CLAUDE_PLUGIN_ROOT}/skills/ops-triage/SKILL.md、${CLAUDE_PLUGIN_ROOT}/skills/ops-fires/SKILL.md を参照してください。ウィザードで提供される内容だけでは不十分な場合、セットアップエージェントはこれらのファイルを直接読み込めます。


ステップ 5 — プロジェクトレジストリを作成する(選択した場合)

テンプレート: 一般的なスタック向けのスターター一式が ${CLAUDE_PLUGIN_ROOT}/scripts/registry.templates/ にあります。テンプレートを使って始める場合は、cp "${CLAUDE_PLUGIN_ROOT}/scripts/registry.templates/<stack>.json" "${CLAUDE_PLUGIN_ROOT}/scripts/registry.json" を実行してから編集してください。または、以下のウィザードで対話形式の検出を続けてください。

ファイルシステムから自動検出する

ユーザーにプロジェクトを手動で入力してもらう前に、既存の git リポジトリをスキャンします。

find ~ ~/Projects -maxdepth 2 -name ".git" -type d 2>/dev/null | sed 's|/.git||' | sort

multiSelect: true を指定した AskUserQuestion で、検出したパスをユーザーに提示します。1 回の呼び出しにつき選択肢は最大 4 つです。1 ページあたり 3 プロジェクトを表示し、最後の選択肢に [次へ...] または [該当なし — プロジェクトを手動で入力する] を追加してページ分けします。

Found git repositories (page 1 of N):
  [ ] ~/Projects/my-app
  [ ] ~/Projects/my-api
  [ ] ~/Projects/my-ai
  [ ] More repositories...

最終ページでは、「その他のリポジトリ...」を [上記以外/選択完了] に置き換えます。

選択されたプロジェクトごとに、次の各フィールドを AskUserQuestion で 1 つずつ収集します。

  • alias(短い名前。必須 — デフォルトとしてディレクトリ名を提案)
  • org(GitHub の組織名またはオーナー名。例:your-org または your-username)
  • infra.platform → [aws]、[vercel]、[cloudflare]、[other] から選択
  • revenue.model → 4 つずつに分けて選択:[saas]、[subscription]、[marketplace]、[More...]。続いて [internal]、[portfolio]、[other]
外部プロジェクトを自動検出する

実際のユーザーのポートフォリオが、Git リポジトリだけで構成されていることはほとんどありません。Shopify ストア、Linear チーム、Slack ワークスペース、Notion データベースは、ops-external と ops-projects が表示できる主要なプロジェクトですが、registry.json に登録されている場合に限ります。このサブステップでは、ウィザードで設定済みの連携を調べ、検出した項目をワンクリックで登録できるよう提示します。

${CLAUDE_PLUGIN_ROOT}/bin/ops-discover-external 2>/dev/null || echo '[]'

このスクリプトは、Shopify の認証情報を $PREFS_PATH .ecom.shopify.* と SHOPIFY_* 環境変数から、Linear の認証情報を LINEAR_API_KEY から、Slack の認証情報をキーチェーンの slack-xoxc/slack-xoxd から、Notion の認証情報を NOTION_API_KEY/キーチェーンの notion-api-key から読み取ります。マージ可能な状態の config ブロックをそれぞれ含む、候補プロジェクトの配列を返します。

候補を解析し、まだ registry.json に存在しないもの(config.alias または source + サービス固有の ID で照合)をそれぞれ AskUserQuestion で提示します。ルール 1(選択肢は最大 4 つ)に従い、1 回の呼び出しにつき候補は 3 件までとし、[More...] を追加します。バッチの例:

Found external projects not yet in your registry (page 1 of N):
  [Register "mystore" (shopify — basic plan, 142 products)]
  [Register "linear-eng" (linear — Engineering, 42 open issues)]
  [Register "notion-roadmap" (notion — Product Roadmap database)]
  [More candidates...]

最終ページでは、最後の選択肢を [None of the remaining — skip] にします。複数選択も可能です。その場合は、multiSelect: true の選択肢リストを 4 件以下にしてください。

承認された候補ごとに、jq を使ってその config ブロックを registry.json .projects[] に直接マージします。

PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT}"
REG="$PLUGIN_ROOT/scripts/registry.json"
[ -f "$REG" ] || echo '{"version":"1.0","owner":"","projects":[]}' > "$REG"
jq --argjson new "$CONFIG_JSON" '.projects += [$new]' "$REG" > "$REG.tmp" && mv "$REG.tmp" "$REG"

ステータスの処理:

  • discovered → そのまま登録します。
  • auth_expired → 警告を表示し、再試行する前に、該当するチャネルについて /ops:setup にユーザーを誘導します。
  • unreachable → [Register anyway (will show as unreachable in dashboards)]/[Skip] を提示します。

検出スクリプトが [] を返した場合は、情報行を 1 行だけ表示して(ℹ 外部プロジェクトは自動検出されませんでした。Shopify/Linear/Slack/Notion は下記から手動で追加できます。)、続行します。黙ってスキップしてはいけません。検出が実行されたことをユーザーに知らせる必要があります。

候補の認証情報の値が環境変数から取得されていて、ユーザーが後で Doppler を使いたい場合は、候補に保存された認証情報キー(SHOPIFY_ADMIN_TOKEN など)を、後から /ops:settings で doppler: 参照に安全に置き換えられます。

既存のレジストリ

registry.json にすでにプロジェクトがある場合は、最初に確認します(選択肢は 4 つで、1 回の呼び出しに収まります)。[Keep existing N projects]、[Add more projects]、[Auto-detect from existing registry]、[Start from scratch]。

  • 「既存を保持」→ このステップをスキップします。
  • 「既存のレジストリから自動検出」→ レジストリを再読み込みし、登録済みの内容を要約してから、不足しているフィールドや新たに検出されたリポジトリの追加を提案します。
  • 「新規作成」→ まず空のひな形({"version":"1.0","owner":"","projects":[]})を書き込みます。上書きする前に確認を求めてください。
  • 「さらに追加」→ 上記の自動検出スキャンを実行し、その後、代替手段として手動入力を提示します。
手動追加ループ

自動検出の後(またはユーザーが「プロジェクトを手動で入力する」を選択した場合):

  • AskUserQuestion で「別のプロジェクトを追加しますか?」と尋ねます → [Yes]、[Done]。
  • 「はい」の場合、以下のフィールドを一度に 1 つの AskUserQuestion で収集します:
    • alias(短い名前、必須)
    • paths(カンマ区切りの絶対パス、必須)
    • repos(カンマ区切りの org/repo、必須)
    • type → [monorepo]、[multi-repo] を選択
    • infra.platform → [aws]、[vercel]、[cloudflare]、[other] を選択
    • revenue.model → 4 つずつのバッチで選択:[saas]、[subscription]、[marketplace]、[More...] の後に [internal]、[portfolio]、[other]
    • revenue.stage → [pre-launch]、[development]、[growth]、[active] を選択
    • gsd → [Yes]、[No] を選択
    • priority(1〜99、デフォルトは最大値+1)
  • レジストリディレクトリの存在を確認します:mkdir -p "${CLAUDE_PLUGIN_ROOT}/scripts"。権限の問題で書き込みに失敗した場合(プラグインのキャッシュディレクトリは読み取り専用の場合があります)、$DATA_DIR/registry.json への書き込みにフォールバックし、シンボリックリンクを作成します。
  • jq で現在のレジストリを読み取り、新しいプロジェクトを追加し、アトミックに書き戻します(jq ... > tmp && mv tmp registry.json)。
  • 追加するたびに、現在の件数を表示し、[Add another] / [Done] を提示します。
  • レジストリエージェント(起動された場合)は、ターゲットパスへの書き込みアクセス権を必ず持っている必要があります。書き込みできない場合、セットアップウィザードはエージェントが返した JSON からファイル自体を書き込む必要があります — ユーザーに介入を求めないでください。

詳細解説: プロジェクトレジストリ(自動検出、レジストリスキーマ、GSD フィルター、優先順位付け)の完全な運用手順、CLI リファレンス、トラブルシューティングについては、${CLAUDE_PLUGIN_ROOT}/skills/ops-projects/SKILL.md を参照してください。このウィザードが提供する以上の詳細が必要な場合、セットアップエージェントはそのファイルを直接読み込むことができます。


ステップ 5b — デーモンサービスの調整

この時点で、デーモンはすでにステップ 2c でインストールされており、ユーザーがチャネルを設定している間、バックグラウンドでブリーフィングキャッシュを事前にウォームアップしています。このステップでは、どのチャネルと統合が設定されたかがわかったので、チャネル依存のサービス(wacli-sync、message-listener、inbox-digest、store-health、competitor-intel)を追加します。

スキップ条件:

  • ユーザーがステップ 2c でデーモンのインストールを拒否した場合、このステップを完全にスキップします。
  • $PREFS_PATH の daemon.enabled != true の場合、スキップします。

それ以外の場合は続行します — サービスリストを調整します:

1. デーモンが実行中であることを確認します:

DATA_DIR="${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}"
PLIST_DEST="$HOME/Library/LaunchAgents/com.claude-ops.daemon.plist"
launchctl print gui/$(id -u)/com.claude-ops.daemon >/dev/null 2>&1 || {
  # Daemon not running — install it now as a fallback
  launchctl bootstrap gui/$(id -u) "$PLIST_DEST" 2>/dev/null
}

2. 5 秒後にヘルスを確認します:

cat "$DATA_DIR/daemon-health.json" 2>/dev/null

JSON を解析します。action_needed が null でない場合、必要なアクションをユーザーに提示します。デーモンがヘルスファイルを書き込んだ場合、以下を出力します:

✓ Background daemon — running (wacli-sync: connected, memory-extractor: scheduled)

ヘルスファイルが存在しない場合(デーモンがまだ初期化中の可能性があります)、さらに 5 秒待って 1 回再試行します。それでも存在しない場合、以下を出力します:

⚠ Daemon started but health file not yet written. Check:
  launchctl print gui/$(id -u)/com.claude-ops.daemon
  tail -20 ~/.claude/plugins/data/ops-ops-marketplace/logs/ops-daemon.log

3. 完全なサービスリストを構築し、ステップ 2c で書き込まれた設定と調整します:

以前のステップで設定された内容に基づいて、有効にするサービスを決定します。briefing-pre-warm と memory-extractor サービスはすでにステップ 2c で有効化されています — それらを保持します。現在設定されている内容に基づいて、チャネル依存のサービスを追加します:

  • wacli-sync — WhatsApp が設定されている場合(channels.whatsapp が設定されている場合)は常に含めます
  • memory-extractor — 常に含めます
  • inbox-digest — 常に含めます(4 時間ごとに実行され、設定されたすべてのチャネルを集約します)
  • store-health — eコマースが設定されている場合($PREFS_PATH に ecom.shopify.store_url が設定されている場合)にのみ含めます
  • competitor-intel — 常に含めます(毎週月曜日 10 時に実行されます)
  • message-listener — WhatsApp または Telegram が設定されている場合に含めます(常駐ポーラー)

services 配列をプログラムで構築します(2c のベースラインから開始):

SERVICES='["briefing-pre-warm","memory-extractor","inbox-digest","competitor-intel"]'
PREFS=$(cat "$PREFS_PATH" 2>/dev/null || echo '{}')
# Add wacli-sync + message-listener if WhatsApp is configured
if echo "$PREFS" | jq -e '.channels.whatsapp' > /dev/null 2>&1; then
  SERVICES=$(echo "$SERVICES" | jq '. + ["wacli-sync","message-listener"]')
fi
# Add message-listener for Telegram too (deduplicate)
if echo "$PREFS" | jq -e '.channels.telegram' > /dev/null 2>&1; then
  SERVICES=$(echo "$SERVICES" | jq '. + ["message-listener"] | unique')
fi
# Add store-health only if Shopify is configured
if echo "$PREFS" | jq -e '.ecom.shopify.store_url' > /dev/null 2>&1; then
  SERVICES=$(echo "$SERVICES" | jq '. + ["store-health"]')
fi
echo "Services to enable: $SERVICES"

デーモンサービス設定を $DATA_DIR/daemon-services.json に書き込みます。Step 2c の既存設定と統合し、briefing-pre-warm と memory-extractor を維持し、新しいチャネル依存サービスを有効にします。各サービスには必ず command フィールドを含めてください。デーモンの start_service() は、これがないサービスをスキップします。スクリプトのパスには、実行時に解決される ${CLAUDE_PLUGIN_ROOT} を使用します。各サービスのエントリーには、以下を含めてください。

  • briefing-pre-warm: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/bin/ops-gather", "cron": "*/2 * * * *" } — /ops:go キャッシュを事前にウォームアップします(2c でインストール済み)
  • wacli-sync: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/scripts/wacli-keepalive.sh", "health_file": "~/.wacli/.health", "restart_delay": 60, "max_restarts": 10 } — WhatsApp が設定されている場合のみ
  • memory-extractor: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/scripts/ops-memory-extractor.sh", "health_file": "~/.claude/plugins/data/ops-ops-marketplace/memories/.health", "cron": "*/30 * * * *" } — 30 分ごと(2c でインストール済み)
  • inbox-digest: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/scripts/ops-cron-inbox-digest.sh", "cron": "0 */4 * * *" } — 4 時間ごと
  • store-health: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/scripts/ops-cron-store-health.sh", "cron": "0 9 * * *" } — 毎日午前 9 時、eコマースが設定されている場合のみ
  • competitor-intel: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/scripts/ops-cron-competitor-intel.sh", "cron": "0 10 * * 1" } — 毎週月曜日の午前 10 時
  • message-listener: { "enabled": true, "command": "${CLAUDE_PLUGIN_ROOT}/scripts/ops-message-listener.sh" } — WhatsApp または Telegram が設定されている場合のみ

サービス設定を書き換えた後、簡易ヘルスチェックをフォアグラウンドで実行し(2 秒未満)、続いてリロードをバックグラウンドで実行します。

# Quick health check — foreground (fast)
test -f "$DATA_DIR/daemon-services.json" && echo "✓ Daemon services config written — N services enabled"

次に、実際のデーモンのリロードをバックグラウンドで実行します。時間がかかる場合があります。

# Background — daemon reload is slow, don't block setup
launchctl kickstart -k gui/$(id -u)/com.claude-ops.daemon 2>&1 && echo "✓ Daemon reloaded" || echo "⚠ Daemon kick failed (may still be running)"

リロードコマンドには run_in_background: true を使用してください。完了を待たず、すぐに次のステップへ進んでください。kickstart が遅くても、デーモンは次のサイクルで新しい設定を自動的に取得します。

daemon.enabled = true と daemon.services(調整済みの配列)を $PREFS_PATH に書き込みます。次を出力します。

✓ Daemon services reconciled — N services enabled (briefing-pre-warm, memory-extractor, wacli-sync, ...)
  Daemon reloading in background.

詳細: バックグラウンドデーモンの運用手順、CLI リファレンス、トラブルシューティング(サービスのライフサイクル、launchctl/systemd との統合、ヘルスレポート、調整のセマンティクス)については、${CLAUDE_PLUGIN_ROOT}/docs/daemon-guide.md を参照してください。このセットアップエージェントは、このウィザードの説明だけでは不十分な場合に、ファイルを直接読み込めます。


ステップ 6 — 設定を保存する(選択した場合)

AskUserQuestion を使って収集します。各項目につき 1 つ質問してください。メモリ、既存の設定、または以前のセッションから自動入力してはいけません。必ず明示的に質問してください。

  1. 所有者名(自由入力):「ブリーフィングでは、Claude に何と呼ばれたいですか?」— デフォルト値なし、メモリからの候補提示なし。

  2. タイムゾーン(単一選択 — 呼び出しあたり最大 4 つの選択肢、地域ごとにまとめる):

    まず、date +%Z または readlink /etc/localtime を使ってシステムのタイムゾーンを検出します。検出できた場合は、最初の選択肢として提示します。

    Select your timezone:
      [<detected timezone>]
      [Americas...]
      [Europe/Asia/Oceania...]
      [Other — type it]
    

    ユーザーが「Americas...」を選んだ場合:[America/New_York]、[America/Los_Angeles]、[America/Chicago]、[Back] ユーザーが「Europe/Asia/Oceania...」を選んだ場合:[Europe/London]、[Asia/Bangkok]、[Asia/Tokyo]、[Australia/Sydney]

  3. ブリーフィングの詳しさ(単一選択):

    How much detail do you want in briefings?
      [full]     — complete rundown of all channels, projects, and incidents
      [compact]  — key signals only, one line per item
      [minimal]  — just the fires and urgent items
    
  4. 主要プロジェクト → 「過去 7 日間にアクティブだったすべてのプロジェクト」を最初のデフォルト選択肢にしてください。 複数のプロジェクトに取り組むユーザーの多くは、単一プロジェクトに絞ったブリーフィングではなく、統合されたブリーフィングを求めています。

    Primary project for briefings?
      [All projects active in last 7 days]  ← default
      [Pick a specific project...]
    

    「特定のプロジェクト」を選んだ場合は、レジストリのエイリアスを 1 ページあたり 3 件、[More...] とともにページ分けして表示します。デフォルトの場合は "primary_project": "all_active_7d"、特定のエイリアスの場合はそのエイリアスを保存します。

  5. YOLO モード → [Yes — auto-approve low-risk actions]、[No — always confirm] を選択します。

  6. デフォルトのチャンネル(単一選択 — 次の 2 つの選択肢は相互排他的です)。「設定済みのすべて」を最初の選択肢として表示し、デフォルトで事前選択してください — ほとんどのユーザーは、すべてのチャンネルを有効にしたいと考えています。

    Which channels should ops skills use by default?
      [All configured channels]
      [Pick specific channels...]
    

    ユーザーが「特定のチャンネル」を選んだ場合は、個々のチャンネルのチェックボックスを表示する follow-up multiSelect を表示します。「設定済みのすべて」を選んだ場合は、設定済みチャンネル名の全リストを default_channels に設定します。

$PREFS_PATH に書き込みます:

{
  "version": "1.0",
  "owner": "...",
  "primary_project": "...",
  "timezone": "...",
  "briefing_verbosity": "...",
  "yolo_enabled": false,
  "default_channels": ["whatsapp", "email"],
  "secrets_manager": "doppler",
  "doppler": {
    "project": "...",
    "config": "..."
  },
  "channels": {
    "telegram": { "bot_token": "...", "owner_id": "..." }
  }
}

ファイルがすでに存在する場合は、上書きせずにマージします。jq で読み込み、jq '. + { ... }' で更新を適用して書き戻します。


ステップ 7 — シェル環境(選択した場合)

  1. プロファイルファイルで CLAUDE_PLUGIN_ROOT がすでにエクスポートされているか確認します(CLAUDE_PLUGIN_ROOT を grep します)。
  2. 見つからない場合は、自動的に追記してください — これは必須の手順であり、任意ではありません。>> を使います(追記し、上書きはしません)。次を表示します:"✓ Added export CLAUDE_PLUGIN_ROOT=... to ~/.zshrc"。ユーザーに許可を求めてはいけません — ここではルール 2(ユーザーにコマンドの実行を委ねない)が適用されます。
  3. ユーザーに次のように伝えます:"Run 'source ~/.zshrc' or open a new terminal for it to take effect." — これは Claude の次のツール呼び出しで承認プロンプトとして表示され、通常どおりユーザーが承認します。

ステップ 8 — 最終サマリーと検証

検出処理を再実行し、最終ステータスダッシュボードを表示します:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► SETUP COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 ✓ Core CLIs:  jq, git, gh, aws, node
 ✓ Channels:   telegram, whatsapp, email
 ✓ Ecommerce:  shopify (<store_url>)             ← omit line if not configured
 ✓ Marketing:  klaviyo, meta, google-ads, ga4, gsc           ← omit line if not configured
 ✓ Voice:      bland, elevenlabs, groq           ← omit line if not configured
 ✓ Secrets:    doppler → my-app/dev
 ✓ MCPs:       linear, sentry, vercel
 ✓ Registry:   20 projects
 ✓ Prefs:      saved to ~/.claude/plugins/data/ops-ops-marketplace/preferences.json
 ✓ Daemon:     ops-daemon → wacli-sync, memory-extractor, inbox-digest

 Next: /ops-go for your first briefing
──────────────────────────────────────────────────────

ecommerce、marketing、voice の各項目について、そのカテゴリで少なくとも 1 つのサービスが設定されている場合にのみステータス行を表示します。設定済みの場合は ✓、スキップした場合は ○ を使います。そのセクションに一度もアクセスしていない場合は、行全体を省略します。

デーモンの行には、実際に有効になったサービスのみを記載します(ステップ 5b で計算された services 配列から取得します)。

必須ツールがまだ不足している場合は、そのツールとインストールするための正確なコマンドを一覧表示し、成功したと断言する前に処理を止めます。

サマリーを表示した後、セットアップの成功を祝う完了バナーを実行します。セットアップセッションの実際の件数を渡します:

bash ${CLAUDE_PLUGIN_ROOT}/bin/ops-setup-complete --channels <N> --projects <N> --agents 9 --skills 15

<N> は、このセッションで設定したチャンネル数および登録したプロジェクト数に置き換えます。


デーモンのヘルス契約

すべての ops スキルは、バックグラウンドサービスに依存する前にデーモンのヘルスを確認してください:

cat ~/.claude/plugins/data/ops-ops-marketplace/daemon-health.json

action_needed が null でない場合は、続行する前に必要な対応をユーザーに提示します。 デーモンが実行されていない場合は、起動を提案します:launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.claude-ops.daemon.plist


呼び出しショートカット

$ARGUMENTS に特定のセクション名が含まれている場合、そのセクションに直接移動します。

引数移動先
cli, installステップ 2
channelsステップ 3
telegramステップ 3a
whatsapp, wacli, whatsapp-doctorステップ 3b
emailステップ 3c
slackステップ 3d
notionステップ 3e
calendar, calステップ 3f
doppler, secretsステップ 3g
vault, password-manager, pmステップ 3h
ecom, shopify, storeステップ 3i
marketing, klaviyo, ads, meta, ga4ステップ 3j
google-ads, gadsステップ 3j(Google Ads)
voice, bland, elevenlabs, ttsステップ 3k
mcpステップ 4
registry, projectsステップ 5
daemon, backgroundステップ 5b
prefs, preferencesステップ 6
env, shellステップ 7

引数が空の場合 → ステップ 0 からウィザード全体を開始します。


安全性

  • 絶対に、明示的な AskUserQuestion による確認なしに brew install を実行したり、ファイルを書き込んだりしないでください。
  • 絶対に、差分を表示して確認を求めずに既存のファイルを上書きしないでください。
  • 絶対に、シークレットを registry.json に入れたり、コミットしたりしないでください。シークレットは $PREFS_PATH(プラグインのソースツリーの完全に外側にある、Claude Code のプラグインごとのデータディレクトリ)またはユーザーのシェルプロファイルにのみ保存します。
  • 絶対に、~/.claude.json や ~/.claude/settings.json に触れないでください。MCP の登録はあなたではなく、Claude Code が行います。
  • 現在のセッションでユーザーが明示的に提供していない限り、出力にユーザーの本名やメールアドレスを表示しないでください。表示名を設定するために、メモリファイル、既存の設定、環境変数から情報を読み込まないでください。

付録:CLI リファレンス(正確な構文 — 推測しないこと)

gog(v0.12.0+)
トップレベルのコマンド

auth, gmail, calendar, contacts, drive, docs, slides, sheets, forms, tasks, keep, chat, people, appscript, config, agent

Gmail — 検索と読み取り
gog gmail search "<query>" --max N -j --results-only --no-input    # Search threads (Gmail query syntax)
gog gmail thread get <threadId> -j                                  # Get full thread with all messages
gog gmail get <messageId> -j                                        # Get single message
Gmail — 操作
gog gmail archive <messageId> ... --no-input --force               # Archive messages (remove from inbox)
gog gmail archive --query "<gmail-query>" --max N --force           # Archive by query
gog gmail mark-read <messageId> ... --no-input                     # Mark as read
gog gmail unread <messageId> ... --no-input                        # Mark as unread
gog gmail trash <messageId> ... --no-input --force                 # Move to trash
Gmail — ラベル
gog gmail labels list -j                                            # List all labels
gog gmail labels modify <threadId> --add LABEL --remove LABEL       # Modify thread labels
gog gmail messages modify <messageId> --add LABEL --remove LABEL    # Modify message labels
Gmail — 送信と返信
gog gmail send --to "[email protected]" --subject "subj" --body "text"                    # Send new email
gog gmail send --to "[email protected]" --subject "Re: ..." --body "reply" --reply-to-message-id <msgId>  # Reply
gog gmail send --reply-to-message-id <msgId> --reply-all --body "reply text"             # Reply all
gog gmail send --to "[email protected]" --subject "subj" --body "text" --attach /path/to/file      # With attachment
Gmail — 下書き
gog gmail drafts list -j                                            # List drafts
gog gmail drafts create --to "[email protected]" --subject "subj" --body "text"
Calendar
gog calendar calendars -j                                           # List calendars
gog calendar events primary --today -j                              # Today's events
gog calendar events primary --from "2026-04-14" --to "2026-04-15" -j  # Date range
gog calendar create primary --summary "Meeting" --from "2026-04-15T10:00:00" --to "2026-04-15T11:00:00"
gog calendar freebusy --from "2026-04-14T00:00:00Z" --to "2026-04-14T23:59:59Z" -j
Contacts
gog contacts search "name" -j                                       # Search contacts
gog contacts list -j                                                # List all contacts
Drive
gog drive ls -j                                                     # List files
gog drive search "query" -j                                         # Search files
gog drive download <fileId>                                         # Download file
Tasks
gog tasks lists                                                     # List task lists
gog tasks list <tasklistId> -j                                      # List tasks
認証
gog auth status                                                     # Check auth status
gog auth add [email protected] --services gmail,calendar,drive,contacts,docs,sheets
wacli
# Health check
wacli doctor --json

# Auth status
wacli auth status --json

# List chats (MUST use subcommand `list`)
wacli chats list --json

# List messages (--after flag uses YYYY-MM-DD)
# macOS
wacli messages list --after="$(date -v-1d +%Y-%m-%d)" --limit=5 --json
# Linux
wacli messages list --after="$(date -d '1 day ago' +%Y-%m-%d)" --limit=5 --json

# Send message
wacli send --to "JID" --message "text"

# Sync (connect and pull)
wacli sync

# Backfill history
wacli history backfill --chat="JID" --count=50 --requests=2 --wait=30s --idle-exit=5s --json

# Contact lookup
wacli contacts --search "name" --json

セットアップ後、memory-extractor デーモンサービスがこの連絡先データから memories/contact_*.md にデータを追加します。

Slack トークンの検証
curl -s -H "Authorization: Bearer XOXC_TOKEN" -b "d=XOXD_TOKEN" "https://slack.com/api/auth.test"
macOS Keychain
security find-generic-password -s "KEY_NAME" -w 2>/dev/null
security add-generic-password -U -s "KEY_NAME" -a "$USER" -w "VALUE"
security delete-generic-password -s "KEY_NAME" 2>/dev/null

コメント