mcpField
B
Banjo

Banjo

ローカル
github.comコミュニケーション2今日更新

Banjo について

Banjo はセルフホスト可能な単一テナントの音声アシスタントで、予約や問い合わせなどの実際の電話を行います。カレンダーと予約時刻を照合し、明確な確認を得てから予約を記録します。

主な機能

  1. 01電話での予約
  2. 02店舗への最大5件の質問
  3. 03後から発信する電話の予約
  4. 04留守番電話・電話メニュー・保留への対応
  5. 05任意の着信予約回線
  6. 06通話と連絡先管理用の11個のMCPツール

活用シーン

  1. 01カレンダーの空き時間に合わせた予約
  2. 02営業時間や価格を店舗に電話で確認
  3. 03後で発信する電話を設定
  4. 04着信回線からの予約や変更を受け付ける

MCP 対応

Claude Code向けに、発信、通話確認・キャンセル・停止、文字起こしの参照、連絡先管理を行う11個のMCPツールを提供します。通話終了後、署名付きJSONイベントを設定済みのWebhookに送信することもできます。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"shatch-banjo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"DATABASE_URL",
"-e",
"MCP_API_KEY",
"-e",
"ASSISTANT_PRINCIPAL_NAME",
"-e",
"PUBLIC_HOSTNAME",
"-e",
"VOICE_AI_PROVIDER",
"-e",
"OPENAI_API_KEY",
"-e",
"TWILIO_ACCOUNT_SID",
"-e",
"TWILIO_AUTH_TOKEN",
"-e",
"TWILIO_PHONE_NUMBER",
"-e",
"NOTIFICATION_CHANNEL",
"ghcr.io/shatch/banjo:0.1.16"
],
"env": {
"DATABASE_URL": "<DATABASE_URL>",
"MCP_API_KEY": "<MCP_API_KEY>",
"ASSISTANT_PRINCIPAL_NAME": "<ASSISTANT_PRINCIPAL_NAME>",
"PUBLIC_HOSTNAME": "<PUBLIC_HOSTNAME>",
"VOICE_AI_PROVIDER": "<VOICE_AI_PROVIDER>",
"OPENAI_API_KEY": "<OPENAI_API_KEY>",
"TWILIO_ACCOUNT_SID": "<TWILIO_ACCOUNT_SID>",
"TWILIO_AUTH_TOKEN": "<TWILIO_AUTH_TOKEN>",
"TWILIO_PHONE_NUMBER": "<TWILIO_PHONE_NUMBER>",
"NOTIFICATION_CHANNEL": "<NOTIFICATION_CHANNEL>"
}
}
}
}
起動コマンドdocker run -i --rm -e DATABASE_URL -e MCP_API_KEY -e ASSISTANT_PRINCIPAL_NAME -e PUBLIC_HOSTNAME -e VOICE_AI_PROVIDER -e OPENAI_API_KEY -e TWILIO_ACCOUNT_SID -e TWILIO_AUTH_TOKEN -e TWILIO_PHONE_NUMBER -e NOTIFICATION_CHANNEL ghcr.io/shatch/banjo:0.1.16
設定が必要な環境変数
DATABASE_URLシークレットPostgres connection URL. Migrations run on boot.
MCP_API_KEYシークレットBearer token MCP clients must send (at least 32 characters, e.g. openssl rand -hex 32).
ASSISTANT_PRINCIPAL_NAMEThe name of the person Banjo calls on behalf of.
PUBLIC_HOSTNAMEPublic hostname Twilio reaches this server on (no scheme), e.g. a tunnel or reverse proxy.
VOICE_AI_PROVIDERVoice AI vendor. openai is the one carrying live traffic.
OPENAI_API_KEYシークレットOpenAI API key, for VOICE_AI_PROVIDER=openai or openai-live.
TWILIO_ACCOUNT_SIDTwilio account SID.
TWILIO_AUTH_TOKENシークレットTwilio auth token.
TWILIO_PHONE_NUMBERThe Twilio number Banjo calls from, in E.164 (+15551234567).
NOTIFICATION_CHANNELHow Banjo tells you a call's outcome. twilio_sms also needs NOTIFY_TO_PHONE_NUMBER and NOTIFY_FROM_PHONE_NUMBER; pushover needs PUSHOVER_APP_TOKEN and PUSHOVER_USER_KEY.

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
ocighcr.io/shatch/banjo:0.1.16

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

Banjo のロゴ

Banjo

Banjo は、先延ばしにしていた電話を代わりにかけます。 散髪の予約、金曜日に Luigi's のテーブルを予約、折り返しの電話がない業者への催促などを伝えるだけで、Banjo が電話をかけ、応答した相手と話し、カレンダーを確認して日時を調整し、予約します。

オープンソースで、自分の Twilio 番号と音声 AI アカウントを使って、自分で運用できます。 設計上、シングルテナントです。通話も認証情報もデータも自分のもので、コードを読んで変更できます。

Banjo は、2 つで構成される仕組みの電話側です。もう一方は Claude Code のスキル (skills/schedule-appointment/)で、用事をオンラインで済ませられるか判断し、できない場合にだけ電話をかけます。

希望すれば、自分の電話番号への着信にも応答します。任意で着信専用回線を設定すれば、相手は予約、確認、日時変更を行えます。また、Google または CardDAV(Fastmail、iCloud)の連絡先に登録済みの発信者を認識します。

通話を聞く

https://github.com/user-attachments/assets/c599a672-8d4e-46f9-8868-64e0840c589b

実際の通話を聞く(2:11):Banjo が犬のグルーミングを予約します。 通話とカレンダーは実際のものですが、トリマーはロールプレイです。Banjo は尋ねられると AI だと伝え、犬について把握している情報を使い、会議と重なる時間帯を断り、予約前に明確な了承を待ってから、カレンダーに予定を登録します。これは初期の通話です。それ以降、Banjo は電話を切る前に予約内容を読み上げるようになり(#47)、尋ねられるのを待たず、すべての通話の冒頭で AI だと伝えるようになりました(#8)。

文字起こし(自動文字起こしを軽く整えたもの)

Banjo: こんにちは。Steve に代わって、犬の Banjo のグルーミングを予約するために電話しています。こちらは Claudia's Fabulous Dog Grooming でしょうか?

Claudia: はい、すみません。Claudia's Fabulous Dog Grooming です。この通話は録音される場合があります。Claudia です。どのようなご用件でしょうか?

Banjo: こんにちは、Claudia さん。ご対応ありがとうございます。Steve に代わって、犬の Banjo のグルーミングを予約するために電話しています。全身のグルーミングを希望しています。新規のお客様で、人懐っこい子ですが、濡れるのはあまり好きではなく、バリカンに緊張することがありますので、優しく対応していただけると助かります。空いている日時はありますか?

Claudia: すみません、本物の人と話しているんですか?

Banjo: Steve に代わって電話している AI アシスタントです。よろしければ、予約の手配をお手伝いできます。Banjo の全身グルーミングで、空いている日時を教えていただけますか?

Claudia: ちょっと、犬の名前は何でしたっけ?

Banjo: Banjo です。Steve の犬です。

Claudia: 犬種と、おおよその大きさを教えてもらえますか?

Banjo: Banjo は小型のテリアのミックスで、おそらくケアーン・テリアです。小さくて人懐っこく、そちらに行くのは初めてです。

Claudia: 全身のグルーミングですか? それともシャンプーだけですか?

Banjo: 全身のグルーミングを希望しています。Banjo にとって最適な内容に調整が必要でしたら、それで構いません。きれいにして、毛を整えていただければと思います。

Claudia: 24日木曜日の3時30分なら予約できます。

Banjo: 少々お待ちください。……ありがとうございます。その時間は Steve の都合がつきません。別の時間を試せますか? 可能でしたら、午前中の早い時間が都合よいです。

Claudia: 金曜日なら、午前10時に入れられるかもしれません。確認してみます。

Banjo: はい、少々お待ちください。……金曜日の午前10時なら Steve の都合がつきそうです。Banjo の全身グルーミングをその時間に予約しましょうか?

Claudia: ええ、おそらく大丈夫です。

Banjo: では確認させてください。金曜日の午前10時に、Banjo の全身グルーミングを予約してもよろしいですか?

Claudia: はい、お願いします。25日金曜日の午前10時から、全身のグルーミングで90分ですね。予約してください。

Banjo: 少々お待ちください。……確認ありがとうございます。では、これで失礼します。

できること

電話での機能

  • 予約を取ります。 カレンダー(Google Calendar、またはFastmailやiCloudなどのCalDAVカレンダー)と照らし合わせて時間を調整し、明確な承諾を得てから予約を取ります。Postgresには、モデルが口頭で何と言ったかではなく、予約が実際に成立したかどうかを記録します。
  • 会話します。 mode: conversation の呼び出しでは、予約を目的とせず、メッセージを伝えたり、何かについて話し合ったりできます。
  • 情報を確認します。 mode: ask の呼び出しでは、営業時間、価格、在庫の有無など、最大5つの質問を相手に電話で尋ね、それぞれの回答、または回答が得られなかったことを構造化データで返します。予約もせず、何かに同意することもありません。
  • 後で電話をかけます。 place_call の scheduledFor を指定すると、設定した時刻に発信します。再起動後も予定は保持されます。
  • 留守番電話と電話メニューに対応します。 留守番電話にメッセージを残し、実際に音声が再生されたことを確認します。また、電話メニューを進むために番号を押します。
  • 保留中も待機します。 保留キューで静かに待機します(最大 HOLD_MAX_MINUTES 分、デフォルトは20分)。保留が始まると通知し、相手が応答したらAIであることを最初に伝えて、通話を再開します。RECORD_CALLS が有効な場合、保留開始時に録音を停止するため、応答した相手には録音の通知が聞こえません。
  • 通話をあなたに引き継ぎます。 相手が人間との会話を求めた場合、オプションで通話を転送します。あなたの電話番号への発信では、1を押した場合にのみ接続されます(TRANSFER_ENABLED)。TRANSFER_MODE=warm の場合、Banjoは別回線であなたに電話して、相手を保留にしたまま概要を伝えます。あなたが応答しなければ、相手との通話を続けます。
  • 通話中にあなたに質問します。 依頼内容にない質問を相手から受けると、Banjoは確認すると伝え、リンクとともに質問をあなたに送ります。そこで入力した内容が相手に伝えられます(ASK_OWNER_ENABLED)。
  • 転送後の会話も記録します。 オプションで、コールド転送後のあなたと相手の会話を、双方に録音の通知を伝えてから通話の文字起こしに追加できます。文字起こしが終わると音声は削除されます(TRANSCRIBE_TRANSFERS)。
  • あなたの番号への着信に応答します。 オプションの着信用回線を使うと、相手は予約、確認、変更ができます。また、GoogleまたはCardDAVの連絡先から識別した発信者には、名前を呼んで応答します(INBOUND_BOOKING_ENABLED)。

安全対策

  • AIであることを伝えます。 すべての発信は DISCLOSURE_LINE で始まり、この文には「AI」と明記する必要があります。また、各通話でその文を伝えたかどうかを記録します。
  • 通知を伝えた後にのみ録音します。 録音はオプション(RECORD_CALLS)で、Banjoが録音の通知を伝えた後にのみ開始します。
  • しつこく電話しません。 24時間のローリング期間中、同じ番号への発信は最大3回までで、上限を回避する方法はありません。
  • 選んだ設定を保持します。 文字起こしは有効にした場合のみ保存され(PERSIST_TRANSCRIPTS)、文字起こしと録音は、デフォルトではどちらも30日後に削除されます。ログでは電話番号と通話内容がマスキングされます。

利用方法

  • Claude Code向けの11個のMCPツール: 通話の発信、確認、キャンセル、停止、文字起こしの閲覧、連絡先の管理ができます。
  • 通話結果を通知します。 通話ごとに結果の概要をSMSまたはPushoverで通知します。
  • エージェントにも通知します。 TASK_WEBHOOK_URL を設定すると、完了した通話ごとに署名付きJSONイベントがPOSTされます。これにより、OpenClawやHermes Agentなどのエージェントは、ポーリングせずに結果を受け取れます。
  • あなたの好みを把握します。 継続的なメモを記したオーナープロフィールが、すべての通話に追加されます(以下を参照)。
  • 簡単に実行できます。 npm run setup で検証済みの .env が作成され、docker compose up で公開済みのamd64/arm64イメージが起動します。ノートパソコンがスリープ中も実行し続ける方法については、常時稼働のLinuxホストでBanjoを実行するを参照してください。 完全な設計についてはdocs/ARCHITECTURE.md、今後の予定についてはdocs/ROADMAP.md、Claude Code、Hermes Agent、またはOpenClawの接続方法についてはdocs/AGENT_SETUP.md、運用手順についてはdocs/RUNBOOKS.md、この分野の他のオープンソースプロジェクトとの比較についてはdocs/COMPETITIVE_LANDSCAPE.mdをご覧ください。

Banjoのランタイムアーキテクチャ

既知の制限事項

Banjoは実際に電話をかけ、実際の予約を行っており、これまで安定して動作しています。一方で、まだ新しく、小規模なプロジェクトです。利用を始める前に知っておくべき点を以下に示します。

  • 実際に動作が確認されている音声プロバイダーは1つだけです。 ライブトラフィックを処理しているアダプターはOpenAI Realtimeだけです。openai-live(GPT-Live)は実際の通話でテスト済みですが、デフォルトではありません。Gemini LiveとElevenLabsは実装の土台のみ用意されており、動作確認されていません。さらに、Geminiは発信者側の文字起こしを一切出力しません。
  • AIであることの開示はプロンプト内のルールであり、通話後に確認されます。強制はされません。 Banjoには、すべての通話をDISCLOSURE_LINE(デフォルト:「こんにちは。{name}に代わってお電話しているAIアシスタントです。」)で始めるよう指示されており、最初の発話は通話後に確認されます。開示がなかった場合は通話試行に記録され、通知にも記載されますが、未開示の通話を防ぐものではありません。 AIであることの開示や双方の同意に関する規則(TCPA/FCC、カリフォルニア州AB 2905など)が適用される地域では、ご自身の通話を確認してください。 (#8)
  • 録音と文字起こしの対象は発信通話のみです。 録音はTwilioアカウント内(2トラック)に保存され、文字起こしはPostgresに保存されます。どちらもデフォルトでは無効です。着信通話は録音されません。(#6)
  • 通話の転送は保留転送で、転送先は固定の1つの番号です。 Banjoは相手が同意した後にのみ転送し、モデルが接続先を選ぶことはありません。接続前に通話の要約を受け取ることはできず、Banjoが通話に残ることもできません。応答しなかった場合、発信者にはTRANSFER_FALLBACK_MESSAGEが再生され、通話は終了します。着信回線では、連絡先に登録済みの発信者のみ転送できます。それ以外の人があなたへの取り次ぎを求めた場合は、折り返しが必要な人として通知されるため、自動音声の迷惑電話があなたの電話を鳴らすことはありません。 (#7、#66)
  • 米国の電話番号へのSMS送信にはキャリア登録が必要です。 A2P 10DLC登録がない場合、結果を知らせるテキストメッセージはキャリアによってブロックされます。Pushoverには登録は不要です。docs/RUNBOOKS.mdの「SMS notifications aren't arriving」をご覧ください。
  • ログはマスキングされますが、アクセス制御はされません。 電話番号は下4桁のみが記録され、ボイスメールのテキストとツールの生の引数は文字数のみが記録されます。ただし、ベンダーからのエラーメッセージに電話番号が含まれることはあり、LOG_TRANSCRIPTS=trueにすると通話の全文が意図的に記録されます。ログは機密情報として扱ってください。
  • 同時に通話できるのは1件だけです。 通話中に着信した場合、着信回線はその通話を拒否します。
  • 外部からアクセス可能なホスト名が必要です。 TwilioがHTTPSとWebSocket経由でコールバックするためです。Quickstartと、これを取り除くことが難しい理由を説明しているdocs/spikes/2026-09-21-outbound-registration-worker.mdをご覧ください。
  • 恒久的にシングルテナントです。 1つのインスタンスで利用できるのは1人だけです。Banjoが意図的に対応しないその他の点についてはCONTRIBUTING.mdをご覧ください。

1回あたりの通話料金

料金は各ベンダーに直接支払います。2026-09-21に確認した単価:

項目料金参照元
Twilio の米国内ローカル番号への発信音声通話$0.0140 / 分Twilio voice pricing
Twilio の米国内ローカル番号への着信音声通話$0.0085 / 分同上
Twilio の米国内ローカル電話番号$1.15 / 月同上
OpenAI gpt-realtime の音声入力$32.00 / 100万トークンOpenAI API pricing
OpenAI gpt-realtime の音声出力$64.00 / 100万トークン同上
OpenAI gpt-4o-mini-transcribe(発信者側の文字起こし)100万トークンあたり入力 $1.25 / 出力 $5.00同上
有効にした場合の Twilio SMS 通知米国内、メッセージ単位Twilio SMS pricing

リアルタイム音声トークンを1分あたりの料金に換算するのは困難です。入力は会話の長さに応じて増え、無音でも課金され、モデルがどれだけ話すかは通話ごとに異なるためです。実際の通話で測定したベンダー料金の合計は、1分あたりおよそ $0.11~$0.17 です。その大部分は電話料金ではなく音声 AI の料金です。3分間の予約通話なら、およそ $0.35~$0.50 です。

通話を転送(TRANSFER_ENABLED)すると、Twilio の課金対象となる区間がもう1つ追加されます。上記の発信料金で TRANSFER_TO_PHONE_NUMBER に発信し、通話中はその分の料金がかかります。会話中は元の通話区間も接続されたままです。通話が引き継がれると、音声 AI の課金は停止します。

正直にお伝えしたい点が2つあります。gpt-realtime-mini を選ぶと、品質が多少落ちる代わりに音声料金は約3分の1になります。また、SaaS サブスクリプションの節約のために Banjo を動かすのはおすすめしません。この料金では、節約額があなたの1時間分の手間に見合うほどになるには、かなりの通話数が必要です。Banjo を使うのは、自分のものだからです。

電話を使わずに試す

npm run sim を実行すると、ターミナルで通話をシミュレーションできます。Banjo が事業者に電話をかけ、応答する人の役をあなたが入力します。電話回線以外は実際の通話と同じで、システムプロンプト、ツール、通話処理、Postgres に保存されるタスク記録も同じです。電話は発信されず、カレンダーにも書き込まれません(予約は9時から18時まで空いている架空のカレンダーに登録されます)。通知も送信されません。必要なのは OpenAI API キーと Postgres だけです。

docker compose up -d postgres
echo "OPENAI_API_KEY=sk-..." >> .env    # skip if your .env already has it
npm install
npm run sim
Banjo is calling Claudia's Dog Grooming for Alex.
[The phone rings. You pick up.]
You: Claudia's Dog Grooming, how can I help?
Banjo: Hi, I'm an AI assistant calling on behalf of Alex. We'd like to book a full grooming for Banjo, a golden retriever...

オプション:--business、--goal、--mode conversation、1つ以上の --question を指定する --mode ask(place_call と同じチェックが適用され、1~5件、各質問は1行)、--duration(予約の場合のみ)、--transfer(または --owner accept|decline|no-answer を指定した --warm)、およびファイルから自分の発話を再生する --script <file>(~ で始まる行は録音のように再生され、メニューや保留キューに使えます)。npm run sim -- --help を実行するか、scripts/sim.ts の冒頭をご覧ください。シミュレーションの記録は独立した banjo_sim データベースに保存されます。各実行の開始時にデータベースの内容は消去され、実際のデータベースには一切触れません。

テキストは音声ではありません。シミュレーションで確認できるのは Banjo の発言と動作であり、通話の音声ではありません。互いの発話への割り込み、背景雑音、タイミングを確認できるのは実際の通話だけです。

クイックスタート

Banjo で実際の通話を発信するには、事前に4つのものが必要です。まず、これらを用意してください。

  1. Twilio アカウントと電話番号。 twilio.com で登録し、音声通話に対応した電話番号を購入して、アカウント SID、Auth Token、電話番号を控えておきます。米国の電話番号宛てに結果をテキストメッセージで受け取るには、送信元の番号も米国の A2P 10DLC に登録する必要があります。登録しない場合、キャリアによってすべてのテキストメッセージが通知なしにブロックされます(Twilio エラー 30034)。docs/RUNBOOKS.md の「SMS notifications aren't arriving」を参照してください。または、SMS を使わず、Pushover のプッシュ通知(NOTIFICATION_CHANNEL=pushover)で結果を受け取る方法もあります。この場合、キャリアへの登録は不要です。

  2. 音声 AI プロバイダー。 OpenAI Realtime は、ここで最も実績のある選択肢であり、推奨されるデフォルトです。Gemini Live と ElevenLabs Conversational AI もサポートされていますが、OpenAI の経路ほど実際の通話トラフィックで検証されていないため、一部の箇所で NEEDS VERIFICATION と表示されています(docs/ARCHITECTURE.md の「Open Risks」セクションを参照)。選択したプロバイダーの API キーを取得してください。

  3. カレンダーと連絡先へのアクセス。 カレンダーと連携したリアルタイムの予約や発信者 ID が必要な場合に設定します。アプリパスワードを使う CalDAV/CardDAV(Fastmail、iCloud、Nextcloud)を使用する場合は、CALENDAR_PROVIDER=caldav および/または CONTACTS_PROVIDER=carddav を設定してください。詳細は docs/RUNBOOKS.md の「Connecting Fastmail calendar and contacts」を参照してください。または、以下の Google を使用します。デフォルトは Google です。CalDAV は Fastmail で実際の予約に使用されています(#70)。

    Google Calendar および/または Google Contacts との連携(発信者 ID のパーソナライズ、find_contact のフォールバック)を使用する場合は、Google OAuth クライアントとリフレッシュトークンが必要です。両方のスコープを一度に指定して発行した、同じクライアントとリフレッシュトークンを共有します。具体的な手順は docs/RUNBOOKS.md の「Minting GOOGLE_OAUTH_REFRESH_TOKEN」の手順書を、各機能の接続方法は docs/ARCHITECTURE.md の Calendar および Google Contacts のセクションを参照してください。この手順を省略しても問題ありません。Calendar と Google Contacts は、クラッシュするのではなく、ログを記録して何もしない形で安全に失敗するため、これらがなくても Banjo のほかの機能は動作します。

  4. ローカルサーバー用の、パブリックからアクセス可能なホスト名。 Twilio は通常の HTTPS(Webhook)と WebSocket(音声 Media Stream)で Banjo にコールバックするため、ローカル開発でもインターネットからアクセスできる実際のホスト名が必要です。localhost は使えません。最も手軽な方法は次のとおりです。

    ngrok http 3000   # or whatever PORT you set
    

    ngrok が出力するホスト名(例:abcd1234.ngrok-free.app。https:// のプレフィックスは付けません)を PUBLIC_HOSTNAME として .env に設定します。ほかの方法を、おおよその手間が少ない順に示します。

    方法使用する場面
    ngrokローカル開発で、最も手早く設定できます。無料プランの URL は再起動のたびに変わるため、毎回 PUBLIC_HOSTNAME を更新するか、有料の固定ドメインを使用してください。
    Cloudflare Tunnel(cloudflared)Cloudflare で所有するドメインに紐づいた、管理可能な固定ホスト名を使ったローカル開発。無料です。
    実際のデプロイ環境経由でリバースプロキシを設定(例:.env.example のデフォルトで示されている ALB)Banjo をノート PC 上ではなく、常時稼働するサービスとして実行する場合。docs/RUNBOOKS.md の「Running Banjo on an always-on Linux host」を参照してください。

その後、全体を Docker で実行します。

npm install
npm run setup          # asks for everything from steps 1-3 above and writes .env
docker compose up      # Postgres + Banjo; migrations are applied on boot

npm run setup は、入力時に回答を検証し(E.164 形式の電話番号、PUBLIC_HOSTNAME のみの入力など)、Twilio と Pushover の認証情報を各サービスで確認できます。また、MCP_API_KEY を生成し、何かを書き込む前に、起動時に Banjo が実行するものと同じ検証を行います。設定を変更する場合は、もう一度実行してください。現在の値がデフォルトとして表示され、古い .env は先にバックアップされます。手動で編集する場合は、cp .env.example .env を実行して値を入力してください。

docker compose up は、各リリースで amd64 と arm64 向けにビルドされる公開イメージ ghcr.io/shatch/banjo を取得します。リリースを固定するには、.env で BANJO_VERSION を設定します。たとえば 0.1.0 のように指定します。デフォルトは latest です。自分のチェックアウトを実行するには、docker compose up --build を使用してください。 ローカルでホットリロードを有効にして開発する場合は、次のようにします。

npm install
npm run setup                   # or: cp .env.example .env, and fill it in
docker compose up -d postgres   # just the database
npm run dev                     # applies migrations, then starts on $PORT

次に、エージェントを Banjo の MCP サーバー(https://<PUBLIC_HOSTNAME>/mcp、Streamable HTTP)に接続し、 MCP_API_KEY をベアラートークンとして使用します。Claude Code の場合:

claude mcp add --transport http banjo https://YOUR-HOSTNAME/mcp \
  --header "Authorization: Bearer $MCP_API_KEY"

非推奨の HTTP+SSE トランスポートのみを話す旧式のクライアントでは、代わりに /mcp/sse を使用できます。

テスト用データベース

npm test のデータベースを使用するテストスイートは、上記の banjo 開発用データベースではなく、同じ Postgres インスタンス上の別の banjo_test データベースに対して実行されます。Compose は初回起動時にこのデータベースを作成します (scripts/init-test-db.sql)。必要なのは一度だけマイグレーションを実行することです。

DATABASE_URL=postgresql://banjo:banjo@localhost:5432/banjo_test npm run db:migrate

起動時のマイグレーションが対象にするのは DATABASE_URL のデータベースのみです。そのため、テスト用データベースは必ず このように明示的にマイグレーションしてください。自動では実行されません。

スキーマの変更

マイグレーションファイルは drizzle/ にあり、コミットします。Banjo は起動時に未適用のマイグレーションを適用するため (RUN_MIGRATIONS_ON_BOOT はデフォルトで有効です)、スキーマの変更を取得して再起動するだけで十分です。明示的に db:migrate を実行する必要があるのは、上記の banjo_test データベースだけです。

スキーマの変更を作成する場合は、npm run db:generate を実行し、生成された SQL を src/**/schema.ts の編集と一緒に コミットしてください。

自分用に設定する:オーナープロファイル

通話用プロンプトは意図的にコード内(src/voice/systemPrompt.ts、src/tasks/promptBuilder.ts)に置いてあります。内容の多くは 実際の通話から学んだものであり、AI であることを明かす、明確な承諾を得てから予約する、タイムゾーンを正しく把握する、といった ルールがテストで固定されています。Banjo をアップグレードすると、プロンプトもアップグレードされます。

変更したい内容は、すべての発信通話にこれらのルールの下に追加される、簡潔な Markdown ファイルであるオーナープロファイルに 記述します。

cp banjo-profile.example.md banjo-profile.md    # git-ignored — edit it
echo 'PROMPT_PROFILE_FILE=./banjo-profile.md' >> .env

電話に出る前に人間のアシスタントへ伝えておきたいことを書いてください。あなたや予約対象の相手についての情報 (「Pepper は爪切りが大嫌いなビーグルです」など)、好み、通話時の話し方などです。Banjo は情報を使ってタスクを実行し、 通話で必要な場合にのみその情報を伝えます。

  • 家族や友人以外には公開しません。 それ以外の相手(事業者や、relationshipTier が設定されていない連絡先)には、タスクに不要な あなたについての質問を、たとえ直接尋ねられても Banjo が丁寧に断ります。family または friend とマークされた連絡先はあなたについて尋ねることができ、 Banjo はプロファイルに基づいて回答します。相手が質問できるようにするには、Banjo が初めて保存する前に Google Contacts で相手を「Family」または「Friends」グループに 追加するか、手動でティアを設定してください(運用手順)。 MCP ツールでは変更できないため、通話内容を読んだエージェントに説得されても公開範囲が広がることはありません。

  • ルールが常に優先されます。 プロンプトでは、プロファイルの内容によって、AI であることの開示、明示的な同意、タイムゾーンに関するルールが覆されることはないとモデルに指示します。プロファイルで Banjo の応対をより親しみやすくすることはできますが、人間だと主張させることはできません。

  • 通話ごとのメモはプロファイルより優先されます。 place_call の constraints.notes のほうが、より具体的な内容です。

  • 起動時に検証し、通話ごとに読み直します。 パスが無効な場合やファイルが 4,000 文字を超える場合、起動は停止します。その後は再起動しなくても、編集内容が次回の通話に反映されます。

  • Docker の場合、ファイルをマウントします。docker-compose.yml の app 配下にある volumes: の行のコメントを外すか、Git の対象外となる docker-compose.override.yml に記述してください。

  • 現時点では発信通話のみです。 着信予約用の番号は知らない相手にも応答するため、個人用のメモは渡されません。

コンパニオンスキル

Banjo が担うのは、「用事を済ませる」のうち電話をかける部分だけです。もう一方の、オンラインで予約するか電話で予約するかを判断し、ブラウザー自動化でオンライン予約を進める部分は、このリポジトリに含まれるエージェントスキルです。場所はskills/schedule-appointment/です。エージェントスキルとリモート MCP サーバーに対応しているエージェントであれば、どれでも利用できます。インストールしてから、エージェントを Banjo の MCP サーバーに接続してください(クイックスタートを参照)。

スキルファイルは、ClawHub の要件に従い、MIT-0(帰属表示の要件がない MIT ライセンス)でライセンスされています。リポジトリの残りの部分は MIT ライセンスです。

任意のエージェント、skills CLIを使用:

npx skills add shatch/banjo --skill schedule-appointment

Claude Code。 スキルへの変更を別途同期しなくても後から反映できるよう、コピーではなくシンボリックリンクを作成してください。

ln -s "$(pwd)/skills/schedule-appointment" ~/.claude/skills/schedule-appointment

OpenClaw(Banjo ではまだテストされていません)。ClawHubまたはローカルのチェックアウトから:

clawhub install @shatch/banjo-schedule-appointment
openclaw skills install ./skills/schedule-appointment --global

Hermes Agent(確認用のターミナルがない場合は、docker compose exec -Tのように--yesを追加してください):

hermes skills install shatch/banjo/skills/schedule-appointment

このスキルは、あなたをどう呼ぶかを決めるために$ASSISTANT_PRINCIPAL_NAMEを読み取ります。Banjo のバックエンドが使用する環境変数と同じです。シェルまたは.envで一度設定すれば、両方で一貫して使用されます。

スタック

Node 22、TypeScript(strict、ESM)、Hono(HTTP)+ raw ws(メディアストリーム音声)、Drizzle ORM + Postgres、Zod、Vitest、Docker。

スクリプト

コマンド内容
npm run setup対話形式でセットアップします。必要な設定を尋ねて検証し、.envに書き込みます
npm run simテキストモードのシミュレーターです。Banjo が電話をかけている間、事業者として入力します。電話も実際のカレンダーも不要です
npm run evalシナリオ評価です。実際の OpenAI を使ったスクリプト形式のシミュレーション通話を採点し、費用を計算します。合格した実行結果は記録され、npm testで無料で再生されます(docs/ARCHITECTURE.mdを参照)
npm run devホットリロード(tsx watch)でサーバーを実行します
npm run build型チェックを行い、dist/にコンパイルします
npm testVitest のテストスイートを実行します
npm run typecheck出力せずに型チェックを行います
npm run db:generate / db:migrate / db:studioDrizzle のマイグレーション

db:generate/db:migrateは、最初にnpm run buildを自動実行します(package.jsonのpre*フックを参照)。このソースで使用している.jsサフィックス付きの相対インポート(Node ESM の実行時に正しく解決するために必要)を、drizzle-kit 0.28.x は解決できないため、drizzle.config.tsは TS ソースではなく、コンパイル済みのdist/db/schema.jsを参照しています。relation "..." does not existが表示される場合、ほとんどの場合はマイグレーションが生成または適用されていません。

ディレクトリ構成

src/
  voice/         vendor-agnostic Voice AI provider abstraction (OpenAI/Gemini/ElevenLabs)
  telephony/     outbound call origination + media streams (Twilio)
  tasks/         task/call-attempt data model, phone-path orchestration
  contacts/      contact directory
  calendar/      Google Calendar or CalDAV integration (phone-path only — see docs/ARCHITECTURE.md)
  googleContacts/ contacts cache (sync/lookup/reconciliation) — feeds contacts/ and inbound/
  carddavContacts/ CardDAV address-book sync into that cache (Fastmail, iCloud, Nextcloud)
  lib/dav/       shared WebDAV plumbing for CalDAV and CardDAV
  transcripts/   opt-in call transcript storage and retention
  recordings/    call recording retention
  inbound/       inbound call handling: booking flow + caller-ID resolution for greeting personalization
  mcp/           remote MCP server for tool-calling clients (e.g. Claude Code)
  session/       per-call state machine wiring telephony <-> voice AI <-> tools
  notifications/ outcome notifications (SMS by default, or Pushover)
  sim/           text-mode simulator (npm run sim): fake phone line and calendar for the real call path
skills/
  schedule-appointment/  companion Agent Skill — decides online vs. phone, drives online
                          booking via browser automation, calls into src/mcp/ for the phone path

コントリビューション

CONTRIBUTING.mdでは、Banjo が意図的に何を目指していないかを最初に説明しています。何かを書く前に、2分ほど目を通す価値があります。セキュリティ上の問題は、イシュートラッカーではなく、SECURITY.mdの手順に従って非公開で報告してください。

ライセンス

MIT — LICENSEを参照してください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。